public class HelloWorld{html
//static: 經過類找到此main方法並調用java
//public: 使得JVM能找到並使用此main方法react
//void: JVM不須要返回值sql
public static void main(String[] args){數據庫
//定義一個String類型局部變量 變量名爲 s編程
String s;小程序
s=」HelloWorld」;設計模式
//這裏調用System.out(輸出流)的println()時會自動調用已經覆寫了的toString(),因此輸出的結果不是對象的地址而是對象的值。數組
System.out.println(」s said:」+s);瀏覽器
}
}
文字解析HelloWorld
字符串數組 String[] ,堆中有的是空數組對象,new String[0] 中有對象可是沒有值。GC做用於堆。
代碼區包括類代碼和共享代碼,數據區包括靜態數據區也叫常量池和緩衝數據區(包括整型 Integer -128~+127 ,字符串對象)
棧中的方法執行空間包括斷點調試,臨時變量,數據局部變量等等。
主類public是編譯器的入口,主方法main是JVM的入口。
String 與 String[] 是兩個不一樣的類
20142023 軟件1412段飛霞
C語言的缺點:內存須要本身去管理,變量不賦值會致使系統崩潰指針太麻煩;優勢是效率高。
Java的缺點:Java以犧牲效率爲代價來提升安全性,自動釋放內存。
Java中通常只有一個主類是公有(public),其餘的類都是默認的。
靜態的繼承編譯時知道,動態的繼承執行時才知道。
Java支持多平臺的緣由:
一、Java是先編譯再解釋。
二、JVM的上層模塊相同,下層與系統相接的地方不一樣。
三、JVM(虛擬機)的個數與系統的個數相同。這就是一次編寫處處運行的緣由。JVM是相同的,而後將.Class文件解釋爲相應的機器指令。
在編譯與解釋中,.java與.class文件都不會變化,JVM是變化的。
Java源代碼與字節碼與機器無關,JVM與機器有關。
JVM是由硬件和軟件模擬的計算機
關於GC(垃圾回收機制)
GC:垃圾回收機制,優勢是更好的回收使用內存,缺點是效率不高。
內存泄漏是指內存使用不當致使系統崩潰。
Java的GC機制只能適當的改善問題,不能避免內存泄漏問題。
環境變量配置的緣由:
一、Path:……bin,找到java javac等命令
二、Classpath:……lib,找到標準庫中的類(不能省略)
三、JAVA_HOME:針對tomcat配置的,肯定jdk的位置。
JVM的內存:
方法區:分爲代碼區和數據區。
堆:堆中通常存放對象,對象都有屬性和方法(通常都有四個字節)
棧:棧中主要包括形參,局部變量,斷點,堆空間的地址,方法區空間的地址以及臨時數據。
實例方法經過對象調用
除了常對象在方法區的常數據區中開闢空間,其餘的對象都在堆中開闢空間。
Applet(java應用小程序)
Applet:是不安全的,容易被黑客入侵,程序由瀏覽器執行
HTML是靜態的,可是存儲在服務器上而後下載到瀏覽器上由瀏覽器執行。
1+1<2 的原理是模塊化
一個程序只要有主類 public修飾的類就能夠被編譯生成.class文件
面向對象:
面向對象的概念:以對象爲核心,屬性與需求都會有變化,可是對象不會變,從而保證程序的正確性和可維護性。
對象是把事物放在問題領域中抽象出它的方法。
對象與對象之間的關係主要有兩種:繼承和關聯(一對一,一對多,多對多)
普通類默認繼承Object類
類與屬性之間的綁定經過this關鍵字
參數簽名:參數類型,參數個數,參數順序
封裝:是指用共有方法操做私有屬性
構造方法:
構造方法沒有返回值類型可是會有參數簽名。沒有return
構造方法在類中能夠有多個,單例的構造方法是私有的
建立一個對象時會調用多個構造方法(this)
若是有父類,則也會調用父類的構造方法(super)
抽象類有構造方法可是接口中沒有構造方法
構造方法是由JVM來調用的,不是經過對象調用
構造方法有無數個,可是無參的構造方法有且只有一個。
通常類的訪問權限分爲兩種:public和 default
構造方法的做用:爲堆裏面的對象的實例全局變量賦初值(初始化)
不能經過this來調用構造方法,可是調用構造方法必定要傳this指針
建立對象先默認初始化再調用構造方法初始化:
建立對象的第一步在堆裏開闢空間,首先開闢屬性空間再開闢方法空間再默認初始化。基本類型值爲0,引用類型爲null,再進行構造方法的初始化
調用構造方法必定要給對它傳對象的地址,構造方法不能是靜態的
方法在堆中開闢空間,經過對象調用,開闢屢次空間
結構化程序設計就是面向過程的意思。(模塊化)
C語言是以函數爲單位
架構師分句需求分析創建基本架構,通常是用MVC的三層架構,流程圖主要用於詳細設計。項目的成敗決定於需求的獲取。
對象的屬性:
經過公有的方法對私有屬性進行訪問,能夠對用戶傳送的數據進行約束。
屬性或者域都是指在類裏面定義的變量,通常都用private,外部不能直接訪問
屬性開闢空間的大小和數據類型有關,方法通常都是四個字節
初始化過程分爲兩次:調用構造方法時爲對象的屬性和方法初始化
默認初始化(普通數據默認爲0,引用類型的數據爲null)
this指針是指對象的地址,對象的值,對象沒有名
實例方法存在於方法區的共享代碼段,堆中存放的是實例方法的引用或地址
調用構造方法不必定會建立對象,可是建立對象必定會調用構造方法。
抽象類與接口中均可以定義屬性
靜態方法不能傳遞this指針。
問題一:建立一個對象時爲何會調用多個構造方法?
由於此類可能有父類,因此會調用父類的構造方法
問題二:this指針是怎麼傳遞的,它的地址是怎麼樣的?
虛擬機傳遞過去的
方法分爲:實例方法,主方法,構造方法。
只有對象才能調用實例方法,實例方法只能經過對象調用
編譯時不能建立對象,只有在執行時虛擬機纔有可能建立對象。
在調用構造方法以前就已經有了對象的地址
實例方法不能直接調用,必定要經過對象調用
主類public是編譯入口,主方法main是jvm入口(執行)
封裝的做用:隱藏類的實現細節,設定權限,保證數據的完整性,有利於修改與加強代碼的可維護性。
方法的重寫:是指方法名還有參數簽名都和父類一致。
方法的重載:是指方法名相同可是參數簽名不一樣
包申明:只有字節碼文件放在包指定的目錄下才能被使用
包導入:指定字節碼文件的具體位置
包導入時 * 與.具體類 的執行效率不一樣,後者效率高。
包申明只有一個,包導入能夠有多個。
當測試類的.class文件與測試類的.java文件不在同一目錄下時,執行測試類應加上類的相對路徑 例如 javac mypack.Test
在doc命令中帶包編譯的格式 javac –d . aa.java
this的使用: 當屬性名和方法中的變量名重名時,在方法中會優勢調用方法中定義的變量,若想調用類中定義的屬性應在前面加上this. 表示經過對象調用。
棧中分配空間,調用一個方法會分配一個空間。
信息隱藏:是指把屬性定義爲私有的,外部不能直接訪問。
Java通常經過接口來保證穩定性。
序列化:表示能夠存儲在硬盤中的數據。(類能夠實現序列化接口)
註釋分爲兩種:
說明性註釋:(類的做用,做者,版本,日期,接口)
功能性註釋:(某屬性,代碼的功能)
對類的註釋:類的做用,做者,版本
對方法的註釋:方法的做用,參數,返回值,異常
Javadoc:收集對類的註釋,在命令行中:javadoc A.java ,會根據註釋生成一系列的文件,以index.Html爲入口查看。
Java類的通常只有public和默認類型,接口也是這樣。
Javadoc收集的註釋是對public類型的方法以及默認的方法的註釋。不包括protected和private類型的註釋。
Javadoc –private Test.java//收集對全部類型的方法的註釋
Javadoc –private –version –author Test.java//收集全部方法的註釋以及程序版本和做者
標識符包括:字母,下劃線,$,_,以及數字(可是數字不能用於開頭)
漢字能夠做爲標識符: Strirng 你好=null;//是合法的
標識符不能定義爲關鍵字或者標準類庫中的類
關鍵字:
boolean: 1個字節,用於關係判斷和邏輯判斷
byte:1個字節, -128~127
short:2個字節,-32768~32767
long:8個字節 int:4個字節
float:有效位數爲8位 double:有效位數爲15位
abstract:能夠用來修飾類或方法,能夠被繼承可是不能本身建立對象
assert:斷言,沒有通過驗證的結果
break:跳出本層循環 continue:跳出本次循環,開始下一次循環
final:定義的類不能被繼承 定義的方法不能被重寫只能重載 定義屬性只能初始化,不能賦值
new關鍵字的最終目的是返回對象的地址
super:標明父類的特徵,經過this去找到父類的對象
throw:拋異常 throws:聲明異常
transient:瞬時狀態
A :字符型 ‘A’ 十進制 65 十六進制 41(16) Unicode ‘\u0041\’
A:字符型 ‘a 十進制 97 十六進制 61(16) Unicode ‘\u0061\’
回車符 : 字符型 ‘\r ’ 十進制 13 十六進制 d(16) Unicode ‘\u000d\’
換行:字符型 ‘\n’ 十進制 10 十六進制 a(16) Unicode ‘\u000a\’
空格:字符型 ‘ ’ 十進制 32 十六進制 20(16) Unicode ‘\u0020\’
Java只有值傳遞,沒有地址傳遞。
Java.Lang:包括 throws ,Exception, Math, String, System ,Integer
一個8進制數至關於三個二進制數
一個16進制數至關於四個二進制數
不一樣數據類型之間的轉換原則:
當數據中有double類型時,結果必定爲double類型
當整形數據與實型數據進行運算的時候,結果應該爲實型數據
Byte char short 數據類型的數據進行運算結果爲int型
雙目運算會改變運算量的類型,單目運算和複合賦值運算不會改變運算變量的類型,
i+=1//逆波蘭式 複合賦值 f_abc//匈牙利變量命名規則用下劃線鏈接
int a=(int)1.567;//造型,向下轉型
數值儘可能不要用造型容易形成數據丟失
引用類型:必定與對象關聯 存放的是對象的地址而不是對象自己
聲明時不會建立對象,只會分配引用空間
Javac *.java//一次編譯當前包下的全部.java文件
編譯時會對全部的語句進行檢查,無論是否被調用到
通常不要在普通方法中建立對象,由於這樣容易引發內存泄漏
實例全局變量:在堆中開闢空間,對象建立時開闢,有默認的值,構造方法會爲實例全局變量初始化 建立幾回對象就會被建立幾回,對象調用,空間在對象消失時銷燬gc
靜態全局變量:具備全局性,該屬性歸該類全部對象公有,沒有this指針,通常經過類使用也能夠經過對象調用
靜態全局變量的內存空間是固定的一塊,被修改後,日後的引用的值都會一塊兒被修改
實例全局變量只能對對象調用,局部變量只能由方法調用,靜態全局變量能由方法,類,對象調用。
靜態全局變量:
靜態全局變量加載時在類的方法區的靜態數據區開闢一次空間,構造方法不對靜態變量初始化,而且靜態變量沒有this指針,不使用對象調用可是每一個對象都對它能夠有引用,靜態變量的生存週期和程序的同樣,通常不會被釋放。
靜態數據和類的關係叫關聯(屬性與類)
動態和類的關係叫綁定(方法與類)
Java沒有真正的輸出地址,除非複寫了hashcode toString方法,當你拿到對象的地址時,JVM會自動的經過地址找到對應的值輸出。
在同一個類中,加載此類時,爲靜態全局變量的開闢內存空間比爲main()開闢空間早
局部變量存儲在棧中,沒有初始化是不會有默認值,全局變量有默認值
形參是指函數申明時的參數,實參是程序運行過程當中實際調用此函數的時候給它傳遞的參數
傳值:形參(方法中的參數)的變化不會影響實參(局部變量)的變化。由於形參和實參不在同一個工做空間,形參在棧中的空間 本方法執行後就消失了。全部的方法工做空間(棧楨)在方法執行後就自動釋放了。
沒有特殊狀況儘可能不要定義靜態變量和靜態方法(單例除外),由於會參加維護成本
調用其餘類時能夠不導包,可是寫類的全路徑名 例如 java.lang.Math
JVM的輸出機制:內部有個valueOf()方法,先判斷對象是否是null,若是是就直接輸出null,若是不是就調用toString()輸出對象的值。
只有屬性沒有方法的對象叫貧血模型
只有方法沒有屬性的模型叫充血模型
在方法中,若是變量名衝突,會優先使用方法中的形參(棧中開闢的空間 局部變量)
主方法與實例方法用了同名變量,被調方法改變變量,main( )中變量值也變
在普通方法中建立對象,方法調用完內存釋放後 對象會變成遊離狀態,容易形成內存泄漏(儘可能不要在普通方法中建立對象)
方法內部中優先在本身的棧工做空間找變量,找不到再經過對象找
實例變量能夠與局部變量同名,可是實例變量與實例變量不能同名
重載時根據參數簽名來調用方法
普通類型傳值時,形參改變,實參不變
引用類型,傳值時,形參改變,實參也變
Class Test{
int ab=12;
public void setAb(int ab){//形參
ab=ab;//ab的值爲形參的值
System.out.println(ab);//11
System.out.println(this.ab);//12
}
Main(){
Test t=new Test();
t.setAb(11);
}
}
數據的運算:
除法:
整形數據除以0,//算術邏輯異常,ArithmeticException(12/0,,0/0)
浮點型數據的運算:
浮點型數據除以0,或者整形數據除以0.0,結果爲Infinity(1/0.0 3.0/0, 3.0/0.0 -1/0.0 )
當 0/0.0 : NaN (Not a Number)
取餘: 被除數小於除數,結果爲被除數 17%18 = 17
17%0 : ArithmeticException
17%0.0 1.3%0 -1.3%0 :NaN
17.6%4 整數部分照常取餘,小數不變
17.6%4.2 不出錯,單數結果不同 17%4.6 也是同樣
位運算:
可以參與 位運算的數據類型包括; int short long char byte
>>右移,至關於除以2
<<左移,至關於乘以2
Java經常使用的是循環右移
循環右移的位數爲: int n ,a ; a>>n 當n>32 時 n=n%32; a 右移n%32位
Long n,a, a>>n 當 n>64時,n=n%64,a 右移 n%64位
字符串運算:
X 和y都是 int類型數據時
System.out.println(「」+x+y);//生成5對字符串對象
「」 / 「」+x / 「」x / y / 「」xy
Sytem.out.println(x+y+」」);//生成3個字符串對象
Xy / 「」 / xy」」
數據的比較:
在引用類型中 equals比較對象的類型再比較對象的值
在基本類型中直接比較值
==號用來比較數值
基本類型只能用==來比較
&&短路與運算:當邏輯表達式有一個值爲假時,則再也不計算後面的表達式,直接給出值
||短路或運算:當邏輯表達式有一個爲真時,則再也不執行後面的表達式,直接給出值
Java只給四個類複寫了toString方法,(沒複寫的會調用==)
File Integer String Date
Integer對象在 -128~127之間會把對象建立在常量池中,相同的引用只建立一個,後來的先判斷是否存在,存在的話直接調用,不然建立。
除了(-128~127)之外的Integer對象在堆中建立對象
Null不能調用 equals方法,不然會出現NullPointException
從表單中獲取的數據不可能爲null,只會出現「」空串和字符串
Switch能夠接收的數據類型:int char byte short
在循環條件爲真時,while 和 do while{} 執行的次數是同樣的 ,當循環次數爲假時,while 不執行 do while執行一次
非正常出口跳出循環:
break:跳出本層循環
continue:結束本次循環,開始下一次循環
Label標記:標識循環體
inner: for(){} break inner;//表示跳出label所標記的那層循環
標識符直接寫在循環體上面,命名規則和變量名相同
int k =System.in.read();//從鍵盤緩衝區中讀取一個字符
例: 輸入 a 回車, 會讀出三個字符 97 ‘\r’ ‘\n’(10)
continue label :結束label所標識的那層循環的本次循環,開始那層循環的下一次循環。
數組和變量:
變量的空間不連續,數組的空間是連續的
數組的空間叫元素名
變量尋址:自動建立變量名 自動映射表 直接尋址
數組元素尋址: 間接尋址(根據下標來尋址)
數組沒有複寫toString (),輸出的是地址
數組:存放數據的容器,長度固定 類型同樣
給數組對象賦值: String[] str={「1」,」2」};//1個變量,兩個對象
數組的主要應用是排序: 插入排序 冒泡排序 堆排序 選擇排序 快速排序
冒泡排序:兩兩比較,大的數據日後
選擇排序:選擇一個元素和其餘元素比較,比它大的不變,小的交換位置
插入排序:第一個數肯定位置 後來的數都和第一個比較 大的數位置不變,小的數放前面
Int[] a=new int[5];//1個變量,5個元素,每一個元素爲int類型
Int[][] b=new int[3][];//1個變量,1個int[][]對象 3個int[]對象,9個元素
使用new來建立多維數組的時候,只須要指明最左邊的大小
Int[][][] a=new int[3][][];//3個元素,每一個元素都是int[][]類型
多維數組就是數組當中的數組
類的繼承:
父類的構造方法和私有屬性和私有方法不會被子類繼承
Java是單繼承,多實現的類
繼承關係中,建立子類對象時不會建立父類的對象,可是會調用父類的構造方法
調用子類的構造方法,父類中的構造方法中傳遞的是子類的地址
哈希地址: 前面是類型 +後面是地址
爲何建立子類對象要調用父類的構造方法?
由於子類須要調用父類中私有的屬性和方法,須要父類的構造方法爲之初始化並與父類創建動態綁定便於父類引用型變量調用
編譯時的綁定爲靜態綁定
向上轉型:父類引用型變量指向子類,父類引用型變量只能看到子類繼承的和覆蓋的方法,看不到子類新增的方法和屬性 只能經過靜態綁定找到類,再經過類的動態綁定找到屬性
建立子類對象的機制?
在堆裏面爲父類的私有屬性和方法開闢空間和父類進行動態綁定
在堆裏爲子類的方法和屬性開闢空間(靜態綁定父類的和子類新增的)
重載:方法的重載是在同一個類中,參數簽名不一樣(對返回值類型訪問權限沒有要求)
抽象方法能夠被重載,main方法能夠被重載,static方法能夠重載爲非靜態方法
JVM在編譯的時候就已經知道該調用哪一個方法,這叫靜態多態,編譯多態
覆蓋:是指在兩個類中,有繼承關係,子類繼承了父類的方法才能覆蓋,而且子類對父類方法的覆蓋只能有一次
覆蓋準則:出如今兩個有繼承關係的類中,方法名和參數簽名必須相同,返回值類型相同,子類的訪問權限不能比父類的訪問權限更嚴格,必定要大於父類的訪問權限
Java中子類對父類的實例方法的重寫叫覆蓋,對是static 方法的重寫和對屬性的重寫叫隱藏
造型:必定是兩個類,而且存在繼承關係,要有向上轉型(造型的效果只是臨時性的,只是把變量的值改成理想型)
訪問權限的控制: private(本類) default(包) protected(子類) public(所有)
關聯和綁定:
關聯:與靜態方法靜態屬性的關聯 沒有綁定this指針
靜態關聯:編譯時類和方法的關聯
動態關聯:加載時 類與靜態全局變量的關聯
綁定: 與構造方法實例方法的綁定有this指針
動態綁定:與私有屬性和私方法的綁定
繼承關係中: 先在堆中爲父類的私有屬性和方法開闢空間 與父類進行動態綁定,父類中的實例方法與父類靜態綁定,覆蓋後的方法和子類靜態綁定。
建立對象
建立對象時會先調用父類的構造方法在調用子類的構造方法,在父類裏面定義的方法被子類調用時會看不到子類中新增的方法。子類引用型變量調用繼承父類中的方法時,沒法找到子類中新增的同名方法,因此會先調用父類的方法
Super:是用來找到和父類動態綁定的私有屬性和方法
Super的特色:
是父類的一種特徵。
只能使用在實例方法中
不能用在static(靜態)方法中
經過super找到父類的綁定的方法,在經過父類的動態綁定找到父類的私有屬性
Super:在構造方法中的做用是顯示的調用父類的哪一個構造方法,出如今指定構造方法的第一條語句,只能有一條 super(); 參數填在括號中,調用父類無參構造方法時,就不寫參數。 默認調用父類無參的構造方法。
普通類的權限只有默認的和public ,內部類什麼權限都有
繼承關係中,父類不提供可供子類訪問的構造方法時,子類對象沒法建立(建立子類對象必定有調用父類的構造方法)
能夠在子類的有參構造方法中,經過使用super調用父類的有參數的構造方法
this:表明其所在類的當前對象的引用
this在類中構造方法中的做用:指定調用本類的某個構造方法
沒有繼承關係時,建立對象也可能調用多個構造方法 this指定
this和super不能出如今同一個構造方法中
初始化塊:做用和構造方法類似,給類的變量賦初值 (僅給定義在初始化塊以前的變量初始化) 比構造方法調用的早 會傳遞this指針
建立對象的執行順序:
一、 先給類中的靜態屬性開闢空間
二、 再給屬性和實例方法開闢空間
三、 調用初始化塊爲之初始化
四、 而後再調用構造方法進行初始化
建立幾回對象就會調用幾回初始化塊語句
WapperClass//封裝類:
封裝類 : Boolean Character的父類是Object //沒有valueOf()方法
Integer Byte Short Long Float Double BigDecimal 的父類是Number 均可以調用valueOf()
封裝類都是final類型,不能被繼承
封裝類的構造方法 :
以基本類型數據爲參數的構造方法
以基本類型數據字符串的形式構造方法
Integer i=new Integer(10); 等價於 Integer i=new Ingeter(「10」);
int ii=i.valueof();等價於 int ii=Integer.valueOf(i);
封裝類複寫了toString()方法和 equals()方法
toString() 表示返回這個對象的字符串,每一個類都有toString()方法
封裝類 異常 集合 date 網絡複寫了toString()
Object 的toString() ,
this.getClass().getName+「@」+Integer.toHexString(hashCode());
獲得對象的地址的方法,Integer.toHexString(hashCode());
實際開發中複寫的tostring()
Public String toString(){
return this.getclass()+」[name」+name+」age」+age+」]」;
}
在調用toString方法時,會先調用valueOf 方法,判斷對象是否爲null,爲null的時候直接輸出null,不爲null的時候纔會調用toString()
Object中的valueOf( ):
Public static String valueOf(Object obj){
return (obj==null)?」null」:obj.toString();
}
任何類都有equals方法,object 中的equals方法直接調用==
本身複寫equals方法:
1判斷被比較的對象是否爲null
2 判斷對象是否相等==
3 判斷類型是否一致 p.getClass()
4 判斷類的屬性是否相等 須要對對象進行造型
Public boolean equals(Object obj){
if(obj==null) return false;
if(obj==this) return true;
if(this.getClass()==obj.getClass()){
Person p=(Person)obj;
if(p.getName().equals(this.getName()){//String複寫了equals方法
return true;
}
}
}
同一個類只有一個反射對象
Static用來修飾類變量 語句塊內部類 static不能用來修飾構造器
構造方法不能對Static變量進行初始化,只能由static語句塊爲靜態變量初始化,而且在類中只加載一次
編譯的時候不能建立對象,反射對象是加載類的時候建立的
靜態方法不屬於對象,建立對象時不會爲靜態方法開闢空間
靜態初始化快中沒有this指針,靜態初始化塊在main()以前執行
靜態初始化塊和初始化塊的區別:
一、語法不一樣,靜態的有static{}
二、 調用機制不一樣,靜態加載類時調用
三、 執行次數不一樣 靜態的只執行一次,
相同點:都是爲屬性初始化
靜態用來實現單例,
單例模式的特色:共享數據線程同步項目安全下降併發性,增長耦合性
飢漢式單例:一加載就建立對象,只建立一個對象
Public class Singleton{
Private Singleton(){}//構造方法私有化,讓外部只能經過類建立對象
Public static Singleton instance=new Singleton();
Public static Singleton getInstance(){
return instance;
}
}
飽漢式單例:第一次使用時 先判斷對象是否存在,不存在時在建立,只建立一個對象
Public class Singleton{
Private Singleton(){}//構造方法私有化,讓外部只能經過類建立對象
Public static Singleton instance=null;
Public static Singleton getInstance(){
If(instance==null){
instance=new Singleton();
}
return instance;
}
}
推薦使用飽漢式單例模式效率高
final:
1、final 定義的方法能夠被繼承,可是不能被覆蓋
2、final修飾變量只能初始化一次,不能賦值
final static int a =20;//a的值不能再修改了
三、final實例全局變量也只能初始化不能賦值
四、引用類型final定義的實例全局變量不能改變對象,可是能夠改變對象的引用 a.name
五、final局部變量若是沒有初始化,只能賦值一次
六、方法的形參能夠是final類型的,只能初始化一次
七、方法內部類中只能使用final類型的形參
final類不能被繼承,final修飾的屬性仍是變量不是常量,常量沒有初始化,常量不能被賦值
Abstract類中會有構造方法,子類繼承abstract類時會調用父類的構造方法建立對象,可是不會建立父類對象
接口:
Interface中沒有構造方法,接口中不能有靜態初始化快語句
內部類能夠保證線程的安全,內部類分爲方法內部類也叫局部內部類,實例內部類也叫全局內部類
一個接口能夠繼承多個接口,可是一個抽象類只能繼承一個類
類與接口的關係叫實現
多態是在執行時才知道的,父類引用型變量調用了子類的那個對象
重寫是編譯時知道的
接口中不能有初始化塊和構造方法,接口中定義的變量都是 public final static 類型的
預運算符 : 類名:方法(); 指定使用哪一個類中的那個方法
接口的特色:
一、編譯時會生成字節碼文件
二、接口中的新增方法也要經過造型來調用,//接口回調
3、接口是一種功能規範,更注重抽象方法,不注重屬性
4、接口的功能:下降耦合性,提升可維護性
內部類:
內部類和外層封裝它的類之間存在邏輯上的從屬關係
內部類能夠訪問外部類的私有屬性
外部類 outer 內部類inner 編譯後 outer$inner.class
擁有內部類的外部類對象建立時不要考慮內部類,和正常類同樣建立
可是內部類的建立須要考慮外部類
Outer oute=new Outer();
Outer.Inner inner= outer.new Inner();
在外部類的方法中能夠自動識別內部類,內部類對象直接擁有對外部類對象的引用
內部類私有時,外部測試類中不能建立內部類對象
外部類方法中能夠建立內部類對象,使用內部類
匿名內部類:私有內部類省略名字,外部沒法使用
局部內部類:定義在方法中的類 做用空間只在方法中
方法內部類對象不能使用方法內部非final類型的變量
內部類能夠聲明爲抽象類被其它內部類繼承,也能夠聲明爲final類型的
Exception:保證程序的健壯性,先處理問題,應對用戶需求的變化
Error:錯誤,是解決不了的問題
RuntimeException:程序自己的異常,還未編譯,運行時異常
IOException : 外部資源問題,編譯時異常
finally:用於異常處理時關閉資源,finally中最好不要有return語句。
異常處理機制中,有返回值棧,返回值壓棧,只返回最後一個return值
Throwable包括Error 和Exception
實際開發中一個try{}能夠配多個catch() 最後catch的是 Exception
父類和子類的異常關係,繼承後 子類不能比父類聲明更多的不處理的異常
子類須要處理的異常必定要比父類多
Throws :表示不處理此類異常,在方法後面申明,程序沒有編譯錯誤(throws IOException)
Throw :出如今方法內部,後面只能跟一個異常對象,把異常對象拋出(throw new RuntimeException(e))
Throw能夠由系統來寫,系統自動檢測程序,也能夠本身定義異常
方法使用了throws表示把異常 拋給了調用它的方法的對象
系統先在catch中找到throw聲明的異常,沒找到再去throws中找不處理的異常
Message :由自定義異常類的有參構造方法設值
e.getMessage();公有的獲取異常信息的方法
e.toString();顯示異常對象的類型,顯示message()信息
e.printStrackTrace();調用toString() 找到異常出現的類方法//最詳細的顯示異常信息
自定義異常類: 1 繼承Exception類 2 提供一個無參的和有參的構造方法 super(msg)
不在業務層和持久層處理異常,交給表示層處理異常,業務層直接拋出異常
異常棧的跟蹤:從棧頂開始跟蹤,一直到異常處理
異常會影響系統的效率,發生異常的位置和捕獲異常的位置越近越好
處理異常的原則:
1 解決運行時異常,設定編譯異常
2對方法的異常作聲明 throws
3捕獲異常把異常代碼放在try{}中,try中的代碼量不能過多
4 catch必定要儘可能和try中的代碼一一對應,多個catch對應一個try
5 捕獲了異常要處理異常
6 有資源存取時,finally中要有關閉資源的,finally中不要有return語句
命令行參數 在cmd 命令中 編譯完A.java 後 在解釋時 輸入 java A 1 2 3 輸入參數
1 2 3 會存入String[] args 數組中
System.exit(1);//手動退出系統
String --.> int :
int age=Integer.parseInt(params);
Java是先編譯後解釋的語言
標準流: System.out 和System.err 都是PrintStream 對象
System.in 是InputStream對象
System 繼承了PrintStream 和 InputStream的父類 (標準流類)
字節流:一次只讀取一個字節
字符流:一次讀取兩個字節,讀中文時不會出錯,讀英文時會自動擴充
Data流和Object流比較重要
Properties其實就是map 以鍵值對的形式存儲數據
通常的key 和 value是Object 類型,Properties的key和value是String類型
建立properties對象 :
Properties props=new Properties();
往properties對象中設定屬性:
props.setProperty(「name」,」zhangsan」);
從properties對象中取值
props.getProperty(name);
Properties文件中的key和value課能夠用 等號 空格 冒號 分隔開
Properties的對象,內存的存儲空間
Properties文件:外存的存儲文件
.\\ 表示相對路徑
InputStrean in=new FileInputStream(「a.properties」);
props.load(in);//讀取配置文件的信息
FileOutputStream fos=new FileOutputStream(「b.properties」);
props.store(fos,name);//將props對象中的數據存儲到b.properties文件中 name 爲對b.properties文件的說明
Key 不能重複,value能夠重複
Java中的系統屬性是java的環境變量
Properties props=System.getProperties();//會建立properties對象, 把環境變量中的內容設到props中
Enumeration 枚舉類型的迭代
Props.propertyNames();///獲取全部的屬性名
HasMoreElement();
nexElement();
複習:
Java的起源 94年出現 爲網路開發而生。 java的出現推進了B/S模式,面向切面編程理念
Java的應用 –網絡應用,應用普遍。
IOS Andriod 不是很流行
Java技術體系架構: J2EE 企業級應用開發
Java的優勢:簡單,面向對象,健壯,多線程,結構中立跨平臺,安全,一次編寫處處運行
一次編寫處處運行:由於有虛擬機,先編譯後運行
垃圾回收機制:GC,對內存的使用有很大的提升,可是沒有解決內存泄漏問題(瞬時態和離線態進行回收) 下降了效率 ,是一個後臺線程 佔用了CPU效率
Applet:字節碼文件嵌入到html中,經過瀏覽器解析執行,瀏覽器自帶虛擬機
程序設計簡史:
結構化程序設計:一次性把全部需求找完,相似瀑布模型
面向對象程序設計:以對象爲核心,對象是指事務在問題領域中的抽象,核心問題是如何找對象。
面向對象的四大特色:隱藏(private),封裝(set/get),多態(父類的方法在子類中的不一樣實現),繼承
領域模型:經過類抽象出類和類之間的關係
類中叫屬性名,對象中叫屬性值
構造方法:由虛擬機系統調用,能夠被重載,建立一個對象可能會調用多個構造方法,編譯時知道調用哪一個構造方法
信息的封裝和隱藏:給屬性加private,外部提供get、set方法 保證信息的安全性和完整性。
Java源文件的結構:
包申明(package abc):字節碼文件必須方法當前包目錄下才能使用,體現了分包管理的原則
包導入(import abc.*;):找到指定的字節碼文件的位置
Strust1.0 :編碼效率低,執行效率高 SpringMVC
Java的註釋:是否能夠被收集 javadoc 能夠收集文檔註釋 /** */
標識符:不能定義爲關鍵字和標準類庫中的類名
Java數據類型 8中基本類型和引用類型
引用類型存放的是對象的地址,不必定在棧中開闢空間,可能在對堆中 或者是方法區中(static在方法區中)
傳遞方法:只有一種值傳遞
雙目運算符會改變運算量的類型,單目運算不會改變
Set和Map必定要複寫equals方法
只有Integer String Date File複寫了equals方法
表單中拿到的字符串不會是null(request.getParameter(「name」))
位運算適合的運算類型:int long byte char short
Switch中的數據類型只能是 int byte short char
數組是個容器,是經過類來建立的對象,長度固定
數組存放的數據類型必須一致,查找速度快,插入刪除比較慢
空數組沒有意義,空集合有意義
鏈表:插入和刪除比較快,查找速度慢
數組是length屬性,集合有size(), 字符串有length()
List集合是動態加長的集合數組
繼承的特色:單一繼承,私有屬性和私有方法不能被繼承
建立子類對象不會建立父類對象,可是會爲父類的屬性開闢空間
重載:在一個類中,多個方法名相同,參數簽名不一樣的方法。編譯時識別
主方法和靜態方法和抽象方法都能被重載
Java對屬性和靜態方法的重寫叫作隱藏
Java對父類的方法重寫叫作覆蓋
重寫的特色:在兩個有繼承關係的類,方法名相同參數簽名返回值類型相同,訪問權限要大,拋出的異常要少(處理的異常必定要多於父類) 抽象方法必需要重寫,靜態方法能夠重寫 叫隱藏。
This:當前對象的地址, new對象的時候建立的,(先有this,才調用構造方法),this所指定的屬性和方法必定在堆中。
Super:父類的特徵,父類綁定的實例屬性和實例方法,只能在實例方法中調用。在構造方法中顯示指定調用哪一個方法。 Super() 必定在子類的構造方法中的第一句
調用super必定要有this
靜態方法中沒有this,
初始化快:在構造方法前對在定義初始化塊之前的實例全局變量進行初始化,放到最後。建立幾回對象調用幾回初始化塊
靜態初始化塊:只調用一次,比main方法還早調用
this super 初始化塊:
第一步:壓棧
第二步:爲父類的屬性初始化
第三步: 爲子類的屬性初始化
第四步:調用父類的初始化塊初始化
第五步:調用子類的初始化塊初始化
第六步:彈出子類的構造方法」
封裝類:是一種類型,基本類型的首字母大寫 char Character ---- int Integer
封裝類的數據結構:都是final類型,複寫了toString() 複寫了equals()
封裝類的對象的建立不能用無參的構造方法,只能有參的
全部的類有都有equals方法,跟==等值比較同樣去比較
Static 能夠經過類調用,也能夠經過類中的任意對象調用
靜態屬性隨意使用會增長耦合性 ,靜態方法不能傳遞this指針,在靜態方法中也不能使用super。
靜態內部類不能訪問外部類的非靜態屬性
構造方法不能靜態(由於沒有this)
單例:Singleton (餓漢式)
靜態全局變量,private static Student instance=new Student();
構造方法私有化 private Student(){}
靜態的公有的public static Student getInstance(){ return instance;}
Singleton (飽漢式)
靜態全局變量,private static Student instance=null;
構造方法私有化 private Student(){}
靜態的公有的public static Student getInstance(){
if(instance==null){
instance=new Student();
} return instance;
}
缺點:耦合性高,效率低
優勢: 安全性高
final: final修飾的類不能被繼承,final修飾的變量只能初始化一次。數組類型的引用類型爲final類型,數組對象的類型不能改變,final類型的變量不是常量。 方法內部類的形參只能是final類型的
抽象:方法沒法實現時,先聲明定義爲抽象方法。(例:求某個圖形的面積和周長)
空方法不算抽象方法,它有空實現。
適配器的特色:把不一樣的對象進行統一的處理
多態:動態編譯,在接口上常用多態
模板模式:繼承
接口:接口中的全部屬性是 public static final 類型的 ,一加載接口字節碼的時候就初始化,在方法區開闢空間
接口中的全部方法是public abstract類型的
接口不是類,更不是特殊的抽象類
接口語法: interface定義,
一個子類只能夠extends 一個父類,抽象類有構造方法,可是不能建立對象,接口沒有構造方法 因此接口不是特殊的抽象類
接口的回調:用接口的引用型變量 接收 實現接口的類的對象
例如:DaoInterface daoInterface=new Daompl();
接口是功能規範,便於維護,下降耦合性
多個無關的類能夠實現同一個接口
一個類能夠實現多個無關的接口
instanceOf造型的時候使用,判斷對象類型是否符合造型要求
內部類:一個類定義在一個類的內部,分爲實例內部類和方法內部類,不能多用,
內部類和外部類的關係是組成關係。
實例內部類的特色:
命名空間只在外部類中的方法能夠識別,若是外部類外部的方法須要使用的話 ,須要使用調用外部類.內部類來使用
類中的內部類能夠訪問外部類的私有屬性
建立內部類對象,必須先有外部類對象
內部類會自動擁有外部類對象的引用
私有內部類只能在包含此內部類的外部類實例方法中被建立,私有內部類省略名稱成爲匿名內部類。
局部內部類使用的參數是final類型,也會自動擁有對外部類對象的引用
Inner class 能夠聲明爲 static private ,若是是靜態內部類就不能再訪問外部類的非靜態屬性。
異常:
使用異常目的:
1,因爲資源緣由形成程序出錯,預先用異常進行處理(IOException)編譯檢查此類異常
2,對於運行時異常,經過異常機制找到異常緣由而且給予解決
持久層不處理異常,業務層不處理異常,通常都在測試層處理異常
異常的種類:
Error:AWTError / LinkageError
Throwabel
Exception:IOException/……/RuntimeException
異常的數據結構:
e.getMessage();公有的獲取異常信息的方法
e.toString();調用e.getMessage(),而且顯示異常對象的類型
e.PrintStrackTrace();異常棧跟蹤,調用e.toString(),而且輸出發生異常的代碼位置
一個try{}後面能夠接多個catch()成正金字塔形式,最後catch (Exception e)
攔截異常後要進行處理
倘若finally 中有 return:
返回值棧,會覆蓋正常流程中的return值
會隱藏異常流程中的異常結果,還會隱藏異常
finally中通常最好不要有return值
自定義異常:
自定義異常類繼承Exception,定義兩個構造方法,一個無參的,一個有參數的構造方法。
public MyException(String msg){ super(msg); }
Property在java util.*;包下面
Property 中用空格,冒號區分 name 和value;
用setProperty()方法修改property對象中的值
用getProperty()方法獲取property對象中的值
load();//用於加載property文件
store();//用於保存修改後的property文件
明日講課內容:
Math
String
Collection
文件過濾
1.3版本:
使用線程同步,同一時刻只能使用一個線程
採用工廠模式完成業務層和持久層操做
業務層和持久層之間加了工廠
類鎖的機制(靜態鎖):用反射對象的鎖
業務層:設計單例時也加上靜態鎖。
1.4版本
awt 界面
1 Math類
1.1 final類型,構造方法私有。全部使用的方法都是靜態的,由類調用。
1.2 提供兩個static final 類型的實例全局量 PI(圓周率)和E(天然對數)
1.3 方法
1.3.1 ceil (返回大於或等於參數的最小整數)
1.3.2 floor (返回小於或等於參數的最大整數)
1.3.3 round(返回四捨五入的整數值)
1.3.4 變量的取值:max,min,abs(絕對值)
1.3.5 對數指數:log,exp
1.3.6 平方根 sqrt,冪運算pow,random 隨機數,
1.3.7 常量 PI,E
1.3.8 sin cos acos atan tan asin (裏面的參數是弧度,double類型的數值),toDegrees():轉化爲角度 toRadians();//轉換爲弧度
2 字符串類
2.1 String類,final類型,不能被繼承,實現了序列化接口,比較器的接口,排序接口,能夠進行存儲,比較,排序
2.2 String內部是final類型的字符數組對象,一旦建立不能被修改,只能建立新的字符串對象
2.3 String對象表明一組不可改變的Unicode字符序列 private final char value[],任何試圖改變string對象的方法都會建立一個新的字符串對象
2.4 String對象的建立
2.4.1 String str1=」abc」;//在方法區的常量池,能夠共享
2.4.2 經過new String對象
2.4.2.1 String str=new String(「abc」);//會建立兩個對象,一個在方法區的常量池,一個在堆裏面
2.4.2.2 String(char[] value);//按字符數組建立字符串對象
2.4.2.3 String(byte[] value);//按字節數組建立字符串對象
2.4.2.4 String(byte[] value,String charsetName);//根據charsetName指定的字符編碼,按字節數組參數建立字符串對象
2.5 String類的方法
2.5.1 concat:字符串的附加,相似 鏈接+,新串在方法區中
2.5.2 s1+=s2;//s1,s2都存在的狀況下,建立兩個字符串對象,一個在堆中,一個在方法區
2.5.3 replace ,repalcaeAll:字符串的替換
2.4.2.1 str.replaceAll(「hello」,」dfx」);//把全部的hello換成dfx
2.5.4 subString:求子串
2.3.4.1 subString(1,9);//取第一個位置包括第一個,到第9-1個位置的子串
2.3.4.2 subString(1);//取從第一個位置開始之後的全部字符
2.3.5 toLowerCase:轉換爲小寫
2.3.6 toUpperCase:轉換爲大寫
2.4 查找字符的方法
2.4.4 endsWith:尾部匹配
2.4.4.1 str.endsWith(「.java」);//判斷末尾的字符串是否匹配 匹配返回true
2.4.5 startsWith:頭部匹配//返回boolean類型
2.4.6 indexOf:找出索引位置
2.4.6.1: str.indexOf(「a」,2);//從第二字符起,a首次出現的位置
2.4.7 lastIndexOf:
2.4.7.1:str.lastIndexOf(「a」,2);//從第二個位置開始反向找a首次出現的位置(反向搜索)
2.4.7.1 str.lastIndexOf(「a」);//從第0個位置開始反向搜索,沒有 返回-1
2.4.8 split :分隔
2.4.8.1 str.split(「,」);按逗號分割後用String[] 接收,分隔爲多個字符串
2.4.9 trim:首位空格刪除
2.4.10 charAt;找到字符串出現的位置
2.4.11 String方法的實例
String str=」123」; String str1=」123」; //生成一個對象,在方法區的常量池中建立
String str2=new String(「aa」);//生成兩個String對象,堆中一個方法區一個
String str3=new String(「vv」); String str4=new String(「vv」);//建立三個 兩個在堆中,一個在方法區的常量池中
str+=str1;//建立一個新的字符串對象,鏈接後的新字符串在堆中開闢空間
String s=new String(「hello」);
String s1=」world」;
s+=s1;
System.out.println(s==」helloWorld」);//結果爲false
用追加(+)或者是鏈接(contact)建立的新串,在常量池中有一份,在堆中也有一份。比較的是堆中的那個對象。
2.4.12 StringBuffer:
構造方法 public StringBuffer(){super(16);}//自動增長16個緩衝空間
Stringbuffer具備必定的緩存,緩存容量是能夠增長的
StringBuilder是線程安全的,使用緩存時不會建立新的對象
Stringbuffer和 String比較:
都用來處理字符串
都提供 了length() charAt() subString()
StringBuffer類對象可變,改變其緩衝區不會建立新的對象
StringBuffer沒有複寫equals方法,不支持+運算
stringBuffer覆蓋了toString(),可是 和String的方法實現不同
String中追加必定會建立新的String對象,StringBuffer中追加不會建立新的對象,追加之後的對象就是原來被追加的對象。
StringBuffer和String不是同一種類型,不能比較。
StringBuffer 使用toString()方法後,會建立String類型的對象,把stringBuffer裏面的字符串賦值給String類型的對象,返回新的String類型對象的地址。新的String對象再調用string類型的toString()顯示輸出字符串。
String和StringBuffer的使用場合:
StringBuffer sb=new StringBuffer(「as」);//建立兩個對象
StringBuffer更節省內存空間
字符串常常變換的場合用StringBuffer
StringBuffer的容量爲20,若是追加200的數據,也不會建立新的StringBuffer對象,只會擴大緩存空間,不會建立新的對象。
如何優化StringBuffer?(如何優化字符串管理?)
預先估算緩存容量,提升stringBuffer的執行效率。String 和 StringBuffer內部都是char[] 數組,最大的缺點是長度固定。
2.4.13 StringBuilder:
StringBuffer和StringBuilder比較
都具備緩存功能
StringBuffer線程安全,一個線程使用不會影響別的線程使用信息
StringBuilder線程不安全(能夠人爲加鎖,保證安全 )
1 文件操做
File 在 java.io.*;下面
建立文件對象:
File file=new File(「a.txt」);//在相對路勁下建立文件
File file1=new File(「Mydos」,」a.txt」);//指定文件所在的目錄
2 Deprecation
javac –deprecation A.java;//用來編譯過時的文件類 表示已通過期了 發出警告
File 類的方法
getName();//獲取文件或者目錄的名字
getPath();//獲取文件或者目錄的路徑
getAbsolutePath();//獲取文件或者目錄的絕對路徑
getParent();//獲取文件或者目錄的根路徑
boolean renameTo(File newName);//更名
boolean exist();//是否存在
boolean canWrite();//是否可寫
boolean isDireactory();//是不是目錄
String[] list();//把路徑下的全部文件遍歷輸出
File currDir=new File(「f://abc」);//找到指定目錄
if(currDir.isDirecory){//判斷是否爲目錄
String[] files= currDir.list();//將目錄用String[] 對象接收
}
for(String file1:files){//循環輸出全部目錄
System.out.println(「file:」+file1);
}
文件的過濾:JavaFilter implements FilenameFilter接口,須要實現accpet()方法。
public boolean accpet(File dir,String name){
File f=new File(dir,name);
if(f.isDirectory()){
return true;
}else {
retrun name.endsWith(「.java」);
}
}
String[] files= currDir.list(new JavaFilter());//將經過過濾的目錄用String[] 對象接收
自動調用accept()的叫回調
accept的實現叫搜索策略
遞歸搜索:(思想)
先按順序搜索,找到目錄時,直接進去目錄下搜索,再按順序進行搜索,若是目錄中存在目錄則依舊再次進入目錄搜索。以此類推,最後一個目錄結構搜索結束後再處理別的文件依次從最後一層倒過來搜索。(搜索到目錄時就進入目錄搜索知道沒有目錄了再跳出來一次搜索)
做業:1.手工實現回調和策略搜索
2.多目錄文件查找
做業1:
import java.io.File;
/**
* 手工實現一級文件搜索
* 找出全部的前綴名爲String的文件
* @author DFX 2017/07/12
* */
public class FileSearchOne {
File currDir=new File("F:\\Users\\javaBase\\src\\string");//建立目錄文件夾
public static void main(String[] args) {
FileSearchOne fso=new FileSearchOne();//建立當前對象
fso.fileList();//調用列出符合過濾條件的文件或目錄名的方法
}
public void fileList(){//列出文件的方法
if(currDir.isDirectory()){//判斷當前文件是否爲目錄
String[] javaFiles=currDir.list(new JavaFilter());//用字符串接收當前符合過濾條件的文件
for(int i=0;i<javaFiles.length;i++){//列出當前目錄下符合過濾條件的全部文件,包含隱藏文件
System.out.println(javaFiles[i]);//輸出文件或者目錄名稱
}
}
}
}
import java.io.File;
import java.io.FilenameFilter;
/**
* 文件過濾類
* 實現FilenameFilter接口,覆蓋accpet()方法
* @author DFX 2017/07/12
* */
public class JavaFilter implements FilenameFilter{
public JavaFilter(){}
@Override
public boolean accept(File dir, String name) {//dir:指文件目錄,name:文件名
File f=new File(dir,name);
if(f.isDirectory()){//判斷是否爲目錄結構
return true;//爲目錄結構時返回目錄
}else{
return name.startsWith("String");//返回以String開頭的文件
}
}
}
做業二:
import java.io.File;
/***
* 遞歸搜索指定過濾文件
* @Author DFX 2017/07/12
*
* */
public class FileSearchMore {
/**
* @param args
*/
public static void main(String[] args) {
FileSearchMore fsc=new FileSearchMore();
File dir=new File("F:\\Users");
fsc.showDir(dir);
}
//函數調用本身 稱爲遞歸
public void showDir(File currDir){
File[] files=currDir.listFiles(new JavaFilterMore());//列出當前目錄下的全部文件
for(int x=0;x<files.length;x++){
if(files[x].isDirectory()){
showDir(files[x]);//是目錄的時候就遞歸,
}else{
System.out.println(files[x]);//不是目錄就不用遞歸,直接輸出
}
}
}
}
import java.io.File;
import java.io.FilenameFilter;
/**
* 多個層件目錄搜索過濾類
* @author DFX 2017/07/12
*
* */
public class JavaFilterMore implements FilenameFilter {
@Override
public boolean accept(File dir, String name) {
File f=new File(dir,name);
if(f.isDirectory()){
return true;
}else{
return name.endsWith(".java");//返回以.txt結尾的文件
}
}
}
集合和數組:
相同點:都是存放數據的容器
不一樣點:
1, 數組經過類建立數組對象,集合經過接口實現類建立對象(更好維護)
2,一旦數組建立對象了長度固定,集合長度可變(空數組無心義,空集合有意義)
3,數組能夠放基本類型的數據也能夠放引用類型的數據,集合只能存放對象的地址(引用類型的數據)
4,數組定義了元素類型必須保持一致,集合引用類型的數據能夠不同(集合存在造型問題)
5,原則上數組存放的元素是有序可重複的,集合除了(List)都是無序不可重複存儲的
6,數組經過下標取得元素,集合通常經過迭代取元素(list能夠不經過迭代)
7,數組沒有複寫toString(),集合複寫了toString();(集合還複寫了equals()和hashCode())
8, 數組的長度用length(),集合的長度用size();
9,集合的空間是能夠刪除的(remove),數組只能刪掉某個空間的元素
10,原則上數組類是不能被複寫的,可是集合能夠複寫(Hibernate複寫了set集合增長了 懶加載功能)
Collections 存儲數據的容器:集合數組對象變量
1 Collection:都有add和remove方法 都用Iterator迭代元素
1.1 Set 無序,不可重複,複寫了equals hashCode toString,遍歷用Iterator,也可使用加強for輸出集合中的元素
1.1.1 hashSet:散列表 經過一維數組+單鏈表
1.2 List有序:是一個一維數組,有序可重複,能夠經過下標遍歷也能夠經過Iterator遍歷
1.2.1 ArrayList:線程不安全,高效
1.2.2 Vector:線程安全,效率低
1.2.2.1:Strack
2 Map:鍵值對存儲,沒有繼承collection 沒有Iterator方法,輸出map中的元素對象須要藉助於List ,Set 集合。 Key 和 Value 加在一塊兒叫 Entry
2.1 HashMap:遍歷HashMap中的全部元素, 用KeySet 把Map中的Key放入set集合,還有一種EntrySet,
2.2 HashTable
2.2.1 Properties:Key 和 Value爲String類型
3 Iterator:線程不安全,效率高,都有自身的迭代功能 hasNext() next(),做用:方便的遍歷list set集合中的元素
4 Enumeration:線程安全,效率低
5 使用集合必定要導入import java.util.*;包
集合通常經過接口實現類來建立
List 有序可重複
List list=new ArrayList();//list集合內部是一個可變長的一維數組
數組變長是指在建立一個新的集合數組
往集合中添加數據
list.add(1); //自動裝箱和拆箱 Integer 類型
list.add(「as」);//String類型
list.add(new Integer(1));//Integer類型
list.add(newe Float(5.0f));//Float類型
集合複寫了equals(),比較時 調用equals方法,
list.size();//集合長度
list.remove(「as」);//移除集合中的 as 元素
System.out.println(list);// 複寫了toString() 輸出集合中的全部元素,輸出順序和添加時一致
Set 無序不重複
Set set=new HashSet();
set.size();//集合長度
set.add(「one」);//String 類型
set.add(4);//自動裝箱 Integer
set.add(new Integer(4));//Integer
Iterator it=set.iterator();//Iterator對象不能經過new來建立,只能經過方法建立。
While(it.hasNext()){//Iterator自身迭代輸出set集合中的元素輸出的元素類型爲Object類型,輸出的時候會自動調用toString方法,須要使用的時候須要人爲造型
System.out.println(it.next());
}
Set集合中的元素不能經過下標來取元素,由於它是無序的,只能經過遍歷取元素
Iterator是一個集合,不是迭代器,線程不安全效率高
Enumeration 是集合,線程安全效率低
Set集合的數據結構:一個線性數組+一個鏈表
Set集合的存儲特色?(先hashCode再 equals)
往set集合中add元素:先經過hashCode()方法計算一維數組下標位置(哈希值),此位置不存在數值的話則直接添加,位置已經有元素了就把已存在的元素和新元素作equals比較,equals比較相同則用新的替換舊的,不一樣則經過鏈表找到下一位置放入元素。每一個一維數組中的桶的哈希值是同樣的,可是key不一樣。
|
查找元素時,先作HashCode()比較,相同再作equals比較。
|
equals比較相同,hashCode必定相同。
|
|||||
一維數組每一個元素的位置叫作桶,桶中存放鏈表
元素的個數叫作容量 7
Size是指每一個位置上實際元素的個數
什麼叫容量?全部的一維數組的個數叫容量(默認容量 16),數組長度爲16
什麼叫負載因子?size除以容量叫負載因子(默認 0.75)負載因子=size/capacity,負載因子越小,碰撞率越低,查找和刪除效率越高。
Map 無序不可重複(key),Map的key 和value都是Object類型,除了Properties中的key 和 value是String 類型
Map map=new HashMap();
map.put(「1」,」mon」);//往map中設數值,分別是key和 value, key不能重複,重複時會覆蓋,後面的那個value被保存
map.get(「1」);//取出map集合中key爲1 的value值
System.out.println(map);//複寫了toString(),把key 和value用等號鏈接輸出 [1=mon]
map.remove(「1」);//移除key爲1 的元素
遍歷map中的元素
方法1:
Set set=map.keySet();//建立set集合,把map中的key設置到set集合中
Iterator it=set.iterator();//把set集合中存放的key放到iterator中進行迭代
While(it.hasNext()){
String key=(String)it.next();//獲得key(通常是Object類型,因此須要轉型)
String value=(String)map.get(key);//獲得value
}
方法2:
Set set1=map.entrySet();
Iterator it1=set1.iterator();//把set集合中存放的key放到iterator中進行迭代
While(it1.hasNext()){
Map.Entry entry=(Map.Entry)it.next();//獲得entry
entry.getKey();//經過entry獲得key
entry.getValue();//經過entry獲得value
}
Map的數據結構是key 和value的鍵值對
做業:經過map實現飽漢式單例,經過key找到類對象
import java.util.HashMap;
import java.util.Map;
/**
* Map實現 單例模式
* 比飽漢模式和飢漢模式更直接
* */
public class SingleTonMap {
public static Map map=new HashMap();//建立map集合
private SingleTonMap(){}
public static synchronized SingleTonMap getInstance(String key){//經過map集合的能夠獲得value ---單例對象
SingleTonMap value=(SingleTonMap)map.get(key);
if(value==null){//判斷value是否爲null
value=new SingleTonMap();//給value賦值
map.put(key, value);//將key和value設置到map中
}
return (SingleTonMap)map.get(key);//獲得value 單例對象
}
}
測試類:
public class TestSingleTonMap {
/**
* 主測試類
* @param args
*/
public static void main(String[] args) {
SingleTonMap stm=SingleTonMap.getInstance("new SingleTonMap()");
SingleTonMap stm1=SingleTonMap.getInstance("new SingleTonMap()");
System.out.println(stm+"---"+stm1);//返回對象的地址
System.out.println(stm==stm1);//true
}
}
集合的擴充:
Collection 是一個接口,有幾個子接口 list set
List 接口底下的類:
ArrayList:底層是數組,查找很快,刪除和修改慢
LinkedList:內部是雙向循環鏈表,既有前驅也有後繼,插入刪除特別快,查找比較慢
Vector:底層和arrayList同樣,效率低,線程安全
Set接口底下的類
HashSet :數組加鏈表
SortedSet:實現了Comparable接口 ,無序不能夠重複,可是能夠按照key進行排序
TreeSet是sortedSet的子類
Map:
HashMap 的查找和刪除都依賴於hashCode 和 equals
HashTable:數據結構和hashMap相似 散列表(哈希表),線程安全,效率低
Properties:數據結構和map同樣,散列表。Key 和value都是String類型
程序:一段靜態代碼,程序執行的藍本(代碼,代碼不佔用資源,資源是指內存)
進程:程序的一次動態執行過程,從代碼加載,執行到執行完畢的一個完整過程,做爲藍本的程序能夠被屢次加載到系統的不一樣的內存區域分別執行,分爲不一樣的進程。同一個程序它的進程不同。(進程須要資源,可是不一樣的進程不會爭用資源,進程能夠同時進行,互不影響)
線程:進程內部單一的一個順序控制流。一個進程執行過程當中能夠產生多個線程,每一個線程也有本身的產生,存在和消失的過程。(一個進程的多個線程,線程之間爭用資源和空間)
線程是爲多個用戶服務的獨立線索。
線程類必須複寫run()方法,JVM執行程序,主線程先建立,
public class Machine extends Thread{
public void run(){
for(int i=0;i<10;i++){
System.out.println(currentThread().getName()+」--」+a);
//currentThread()是指獲得當前線程的地址(線程的引用)
//currentThread().getName();指獲得當前的線程名
}
sleep();//靜態方法
try{}catch(InterruptedException e){}
}
public static void main(String[] args){
Machine mc=new Machine();//建立一個線程對象
mc.setName(「m1」);//將線程命名爲m1
mc.setPriority(「Thread.MAX_PRIORITY」);
mc.start();//使得mc處於就緒狀態,就緒狀態的線程特色,已經被分配了指令計數器,已經分配了工做空間 --棧
mc.run();//主線程執行mc線程的run方法,m1線程的入口方法
}
}
線程依賴於底層,調度策略不惟一。調度策略混亂,因此每次執行結果不惟一。
按線程分棧,每一個線程對應一個棧(相互獨立),每一個棧中有多個方法。
處於死亡狀態的線程特色:釋放棧裏面的工做空間,被GC回收
線程命名優先級和名字應該在線程就緒狀態以前設定。
線程生命週期狀態轉換圖:
線程的生命週期:
線程的建立狀態:
Jvm一啓動就建立主線程
普通線程在主線程中建立(在堆裏建立空間 new 線程對象)
主線程裏建立的線程和主線程具備相同的優先級,激活了start,就會和主線程搶佔資源。
Start是激活線程
線程的就緒狀態:
主線程執行某個線程的start ,線程就被激活,能夠和主線程搶佔資源。就緒狀態線程的特色:已經分配了資源處理機的指令計數器(PC),已經被分配了棧工做空間
線程的運行狀態:
虛擬機從就緒狀態中選擇一個線程佔用處理機,這種選擇就緒線程佔用處理機的方式叫作調度策略。run()方法是除了主線程之外,其它線程的入口。特色:佔用CPU執行程序。
線程的阻塞狀態:
等待CPU,還不能釋放資源,pc記錄方法執行的指令,把棧楨的使用空間放在計數器裏面。(計數器比較快),阻塞不能直接進入運行狀態,要先進入到就緒態,等待運行。
線程的死亡狀態:
內存空間被GC回收
1 線程:
線程的工做空間是穩定的,除非線程死亡
線程的方法的工做空間是不穩定的,執行完後就會被GC回收
處於就緒狀態的線程能夠有多個,可是處於執行狀態的線程只有一個
強行喚醒睡眠中的線程會使得線程處於異常狀態
線程睡眠時會進入阻塞狀態,這時候就緒狀態的線程會根據調度策略來進入執行狀態。Java的調度策略是搶佔式的策略。(隨機調度策略)
C語言的調度策略是時間片輪轉,先來先服務
棧中存放形參,局部變量,斷點,臨時數據
死亡狀態的線程釋放資源
處於阻塞態資源保存在PC和寄存器中
線程能夠從運行態直接轉到就緒態
主線程死亡的狀態是主方法執行完,其它線程的死亡狀態是其run方法執行完
線程的優先級:
Thread.MIN _PRIORITY=1;
Thread.NORM _PRIORITY=5;//主方法的線程優先級爲5,普通線程沒有設定優先級默認和主線程同樣 均爲5級
Thread.MAX _PRIORITY=10;
主線程是第五級,也能夠經過SetPriority()方法設定優先級
yield()//只給同一優先級的線程讓步,
搶佔的時候 低優先級的給高優先級的讓步
setDaemon(true);//將線程設爲後臺線程,而且啓動(也叫守護線程)
後臺線程的特色:由主線程建立,前臺線程執行完了 ,後臺線程自動結束(死亡)
Join的特色:當A線程執行到B線程的join方法時,A線程就會等待,一直等到B線程執行完,A纔會執行。Join用來臨時加入線程執行。
前臺線程和後臺線程的調度機制就是時間片輪起色制
主線程死亡後,後臺線程在分配的時間內會繼續執行,時間到了就會自動銷燬
若是調度機制是時間片輪起色制,yeild()方法不會對線程的執行順序形成影響
主線程執行完主方法建立線程對象後會死亡,可是不影響其建立的程的執行
讓多個線程共享同一個資源,須要在內部類中建立線程
建立線程的方法
1.1 繼承Thread類,實現run()方法
1.2 實現Runnable接口,實現run()方法 建立的類不是線程類,對象也不是線程對象。把接口建立的對象做爲參數方法Thread 對象建立中才是線程類。這個類的對象是爲了線程類提供run()方法。
例如:
MyThread mt=new MyThread();//MyThread類實現了Runnable接口,而且實現了run()方法
Thread thread=new Thread(mt);//thread纔是線程對象,調用有參構造方法,參數必定是對象的地址,而且所指的對象必定要實現Runnable接口,實現run()方法。
實現資源共享時,Thread thread1=new Thread(mt);
Thread thread2=new Thread(mt);
thread,thread1,thread2共享mt所指對象的變量。
1.3 線程的建立,實現Runnable接口,能夠不用建立內部類實現資源共享。
1.4 isAlive();//判斷線程對象是否處於激活狀態
1.5 終止線程的方法
1.5.1 經過設定共享數據,根據標記控制線程執行。共享相同對象的變量,修改變量的屬性值。
1.5.2 thread.stop();//在時間片範圍內直接終止thread線程,此方法不推薦使用,若是thread線程正在執行原子操做,忽然終止會破壞數據的原子性,影響對其餘線程的使用。
1.5.3 thread.interrupt();//thread在睡眠時,主線程執行thread.interrupt(),主線程強行終止thread線程的睡眠,讓thread線程處於就緒狀態,一旦thread被喚醒後,thread線程從(catch)異常代碼開始執行,拋出異常,終止線程
2 線程的同步
Synchronized:同步能夠保證數據的原子性不被破壞
不一樣的線程對象執行的run方法在不一樣的工做空間
鎖是一種對臨界資源控制的機制,利用每一個對象自身的功能。
Synchronized(obj){};//對象鎖,控制語句塊
對實例方法加鎖時,鎖的是調用實例方法的對象。傳遞的鎖對象是 this
對象鎖:主要鎖語句塊(同步塊)做用範圍爲上鎖的語句塊
方法鎖:鎖的是調用該方法的對象的全部方法(實例方法)做用範圍是對象的全部方法
類鎖:鎖的是加載類時建立的反射對象。靜態方法經過類調用,加載類會建立和類相關的反射對象,給靜態方法加鎖時,鎖的是全部類上的靜態方法。一個線程訪問一個靜態方法,全部線程和全部靜態方法都不能被執行。做用範圍是該類的全部靜態方法 傳遞的鎖對象是 類名.class
做業:
使用內部類建立四個線程,兩個對實例全局變量i作+1操做,兩個線程對i作-1操做。加減操做不用考慮順序。
1 添加sleep() 能夠人爲的控制調度策略,更改線程的執行順序
線程對象都具備start()方法,若是不能調用start()方法,則不是線程對象
普通線程的run()方法執行完後,線程死亡,內存被GC回收。
鎖體如今哪?
對象就是鎖。synchronized(new Object());
synchronized的做用?
鎖語句塊,保證同一時刻只有一個線程能夠操做這段語句塊。只能操做結束後其它線程才能操做。
上鎖的條件:至少有兩個或兩個以上的線程。
無論是對象鎖仍是類鎖或者是方法鎖,起做用的都是對象。
實例方法鎖:鎖對象是this,一旦調用一個方法,其它線程沒法使用該類對象的 其它方法。
2 同步代碼塊設置不當會致使程序出錯
This.notify();//(喚醒等待池中的線程,放到鎖池裏),保證生產者和消費者不會爭用資源(此狀態下當前線程依舊佔領處理機,當執行到wait方法時才讓出處理機,本身進入等待池中)
this.wait();//開啓鎖,讓別的線程執行,當前線程進入等待池。
3 生產者和消費者
進入鎖池表示進入阻塞態
Wait():先把鎖池開啓,把本身放入等待池中等待
生產者送情報,送完以後要等消費者取到情報後才能離開
notify():把等待池中的線程放到鎖池中,這時候處理機依舊是當前線程在佔領,直到當前線程執行wait()方法,被喚醒的線程纔會開始佔領處理機執行程序。
消費者先回來的·
4 線程如何保證安全性:synchronized
線程如何保證併發性:ThreadLocal
線程出現死鎖:方法鎖中的有語句塊鎖,語句塊鎖中有方法鎖,鎖的對象不一樣,一個是this,一個是obj。wait(),使得線程處於等待池;notify(),喚醒的線程是按順序喚醒的,通常是喚醒第一個進入等待池中等待的線程。線程進入等待池是按順序進入的,先進入的通常會先被喚醒。
notifyAll():喚醒線程池中全部處於等待的線程。
等待和喚醒必須是同一個鎖,鎖能夠是任意對象,能夠被任意對象調用的方法定義在Object類中。
非線程資源類中也能夠有同步資源,同步代碼塊。
/**
* 用內部類實現線程,建立四個線程,
* 其中兩個線程對實例全局變量+1操做,兩個線程對實例全局變量-1操做。
* 加減不考慮前後順序
* */
public class TestThread {
int i=10;//目標操做數
// int count=0,count1=0;//用來控制執行次數的標記,當count>10的時候就結束
// Object obj=new Object();
/**
* @param args
*/
public static void main(String[] args) {
TestThread tt=new TestThread();//建立當前類的外部類對象,用於建立內部類
AddThread addThread=tt.new AddThread();//建立內部類對象
SubstractThread subThread=tt.new SubstractThread();//建立內部類對象
Thread threadAdd=new Thread(addThread);//建立作+1操做的線程對象
Thread threadAdd1=new Thread(addThread);
Thread threadSub=new Thread(subThread);//建立作-1操做的線程對象
Thread threadSub1=new Thread(subThread);
threadAdd.start();//啓動線程,使得線程處於就緒狀態
threadAdd1.start();
threadSub.start();
threadSub1.start();
}
private synchronized void inc(){//同步這兩個方法,使得線程不能同時對i進行+1 和-1操做,只能選擇其中一個操做。
i++;
}
private synchronized void dec(){
i--;
}
//作+1操做的內部類
class AddThread implements Runnable{
public void run(){
for(int k=0;k<5;k++){
//打印出當前執行的線程名 和當前i的值
synchronized(obj){ System.out.println(Thread.currentThread().getName()+"--add---前:i= "+i);
inc();
System.out.println(Thread.currentThread().getName()+"--add---後:i= "+i);
}
}
}
}
//作-1操做的內部類
class SubstractThread implements Runnable{
public void run(){
for(int j=0;j<5;j++){
//打印出當前執行的線程名 和當前i的值
Synchronized(obj){
System.out.println(Thread.currentThread().getName()+"--substract---前:i= "+i);
dec();
System.out.println(Thread.currentThread().getName()+"--substract---後:i= "+i);
}
}
}
}
}
5 I/O流:java經過流完成了和外部數據的交互
外部數據是指外存,標準設備,網絡
I/O流是一條用來傳送數據的管道
5.1 輸入流:讀 從外向內,讀入到內存的存儲文件中
5.2 輸出流:寫 從內向外,輸出到外部的文件中
5.3 流的傳送單位是字節流 byte
5.4 從文件的角度看待流:
5.4.1:文本文件 顯示器和鍵盤,是用一個字節來存放一個字符的,是可見的,顯示器是典型的文本文件,從鍵盤中輸入的都是字符,以後轉換爲二進制。 特色:以字符的形式出現,每一個字符佔用一個字節, 文件文件都是可見的 文本文件最大的特色是須要轉換
3.141592678:以文本文件存儲佔11個字節,存放的是ASIIC碼值,最後顯示的是字符
5.4.2:二進制文件 .exe文件,之內存的方法存儲,double類型3.141592678 八個字節。二進制文件和內存的形式相同,不可見,不須要轉換,二進制文件的讀寫效率更高
數據在內存中運算都是以二進制類型進行運算的
字節流的種類:
文件字節流:從文件中拿數據
標準字節流:從鍵盤緩衝區中拿數據
網絡字節流:經過Socket從信道中拿數據
管道字節流:從管道中拿數據
順序字節流:sequence流,通常只有一種順序輸入流,
全部字節流都有個共同的父類,也叫作基類。輸入流的基類:InputStream (抽象類),輸出流的基類:OutputStream(抽象類),這兩個基類是抽象類,不是接口。
文件字節輸入流和文件字節輸出流:(會產生編譯異常)
主要catch()兩個異常,FileNotFoundException 和 IOException
FileInputStream:
FileInputStream:若是文件存在,會刪除從新建立,不存在也不會拋出異常,會建立新的文件
System.out.println()和System.err.println()是同樣的,能夠一塊兒使用
隨機訪問流:
RandomAccessFile:它的基類 (父類)是Object,隨機流不區分輸入流和輸出流,能夠隨機訪問文件當中的任何字符,隨機流能夠訪問文本文件和二進制文件,對文件的訪問方式要設定,
二進制文件的特色:存放數據的方式和內存同樣
randf.seek(2*4);//將文件位置移動8個位置,每一個int類型的數據佔4個字節
readInt();//按二進制文件讀取數據,一次讀取四個字節。
一、 文件字節流處理文本文件,對象流處理二進制文件
二、 字節流:是最基本的流
int c; while(c=fis.read()!=-1) fos.write(c);
對於輸入流,必定要 fis.flush();
三、隨機流 RandomAccessFile
RandomAccessFile raf=new RandomAccessFile(「a.txt」,」rw」);//隨機流,指定文本和訪問方式。
文件位置指針的移動位置是能夠手動肯定的,以字節爲單位
raf.seek(1*4);//指定指針開始查看的位置
四、套接流BufferedInputStream BufferedOutputStream
過濾流,緩衝流: BufferedInputStream bin=new BufferedInputStream(in,256);//in:表示文件,256表示一次最多讀取字節或者字符的個數
byte[] buf=new byte[1024];
int c=bin.read(buf,0,512);//c返回的是實際讀取到的字符的個數
流關閉時,能夠直接只關閉套接流。
BufferedOutputStream : bos.write();以後必定要用bos.flush();來強制輸出。
Buffered流的特色:
一、 要有字節流對象做爲參數,也能夠是對象流
二、 通常處理文本文件,不處理二進制文件
三、 通常來講不能一次讀取一行字符
四、 做爲套接流,而且區分輸入流和輸出流
Data流(數據流)
一、是一種嵌入流,首先得有字節流(文件字節流,網絡字節流,通常不用標準字節流)
二、既能夠讀取文本文件,又能夠像隨機流同樣存取二進制文件,並且可以按行讀取(readLine())
三、若是嵌入到網絡字節流,能夠讀取還能對網絡字節流進行編碼
DataInputStream
Dis.readUTF();
Dis.writeUTF();
Data流處理二進制文件:必定要按存的順序去讀取文件,否則可能會亂碼
Data流的readLine()讀取的必定是文本文件,
通信的雙工理論:只能聽見對方的不能聽見本身的聲音。
文件流的目標是文件,網絡流的目標是網絡信道
標準流: 通常套接buffered流,通常不套接Data流
鍵盤和顯示器都是字節設備
標準字節輸入流(InputStream)的最大功能是 從鍵盤中拿到的字節數據,轉換成字符串 System.in
標準字節輸出流(PrintStream)從文本中拿到數據到顯示器中顯示 System.out/System.err
System類不能同時繼承InputStream和PrintStream這兩個類,因此System中須要調用到InputStream和PrintStrem 的方法是靜態方法,將InputStream 和 PrintStream做爲參數傳入方法中。
對象流:
可以輸入輸出對象的流稱爲對象流
對象的持續性:可以記錄本身的狀態以便未來再生的能力,叫作對象的持續性
對象的串行化(序列化):對象傳送本身狀態的過程叫作串行化
從流中拿出對象的狀態生成對象的過程又叫反序列化,反正串行化
怎麼完成串行化?
一、 生成對象的類必定要加入串行化協議(對象類 implements Serializable接口,不用實現任何方法 )
二、 對對象的屬性賦予狀態,對對象屬性賦值 (建立類對象,而且給對象的實例全局變量賦值)
三、 建立對象輸出流對象,調用相應的方法 writeObject();(FileOutputStream )
四、 把對象所指的狀態經過管道一步一步的寫到對象輸出流所指定的二進制文件中
存放對象狀態的文件只能是二進制文件
對象的狀態想要傳送,對象類必須實現Serializable
對象輸入流對象:ObjectInputStream
ObjectInputStream ois=new ObjectInputStream(fin);
Student stu=(Student)ois.readObject();
對象輸出流對象:ObjectOutputStream
反序列化:經過對象輸入流對象從指定位置讀取對象的狀態,調用 readObject(),將對象狀態再生成對象
在變量前加上 transient表示不想進行傳送,在進行網絡傳送時會不進行傳送
對象的序列化:
//對象的序列化
public void objSer()throws IOException{
//建立須要被序列化的對象
Student stu1=new Student();
stu1.setNum(123);
stu1.setName("西歐愛心");
FileOutputStream fos=new FileOutputStream("1.txt");//建立字節文件輸出流對象
ObjectOutputStream oos=new ObjectOutputStream(fos);//建立對象輸出流對象
oos.writeObject(stu1);//序列化對象
oos.close();//關閉對象輸出流
}
建立對象的五種方法:
一、 New//new Student();
二、 方法 //set.iterator();
三、 反射
in=new FileInputStream("hello.properties");
prop.load(in);//加載文件
String className=prop.getProperty("className");//獲得配置文件中的類名
Class c=Class.forName(className);//反射類
ReflectDemo reflectDemo=(ReflectDemo)c.newInstance();//將反射類獲得的實例對象造型爲接口類型
四、 反序列化
//對象的反序列化
public void objRecov() throws IOException, ClassNotFoundException{
FileInputStream fis=new FileInputStream("1.txt");//建立字節文件輸入流
ObjectInputStream ois=new ObjectInputStream(fis);//建立對象輸入流對象
Student stu=(Student)ois.readObject();//對象的反序列化,經過反序列化獲得對象
System.out.println(stu.getNum()+"--"+stu.getName());//使用反序列化獲得的對象
ois.close();//關閉對象輸入流
五、 克隆
管道流 PipedInputStream PipedOutputStream
特色:
一、 輸入流和輸出流首位相接
二、 文件內存把輸出放在管道輸出流(內到外),另外一個線程從管道中拿出數據到內存 稱爲管道輸入流(外到內)
三、 管道流的傳輸不涉及文件也不涉及網絡(都是字節流)
PipedInputStream pis=new PipedInputStream();//建立一個管道輸入流對象
PipedOutputStream pos=new PipedOutputStream(pis);//建立一個管道輸出流對象,將管道輸入流對象做爲參數傳給管道輸出流對象
pos.write((byte)123);//將字節123寫入管道中
pis.read();//讀取管道中的數據,若是管道中沒有數據則會一直處於等待狀態
管道流的做用通常是用於線程之間的數據傳送,管道流必須依附線程
線程死亡後,管道流若是未關閉繼續讀取的話會報錯: write and dead
生產者拿到管道輸出流,消費者拿到管道輸入流,將管道流做爲建立線程對象的構造方法的參數傳入。
管道流使用完後要記得關閉, pis.close();
順序流:SequenceStream
FileInputStream fis=new FileInputStream(「file.txt」);
FileInputStream fis1=new FileInputStream(「file1.txt」);
SequenceInputStream sis=new SequenceInputStream(fis,fis1);//鏈接多個文件字節輸入流
DataInputStream dis=new DataInputStream(sis);//將順序流方法數據流中 以行爲單位讀取
String str=dis.readLine();//(判斷結束的比較對象爲 null)
字符流:一次只能讀取一個字節
字符流的基類爲Reader 和 Writer
InputStreamReader dis=new InputStreamReader(new FileInputStream(「file.txt」));
字符流基於字節流,建立字符流對象時,要把字節流對象做爲參數傳入。
字符BufferedReader 一次能夠讀取一行 readLine()
三種套接流:(用來套接字節流)
1)、Buffered流
2)、Data流
3)、Object流
反射:如何經過字符串拿到反射對象 完成自動裝配
String className="package.className";//寫出類名的全路徑名
* Class c=class.forName(className);//加載反射類
* Object obj=c.newInstance();//建立反射類對象
* User user=(User)obj;//強轉類型
* user.setName();//調用方法
*
* 反射的缺點:
* 效率低,打破對象的封裝性,代碼複雜,可維護性不是很好
*
* 優勢:
* 能夠直接訪問對象的方法 屬性
* 建立對象 能夠反編譯
*
* 通常狀況下不要用反射
用反射的目的:用戶的需求改變不用改變當前的代碼,只須要改配置文件就能夠了
做業:用管道流實現生產者消費者
package homework;
import java.io.IOException;
import java.io.PipedOutputStream;
/**
* 生產者類
* */
public class ProductorPipe implements Runnable {
private PipedOutputStream pipeOut;//定義管道流輸出流用來傳輸數據
public ProductorPipe(PipedOutputStream pipeOut){//在構造方法中傳入管道流輸出流對象,使得建立生產者線程對象的時候注入管道流輸出對象
this.pipeOut=pipeOut;
}
public void run(){
for(int i=0;i<10;i++){
try {
pipeOut.write((byte)i);//往管道流中寫入數據
System.out.println("write---"+i);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
pipeOut.close();//關閉輸出管道流
} catch (IOException e) {
e.printStackTrace();
}
}
}
package homework;
import java.io.IOException;
import java.io.PipedInputStream;
/**
* 消費者類
* */
public class ConsumerPipe implements Runnable{
private PipedInputStream pipeIn;//定義管道輸入流來讀取管道中的數據
public ConsumerPipe(PipedInputStream pipeIn){//在構造方法中傳入管道流輸入流對象,使得建立消費者線程對象的時候注入管道流輸入對象
this.pipeIn=pipeIn;
}
public void run(){
for(int i=0;i<30;i++){
try {
int j=(byte)pipeIn.read();//讀取管道流中數據,當管道中沒有數據的時候,會輸出 -1
System.out.println("讀數據---*****"+j);
} catch (IOException e) {
e.printStackTrace();
}
}
try {
pipeIn.close();//關閉管道輸入流
} catch (IOException e) {
e.printStackTrace();
}
}
}
package homework;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
/**
* 測試管道流鏈接的生產者消費者線程
*
* */
public class TestPipeProCon {
public static void main(String[] args) {
PipedOutputStream pipeOut =new PipedOutputStream();//建立管道輸出流對象
PipedInputStream pipeIn=null;
try {
pipeIn=new PipedInputStream(pipeOut);//建立管道輸入流對象
} catch (IOException e) {
e.printStackTrace();
}
ProductorPipe pro=new ProductorPipe(pipeOut);//建立生產者對象
ConsumerPipe com=new ConsumerPipe(pipeIn);//建立消費者對象
Thread thPro=new Thread(pro);//建立生產者線程對象
Thread thCom=new Thread(com);//建立消費者線程對象
thPro.start();//啓動生產者線程
thCom.start();//啓動消費者線程
}
}
字符Buffered流能夠按行讀取,字節Buffered不能夠按行讀取。字符流不能讀取二進制文件。
Data流能夠按行讀取也能夠讀取二進制文件
Awt:事件突發機制 觀察者機制 (內部類/匿名類)
本週須要完成的項目:
計算器:菜單欄
銀行項目1.4 :工廠模式 反射類
銀行項目1.5 :awt
java聊天室:線程數組,線程集合
反射:如何經過字符串拿到反射對象 完成自動裝配
String className="package.className";//寫出類名的全路徑名
* Class c=class.forName(className);//加載反射類
* Object obj=c.newInstance();//建立反射類對象
* User user=(User)obj;//強轉類型
* user.setName();//調用方法
*
* 反射的缺點:
* 效率低,打破對象的封裝性,代碼複雜,可維護性不是很好
*
* 優勢:
* 能夠直接訪問對象的方法 屬性
* 建立對象 能夠反編譯
*
* 通常狀況下不要用反射
動態裝配:
一、 如何建立一個類型不斷變化的對象?
二、 怎麼用工廠完成裝配?
Faotory 處於業務層和持久層之間,建立factory類的步驟:
一、 建立properties對象
二、 建立流對象 FileInputStream
三、 加載 load(),關閉流
四、 從properties文件中讀取className的值(存儲的類名要寫全稱 com.cx.UserDaoFactory),拿到的僅僅是字符串 類名 className
五、 加載到內存Class c= Class.forName(className);//建立映射對象,能夠經過映射對象獲得屬性,方法。 映射對象能夠經過getClass()獲得。
六、 建立對象實例: Object obj=c.newInstance();
七、 造型 : userDao=(BankDaoInterface)obj;//按照接口造型,
八、 加同步的飽漢式單例獲得當前類的對象
用反射的目的:用戶的需求改變不用改變當前的代碼,只須要改配置文件就能夠了
1 工廠建立對象是單例模式,在項目當中只有一個工廠完成裝配
2 工廠使用synchronized 保證安全性
工廠屬於持久層
表示層:接受用戶的請求,對請求進行分析
業務層:完成表示層所要求請求的功能
持久層:完成對數據庫的存儲操做
模型層:把數據封裝到bean中 (bean:是數據在內存中的存儲方式)
三、怎麼使用工廠?
業務層接口上面對應的是表示層
業務層和持久層必須用接口
業務層也是單例模式 synchronized ,(一個請求多個線程來訪問,使用單例保證一個請求建立一個業務對象,保證訪問的安全性 <單例+同步>)
業務層使用<單例+同步>來建立業務對象是有必要的
安全級別越低,併發性越高
四、表示層怎麼獲取業務對象操做持久層?
業務層有持久層接口變量,工廠也有持久層接口變量
在建立業務層對象的時候,會調用業務層無參的構造方法,因此在業務層的構造方法中,建立工廠,經過建立工廠拿到持久層對象
業務層和工廠都使用<單例+同步>建立對象,持久層能夠不用同步,保持單例就行
業務層經過工廠對象拿到工廠裝配的持久層對象的地址,指定業務層該調用的持久層對象(體現了擁抱需求)
在業務層 經過工廠獲得的持久層對象給業務層中定義的持久層實例全局變量賦值,而後在調用持久層中的方法
private ManagerImpl(){//業務層的構造方法
UserDaoFacory userDaoFactory= UserDaoFacory.getInastance();
UserDao= userDaoFactory.createUserDao();//createUserDao是工廠中的一個實例方法,用來返回經過反射獲得的userDao對象方法
}
建立工廠作兩件事:
一、 經過反射建立持久層對象(根據用戶需求動態建立持久層對象)
二、 將持久對象裝配給userDao(賦值給)(把持久層對象傳給指定變量)
業務層:
一、在構造方法中建立工廠拿到工廠對象
二、拿到工廠對象中獲得的(動態變化的)持久層對象
爲何引用工廠模式?
持久層常常變化 ---- 擁抱需求
工廠被用了幾回? (只用一次,完成裝配)
只用一次,第一個線程被調度執行業務層對象的時候使用了工廠,業務對象只建立一次,因此也只調用了一次業務對象的構造方法,日後業務對象已存在,不用再建立。而且業務層已經肯定了該用哪一個持久層對象了,就不用再使用工廠了
在用工廠裝配的時候,可不能夠有多個線程完成裝配操做?
不能夠,工廠必須是<單例+同步>,保證安全性
工廠模式 鏈接業務層和表示層 做業
/**
* 工廠類<單例+同步>
* 經過反射從properties文件中獲得持久層的實現類對象
* @Author DFX
* @Version 1.3 2017/07/18
* */
public class DaoFactory {
private DaoInterface daoImpl;//定義持久層接口實現類的對象
/*
* <飽漢式單例+同步>
*
* */
private static DaoFactory daoFactory=null;
private DaoFactory(){}
public synchronized static DaoFactory getInstance(){
if(daoFactory==null){
daoFactory=new DaoFactory();
}
return daoFactory;
}
/*
* 經過反射獲得持久層實現類對象
* @Params null
* @Return DaoInterface
*
* */
public DaoInterface getObj(){
Properties prop=new Properties();
FileInputStream fis=null;
try {
fis=new FileInputStream("daoImpl.properties");
prop.load(fis);
String className=prop.getProperty("className");//獲得反射類全名
Class c=Class.forName(className);//加載反射類
Object obj=c.newInstance();//建立反射類對象
daoImpl=(DaoInterface)obj;//對反射類對象造型爲實例接口
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return daoImpl;//返回持久層實現類對象
}
}
在業務層的構造方法中經過工廠類獲得持久層對象
DaoInterface daoImpl;
// 無參構造方法
public ManagerImpl() {
DaoFactory daoFactory=DaoFactory.getInstance();//獲得工廠類對象
daoImpl=daoFactory.getObj();//經過工廠類對象獲得持久層接口實現類對象
}
public static synchronized ManagerImpl getInstance(){};//靜態鎖,做用於和類所關聯的反射對象
靜態鎖的目的:把線程的並行變成串行
業務層加鎖->持久層加鎖-> 數據庫加鎖->事務加鎖(效率愈來愈高,安全性愈來愈低)
自我介紹:我的信息 本身所學的專業知識 應聘崗位技術
經常使用的容器 Frame 和 Panel
TextArea:文本域,一次能夠寫多行
TextField:文本區,一次只能夠寫一行
Panel 須要被加載到Frame中,panel 是不可見的//frame.add(panel);
TextField:文本
TextField(int columns):新建一個指定行數的文本域
佈局:組件在框架中的排列方式
流式佈局FlowLayout:從左到右,從上到下(根據框架大小自適應) 面板的默認佈局
網格式佈局 GridLayout: GridLayout(2,1);//指定 兩行一列(計算器)
邊界佈局BorderLayout:是frame框架的默認佈局,中間大,東南西北分
網格包佈局GridBagLayout
Gridx=1;//X軸距離
Gridy=1;//Y軸距離
setHeight=1;//高度
setWidth=1;//寬度
Awt中沒有單選框,只有Checkbox(複選框)
要設置單選框時,須要設定複選框組 CheckboxGroup
CheckboxGroup cg=new CheckboxGroup();
Checkbox cb=new Checkbox(female,cg,true);
選擇框:
Choice movies=new Choices();//下拉列表框
Movies.addItem(「^^^」);
網格式佈局
* public GridLayout(int rows,int cols,int hgap,int vgap)
* rows:行
* cols: 列
* hgap: 水平間距
* vgap: 垂直間距
*
* String str=but0.getLabel();//獲得按鈕上的內容
Awt的事件突發機制
組件會產生什麼事件,監聽器實現什麼接口,有什麼方法
1.一、 事件源產生事件,監聽器處理事件。
1.二、 一個事件源可能會產生不一樣類型的事件
1.三、 MyListener實現ActionListener接口,實現actionPerformed方法
1.四、 觀察者模式:MyListener ml=new MyListener();//其中ml爲觀察者對象
1.五、 AddActionListener(new ActionListener(){//事件驅動
public void actionPerformed(ActionEvent e){
//這裏寫出須要的操做
}
});
1.六、 class ButAction extends Frame Implements ActionListener{//定義類時繼承Frame框架實現ActionListener接口
public ButAction(){//構造方法中有this指針
but.addActionListener(this);//默認調用當前對象的actionPerformed方法
public void actionPerformed(ActionEvent e){//實現ActionListener接口中定義的方法
}
}
}
1.七、 ActionEvent:實現ActionListener接口,實現 actionPerformed方法
1.八、 ItemEvent:複選框,單選框,列表框的單擊,選擇框的單擊會產生這個事件 實現 ItemListener接口 只有一個方法須要實現 itemStateChanged()
1.九、 FocusEvent(焦點事件):每一個組件都有這個事件,實現FocusListener接口,實現focusLost(焦點丟失) 和 focusGained(焦點得到)方法(適配器類:FocusAdapter) 焦點事件對數據的檢查很是重要
tf.addFocusListener(new FocusAdapter(){//調用空實現類,能夠只選擇其中一個方法實現 ,還有個focusGained方法被空實現了
public void focusLost(FocusEvent e){//焦點丟失方法
TextField tf=(TextField)e.getSource();//拿到事件源
if(!tf.getText().equals(「Tom」)){//分析數據是否正確
tf.setText(「」);//清空文本框中的數據
tf.requestFocus();//從新得到焦點(光標的位置)
}
}
});
焦點事件能夠對用戶輸入的信息作格式驗證
1.十、 KeyEvent:鍵盤事件 。(能夠對輸入的任何字符作監聽而且獲取輸入的字符)實現KeyListener接口,實現三個方法
keyPressed:鍵盤輸入(按下)//顯現鍵值①
int keCode=e.getKeyCode();//獲得輸入的字符
keyTyped:鍵盤按下並釋放//顯現鍵符②
e.getKeyChar();//獲得鍵盤錄入的字符
keyReleased :鍵盤釋放(鬆開)
int keyCode=e.getKeyCode();
repaint();//重繪,讓frame設置的屬性當即顯示效果
addKeyListener(new KeyAdapter(){
public void keyPressed(KeyEvent e){
}
});
1.十一、 MouseEvent:鼠標事件,有兩種監聽器 須要實現MouseListener或者 MouseMotionListener接口,接口中的方法有:
mouseClicked:單擊 int clickNum=e.getClickCount();//獲得鼠標單擊次數(能夠對文本框產生的事件作鼠標事件監聽)
e.getX();//獲得X座標e.getY();//獲得Y座標
mouseEntered:
mouseExited:
mousePressed:
mouseReleased:
mouseDragged:
mouseMoved:
(適配器類:MouseAdapter)
1.十二、 適配器類:將監聽器中的全部方法都實現,只是空實現。空實現的類叫作適配器類
1.1三、 WindowListener:窗口事件。能夠繼承WindowAdapter適配器類,此類已經對WindowListener接口中的全部方法都作了空實現。因此使用的時候能夠選擇本身須要用到的方法進行復寫。
frame.addWindowListener(new WindowAdapter(){//窗體驅動
public void windowClosed(WindowEvent e){
System.exit(0);//退出,關閉窗體
}
});
1.1四、 多點監聽器:
一個組件實現多個監聽器接口,實現每一個接口中的每一個方法
一、 匿名內部類
將私有內部類,寫到構造方法中,直接變成匿名內部類
在構造方法中:
this.addWindowListener(new WindowAdapter(){//這個對象沒有類名,只知道這個對象的類繼承了WindowAdapter父類
public void windowClosing(WindowEvent e){
System.exit(0);
}
});
this.addWindowListener(new WindowListener(){//new後面跟一個接口,可是接口不能建立對象,這隻能說明 這是個實現了WindowListener 接口的匿名類
});
匿名類的優勢:代碼簡單
匿名類的缺點:可維護性差,不易理解,使用範圍窄, 只能在一個場合使用
匿名類只在特殊場合使用:
一、 事件突發機制 作監聽器
二、 Spring IOC 和AOP 的機制 callback 回調的核心技術
二、 Swing(Menu)用swing如何作菜單
Awt的缺點:
一、 依賴底層,在不一樣的系統下顯示的結果不一樣
二、 沒有單選框
三、 作出來的效果比較死板
四、 關閉時必定要使用事件突發機制
Swing:
Java 爲swing提供JFC類庫
使用swing要導入三個包 javax.swing.*; java.awt.*; java.awt.event.*;
Model:業務層 持久層 模型層
原則:作圖形界面最好是不要把swing和awt混在一塊兒寫,不然會混亂 (由於swing是穩定的,awt是基於底層不穩定的)凡是以J開頭的組件都屬於swing,相似JFrame 。
JFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//自動實現窗口關閉
JButton.setMnemonic(KeyEvent.VK_F);//在按鈕上設置快捷鍵 F
JButton上能夠添加背景圖片,再添加文字
JTextField jtxt=new JTextField(Document doc,int column,int row);
New JtextField(「默認文字」,」圖片(ImageIcon)」,」」);
JComboBox :組合框
菜單:
JMenuBar mb=new JMenuBar();//建立菜單條
f.setMenuBar(mb);//將菜單條放入框架中
JMenu m1=new JMenu(「文件」);//建立菜單
mb.add(m1);//把菜單添加到菜單條中
mb.setHelpMenu();//建立幫助菜單項
JMenuItem mi1=new JMenuItem(「新建」);//建立菜單項
m1.add(mi1);//將菜單項添加到菜單條上的菜單中
mi1.addActionListener();//菜單項能夠添加事件監聽事件
菜單項能夠添加二級菜單(能夠是普通菜單項,也能夠是複選菜單項)
JCheckBoxMenuItem:複選菜單項
m1.add(「Hello World」);// 能夠把字符串做爲子菜單
m1.addSeparator();//在菜單中添加間隔線
菜單中添加菜單,表示被添加的菜單是二級菜單,以後再添加菜單項
1 通信協議:計算機域計算機之間通信的約定的方式
1.一、 OSI協議分爲七層:物理層、鏈路層、網絡層、傳輸層、會話層、表示層、應用層
1.二、 TCP/IP(傳輸控制/網際協議)參考模型包括五層:物理層、鏈路層、網絡層、傳輸層、應用層(URL和URLConnection)
URLConnection:是對設備的鏈接
1.三、載波監聽多路訪問:先聽後發,邊聽邊發,碰撞後隨機重發
1.四、 網絡層:點到點
1.五、 傳輸層:端到端,不關心中間怎麼傳輸(TCP和UDP協議)
1.六、UDP(用戶數據報)協議特色:不可靠,無序,可是傳送效率高
1.七、TCP(傳輸控制)協議特色:可靠,有序,以字節流的方式傳送數據,一般被稱爲流通訊協議
1.八、端口號:標識網絡應用的邏輯地址
1.8.一、 Oracle端口號:1521
sqlServer 端口號:1433
Mysql端口號:3306
1.8.二、端口號定義規範: 0~65535,其中0~1023爲系統保留
2 Java提供的網絡功能的四大類:
2.一、InetAddress:面向IP層,用於標識網絡上的硬件資源(InetAddress:封裝IP地址和端口信息) 網絡層
2.1.一、構造方法私有化,不能用new來建立對象也不能用反射來建立。能夠經過靜態方法建立
2.1.二、域名:用來標識的字符串 例如:www.sina.com
2.1.三、靜態方法:getLocalHost();//獲取本機InetAddress對象
2.1.四、靜態方法:InetAddress.getByName(「www.ztenc.com.cn」);//進入中興服務器,經過域名找到服務器的IP地址和機器名
InetAddress address=InetAddress.getLocalHost();//獲得主機名和主機的IP地址USER-20150330OI/172.16.0.126
System.out.println("address:"+address);
InetAddress host=InetAddress.getByName("USER-20150330OI");//根據主機名獲得主機名和IP地址(USER-20150330OI/172.16.0.126)
System.out.println("host:"+host);
2.二、URLs:面向應用層,經過URL,標識網絡服務器上的資源(URL和URLConnection)
2.三、Sockets:面向傳輸層。(Socket:客戶端經過socket發送請求 ,ServerSocket:服務端經過ServerSocket對象作請求監聽)
2.四、Datagram:DatagramPacket:數據報,DatagramSocket:郵遞員 MulticastSocket:多波協議,發送方在指定端口上發送信息,發送端沒有明確的地址,能夠同時有多個接收方在指定端口上接收。(一我的發送多我的接收)
3 Applet類的字節碼文件嵌入在html中,服務器經過下載字節碼文件,運行程序
4 URL url=getCodeBase();//獲得提供它的主機的URL實例,只在Applet程序中用
Host host=url.getHost();//利用URL獲得主機名
InetAddress address=InetAddress.getByName(host);//根據主機名稱獲得主機名和主機的IP地址
DataSocket ds=new DataSocket();//郵遞員
DatagramPacket dp= new DatagramPacket(buf,length,address,port);//buf:字節數組, length :一次傳送數據的長度,address:主機的IP地址,port:服務器端口號
ds.send(dp);//郵遞員發送數據報
5 URL url= new URL(「http://www.ztenv.com.cn/text.html」);//獲得url(用於下載text.html文件)
經過URL(統一資源定位器)獲取網絡字節輸入流對象,url.openStream(),返回一個網絡輸入字節流(從網絡開始,讀到客戶端)
new InputStreamReader(url.openStream());//把字節流變成字符流
BufferedReader br=new BufferedReader(new InputStreamReader(url.openStream()));//把字符流套入buffer流
URL url=new URL(「file:/D:/a.txt」);//file協議,表示讀取本機文件
6 URLConnection (用於上傳文件)
URL url=new URL(「file:/D:/a.txt」);
URLConnection uc=url.openConnection();//獲得鏈接對象
uc.getInputStream();//經過鏈接對象建立網絡字節輸入流對象,經過輸入流讀取數據,叫作下載
URL url1=new URL("file:/f:/Users/a.java");//file協議 讀取本機文件
URLConnection uc=url1.openConnection();//獲得鏈接對象
InputStreamReader in=new InputStreamReader(uc.getInputStream());//建立網絡字節輸入流對象,封裝到輸入字符流中
BufferedReader br1=new BufferedReader(in);//將字符流套入buffer流中while(br1.readLine()!=null){//讀取buffered緩衝流中的數據
System.out.println(br1.readLine());
}
uc.getOutputStream();//建立網絡字節輸出流對象,經過這個流把客戶端的數據上傳到服務端,經過輸出流寫入數據叫作上傳
OutputStreamWriter out=new OutputStreamWriter(uc.getOutputStream());//建立網絡輸出字節流對象,封裝到輸出字符流中
BufferedWriter bw=new BufferedWriter(out);//將字符流套入buffer流中
bw.flush();
7 使用第四層協議TCP協議來通訊
服務器至關於中介轉發做用
7.一、Socket通訊:
ServerSocket :用在服務端,建立時須要給定端口號,調用accpet()方法,對用戶在指定端口上的請求作監聽 ss=new ServerSocket(port); ss.accpet();
Socket:客戶端經過Socket向該端口發送鏈接請求 Socket(host,port);
客戶端和服務端都要建立兩個流,服務端的getInputStream()從信道中讀取數據,客戶端也能夠建立網絡本身輸入流讀取數據。服務端和客戶端均可以建立getOutputStream()能夠把信息寫入信道中。 客戶端只能從信道中讀取服務端放入信道中的數據,服務端也只能讀取客戶端放入信道中的數據。(全雙工理論)
先走服務端,ServerSocket在4331端口上建立服務端對象,調用accpet()方法,返回的對象爲Socket類型。
客戶端創建鏈接請求,new Socket(「localhost」,4331);,一旦沒有出異常,信道就已經建立了.客戶端經過mySocket建立網絡字節輸入流對象,從信道中讀數據到客戶端,mySocket建立網絡字節輸出流對象,輸出數據到信道中。
若是服務端和客戶端一塊兒從信道中讀取信息會產生死鎖。
mySocket(客戶端)
DataOutputStream out=new DataOutputStream(mySocket.getOutputStream());//客戶端獲取輸出數據流 out.writeUTF(「你好」);//客戶端往信道中寫入數據給服務端
DataInputStream out=new DataInputStream(mySocket.getInputStream());//客戶端獲取輸入數據流 out.readUTF();//客戶端從信道中讀取服務端寫入的數據
you(服務端)
DataOutputStream out=new DataOutputStream(you.getOutputStream());//服務端獲取輸出數據流 out.writeUTF(「你也好」);//服務端往信道中寫入數據給客戶端
DataInputStream out=new DataInputStream(you.getInputStream());//服務端獲取輸入數據流 out.readUTF();//服務端從信道中讀取客戶端寫入信道中的數據
readUTF();//一次只能讀取一個字符串
鏈接時,先開啓服務器,斷開鏈接時,先斷開客戶端。
InetAddress複寫了toString():顯示主機名+IP地址
協議名:規定訪問資源的方式(file:本地訪問,http:瀏覽器)
URL url=new URL(「file:/f:/t.txt」);
url.openStream();//字節輸入流
客戶端在同一時刻能夠讀取信道中的數據和寫入數據到信道中。服務端也能夠在從信道中讀取數據的時候同時寫入數據到信道中。由於客戶端和服務端有兩個虛信道。 只須要避免客戶端和服務端都從信道中讀取數據,而且信道中沒有數據的時候就不會產生死鎖。
1 UDP協議(無序不可靠可是高效)
先把數據放在數據報中,數據以字節數組對象的形式放入數據報中。
String str=」abcdefg」;
byte[] buf=str.getBytes();//將字符串變爲字節數組對象
一個類中至少要有兩個線程,一個線程負責發送數據,另外一個線程負責接收數據。(也有可能發送數據的時候正好接收數據了)
上海用Thread線程接收北京發送的數據,上海在主線程經過actionPerformed方法向端口號8888發送信息,北京經過調用Thread線程所執行的run方法中8888端口號中接收信息。 主線程用來發送數據,Thread線程用來接收數據。
主線程是虛擬機建立的,另一個線程應該在主線程主方法中建立。
class BeiJing extends Frame implements ActionListener,Runnable{
public BeiJing(){
Thread thread=new Thread(this);//在構造方法中建立線程對象,用於對方接收信息
thread.start();//啓動接收數據的線程
this.addActionListener(this);
}
//響應發送數據報按鈕事件(發信)
public void actionPerformed(ActionEvent e){
byte[] buf=textOut.getText().trim().getBytes();//拿到輸出文本框的內容
InetAddress address=InetAddress.getByName(「localhost」);//獲得地址
DatagramPacket dp=new DatagramPacket(buf,buf.length,address,port);//把數據封裝到數據報(相似於把信放入信箱中)
DatagramSocket ds=new DatagramSocket();//郵遞員
ds.send(dp);//發送數據報
}
//對方接收信息(收信)
public void run(){
byte[] buf=new byte[8192];//空的字節數組對象
DatagramPacket dp=new DatagramPacket(buf,buf.length);//空的數據報
DatagramSocket ds=new DatagramSocket(port);//在port端口上建立郵遞員
ds.receive(dp);//接收數據(收到的數據存入空的數據報dp中)
dp.getPort();//獲取發送端端口號
dp.getAddress();//獲取發送端的IP地址
dp.getLength();//獲取接收到的數據的長度
dp.getData();//是一個字節數組對象
String message=new String(dp.getData());//將字節數組對象變爲字符串
textIn.setText(message);//將接收到的數據設置到
textIn.append(「hahaha」);//在文本框中追加數據
}
frame.pack();//自動調整組件大小
}
2 多波協議(羣發消息)
MulticastSocket:多播套接字
InetAddress group=InetAddress.getByName(「239.255.8.0」);// 獲得多播組地址對象
MulticastSocket socket=new MulticastSocket(port);//指定播送消息的套接字,郵遞員
socket.joinGroup(group);//加入多播組
接收端和發送端的group和port應該是相同的。
調用線程的interrupt()方法,線程從封鎖態進入就緒態
接收端:
在public void actionPerformed(ActionEvent e){} 方法中建立一個線程,new Thread(this); 接收信息類實現 Runnable接口。
在public void run(){}方法中接收信息。
建立空字節數組byte[] buf=new byte[8192];
建立空數據報new DatagramPacket(buf,buf.length,group,port)(指定group,port 接收端和發送端相同),
MuticastSocket多播套接字爲郵遞員。 socket.receive(dp);//將數據放入數據報中 dp.getData();//獲得數據報中的數據,爲字節數組類型
String message=new String(dp.getData());//將字節數組變爲字符串
中止接收按鈕響應: thread.interrupt();//只應用一個線程處於封鎖狀態
繼續設置標誌位 flag=true;
thread.interrupt()方法一執行,接收線程會執行catch中的代碼,在catch代碼塊中判斷flag的值,爲true時 break。
3 Java聊天室(多線程,接口,GUI 事件突發機制)
服務器建立ServerSocket對象 new ServerSocket(port,10);//端口號和最大鏈接數
對於最大限度用戶數,服務器端應該用線程池或者線程集合。重點在服務端。
爲多個用戶建立信道,同時爲多個用戶服務。
經過線程對象拿到信道,得到流
怎麼管理10個線程對象?
線程數組來維護多個線程對象。定義一個線程繼承了Thread類,複寫run方法,提供個有參的構造方法。在服務端定義該類的線程數組,使用數組管理多個線程對象。
private ServerThread[] serThread=new ServerThread[maxClients];
serThread[i]=new ServerThread(ss.accept(),i);//建立服務器線程,i表示等待鏈接線程數
serThread[i].start();//啓動線程
下線:
定義一個下線數組,10個元素 int[],先判斷全部上線的人數,再判斷下線人數
用for循環判斷用戶是否已經下線(用戶ID)
for(int m=0;m<onlineClients;m++){//對上線人數的循環
boolean flag=true;//標記用戶是否爲上線狀態:true表示已上線,false:表示已下線
for(int j=0;j<outlineID;j++){//對上線後又下線了的人數的循環
if(i==outline[j]){//判斷用戶i是否已經下線,若是i不在下線數組裏面表示它以成功上線
flag=false;
break;//跳出本層循環
}
}
私聊:
if((!message.equals(""))&&(message!=null)&&(message.startsWith("*"))){//判斷是否爲私聊信息
StringTokenizer str=new StringTokenizer(message,"*"); //截取出以*號分隔的的字符 *12*qwe 截取後結果爲: 12
num=Integer.parseInt(str.nextToken());//獲得信息接收端目的用戶
serThread[num].output.writeUTF(message);//將信息寫給目的用戶
服務端接收信息,客戶端發送信息
StringTokenizer(str,」*」);//用*分隔字符串
公聊:
雙重for循環,把信息發給每個在線的用戶
for(int i=0;i<onlineClients;i++){
boolean flag=false;
for(int k=0;k<outline.length;k++){
if(i==outline[k]){
flag=true;
break;
}
}
if(flag){
try {
serThread[i].output.writeUTF(ID+"號用戶剛剛下線了");
}catch (IOException e1) {
e1.printStackTrace();
}
}
}
問題?
用戶下線後,此用戶還能繼續上線嘛?
不能,由於線程數組已經滿了,下線後內存已經被佔。此現象稱爲假溢出
能夠用集合來存儲線程對象,也能夠用線程池
聊天時只有一個服務器,只須要先開啓而且開啓一次就好,客戶端能夠開啓多個,相互發送消息。
週末做業:
聊天室,TCP協議,UDP協議。版本各一個,使用線程池或者集合數組存儲線程對象
多播協議聊天實例:
服務端:
//服務端
public void actionPerformed(ActionEvent e6){
byte[] buf=textOut.getText().trim().getBytes();//將文本框中須要發送的數據變成字節數組對象
try {
InetAddress address=InetAddress.getByName("239.255.8.0");//端口號必須爲D類地址 240.0.0.0-239.255.255.255
MulticastSocket ms=new MulticastSocket();//多播郵遞員
ms.joinGroup(address);//加入多播組織
DatagramPacket dp=new DatagramPacket(buf,buf.length,address,23342);//將數據打包
ms.send(dp);//發送數據
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}}
客戶端:
//啓動線程接收用戶發來的數據
public void run(){
while(true){
byte[] buf=new byte[8192];//建立空的字節數組對象,接收多播發過來的數據
try {
InetAddress addr=InetAddress.getByName("239.255.8.0");//指定接收同一廣播地址的廣播
DatagramPacket dp=new DatagramPacket(buf,buf.length);//準備好數據包接收數據
MulticastSocket ms=new MulticastSocket(23342);//監聽多播端口號
ms.joinGroup(addr);//加入多播組織
ms.receive(dp);//接收數據
String message=new String(dp.getData());//將接收過來的數據變爲字符串類型
textIn.append(message+"\n");//存入文本輸出域中
System.out.println("lalala__"+message);
} catch (UnknownHostException e1) {
e1.printStackTrace();
} catch (SocketException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} }
B GRVFC