參考:http://www.runoob.com/java/java-tutorial.html
appendReplacement 和 appendTail 方法
Java 重寫(Override)與重載(Overload)
Java 基本數據類型
內置數據類型
byte:
l byte 數據類型是8位、有符號的,以二進制補碼表示的整數;
l 最小值是 -128(-2^7);
l 最大值是 127(2^7-1);
l 默認值是 0;
l byte 類型用在大型數組中節約空間,主要代替整數,因為 byte 變量占用的空間只有 int 類型的四分之一;
l 例子:byte a = 100,byte b = -50。
float:
l float 數據類型是單精度、32位、符合IEEE 754標准的浮點數;
l float 在儲存大型浮點數組的時候可節省內存空間;
l 默認值是 0.0f;
l 浮點數不能用來表示精確的值,如貨幣;
l 例子:float f1 = 234.5f。
double:
l double 數據類型是雙精度、64 位、符合IEEE 754標准的浮點數;
l 浮點數的默認類型為double類型;
l double類型同樣不能表示精確的值,如貨幣;
l 默認值是 0.0d;
l 例子:double d1 = 123.4。
char:
l char類型是一個單一的 16 位 Unicode 字符;
l 最小值是 \u0000(即為0);
l 最大值是 \uffff(即為65,535);
l char 數據類型可以儲存任何字符;
l 例子:char letter = 'A';。
引用類型
l 在Java中,引用類型的變量非常類似於C/C++的指針。引用類型指向一個對象,指向對象的變量是引用變量。這些變量在聲明時被指定為一個特定的類型,比如 Employee、Puppy 等。變量一旦聲明后,類型就不能被改變了。
l 對象、數組都是引用數據類型。
l 所有引用類型的默認值都是null。
l 一個引用變量可以用來引用任何與之兼容的類型。
l 例子:Site site = new Site("Runoob")。
byte,short,char—> int —> long—> float —> double
數據類型轉換必須滿足如下規則:
l 1. 不能對boolean類型進行類型轉換。
l 2. 不能把對象類型轉換成不相關類的對象。
l 3. 在把容量大的類型轉換為容量小的類型時必須使用強制類型轉換。
l 4. 轉換過程中可能導致溢出或損失精度,例如:
l 5. 浮點數到整數的轉換是通過舍棄小數得到,而不是四舍五入,例如:
(int)23.7 == 23; (int)-45.89f == -45
隱含強制類型轉換
l 1. 整數的默認類型是 int。
l 2. 浮點型不存在這種情況,因為在定義 float 類型時必須在數字后面跟上 F 或者 f。
Java 變量類型
Java語言支持的變量類型有:
l 類變量:獨立於方法之外的變量,用 static 修飾。
l 實例變量:獨立於方法之外的變量,不過沒有 static 修飾。
l 局部變量:類的方法中的變量。
public class Variable{ static int allClicks=0; // 類變量 String str="hello world"; // 實例變量 public void method(){ int i =0; // 局部變量 } }
Java 局部變量
l 局部變量聲明在方法、構造方法或者語句塊中;
l 局部變量在方法、構造方法、或者語句塊被執行的時候創建,當它們執行完成后,變量將會被銷毀;
l 訪問修飾符不能用於局部變量;
l 局部變量只在聲明它的方法、構造方法或者語句塊中可見;
l 局部變量是在棧上分配的。
l 局部變量沒有默認值,所以局部變量被聲明后,必須經過初始化,才可以使用。
實例變量
l 實例變量聲明在一個類中,但在方法、構造方法和語句塊之外;
l 當一個對象被實例化之后,每個實例變量的值就跟着確定;
l 實例變量在對象創建的時候創建,在對象被銷毀的時候銷毀;
l 實例變量的值應該至少被一個方法、構造方法或者語句塊引用,使得外部能夠通過這些方式獲取實例變量信息;
l 實例變量可以聲明在使用前或者使用后;
l 訪問修飾符可以修飾實例變量;
l 實例變量對於類中的方法、構造方法或者語句塊是可見的。一般情況下應該把實例變量設為私有。通過使用訪問修飾符可以使實例變量對子類可見;
l 實例變量具有默認值。數值型變量的默認值是0,布爾型變量的默認值是false,引用類型變量的默認值是null。變量的值可以在聲明時指定,也可以在構造方法中指定;
l 實例變量可以直接通過變量名訪問。但在靜態方法以及其他類中,就應該使用完全限定名:ObejectReference.VariableName。
類變量(靜態變量)
l 類變量也稱為靜態變量,在類中以static關鍵字聲明,但必須在方法構造方法和語句塊之外。
l 無論一個類創建了多少個對象,類只擁有類變量的一份拷貝。
l 靜態變量除了被聲明為常量外很少使用。常量是指聲明為public/private,final和static類型的變量。常量初始化后不可改變。
l 靜態變量儲存在靜態存儲區。經常被聲明為常量,很少單獨使用static聲明變量。
l 靜態變量在第一次被訪問時創建,在程序結束時銷毀。
l 與實例變量具有相似的可見性。但為了對類的使用者可見,大多數靜態變量聲明為public類型。
l 默認值和實例變量相似。數值型變量默認值是0,布爾型默認值是false,引用類型默認值是null。變量的值可以在聲明的時候指定,也可以在構造方法中指定。此外,靜態變量還可以在靜態語句塊中初始化。
l 靜態變量可以通過:ClassName.VariableName的方式訪問。
l 類變量被聲明為public static final類型時,類變量名稱一般建議使用大寫字母。如果靜態變量不是public和final類型,其命名方式與實例變量以及局部變量的命名方式一致。
Java 修飾符
修飾符 |
當前類 |
同一包內 |
子孫類(同一包) |
子孫類(不同包) |
其他包 |
public |
Y |
Y |
Y |
Y |
Y |
protected |
Y |
Y |
Y |
Y/N(說明) |
N |
default |
Y |
Y |
Y |
N |
N |
private |
Y |
N |
N |
N |
N |
默認訪問修飾符-不使用任何關鍵字
default (即缺省,什么也不寫): 在同一包內可見,不使用任何修飾符。使用對象:類、接口、變量、方法。
使用默認訪問修飾符聲明的變量和方法,對同一個包內的類是可見的。接口里的變量都隱式聲明為 public static final,而接口里的方法默認情況下訪問權限為 public。
公有訪問修飾符-public
被聲明為 public 的類、方法、構造方法和接口能夠被任何其他類訪問。
如果幾個相互訪問的 public 類分布在不同的包中,則需要導入相應 public 類所在的包。由於類的繼承性,類所有的公有方法和變量都能被其子類繼承。
以下函數使用了公有訪問控制:
public static void main(String[] arguments) { // ...}
Java 程序的 main() 方法必須設置成公有的,否則,Java 解釋器將不能運行該類。
受保護的訪問修飾符-protected
protected 是最難理解的一種 Java 類成員訪問權限修飾詞,更多詳細內容請查看 Java protected 關鍵字詳解。
protected 需要從以下兩個點來分析說明:
l 子類與基類在同一包中:被聲明為 protected 的變量、方法和構造器能被同一個包中的任何其他類訪問;
l 子類與基類不在同一包中:那么在子類中,子類實例可以訪問其從基類繼承而來的 protected 方法,而不能訪問基類實例的protected方法。
l 接口及接口的成員變量和成員方法不能聲明為 protected。
訪問控制和繼承
請注意以下方法繼承的規則(只能降級):
l 父類中聲明為 public 的方法在子類中也必須為 public。
l 父類中聲明為 protected 的方法在子類中要么聲明為 protected,要么聲明為 public,不能聲明為 private。
l 父類中聲明為 private 的方法,不能夠被繼承。
非訪問修飾符
為了實現一些其他的功能,Java 也提供了許多非訪問修飾符。
static 修飾符,用來修飾類方法和類變量。
final 修飾符,用來修飾類、方法和變量,final 修飾的類不能夠被繼承,修飾的方法不能被繼承類重新定義,修飾的變量為常量,是不可修改的。
abstract 修飾符,用來創建抽象類和抽象方法。
synchronized 和 volatile 修飾符,主要用於線程的編程
final 修飾符
final 變量:
final 表示"最后的、最終的"含義,變量一旦賦值后,不能被重新賦值。被 final 修飾的實例變量必須顯式指定初始值。
final 修飾符通常和 static 修飾符一起使用來創建類常量。
final 方法
類中的 final 方法可以被子類繼承,但是不能被子類修改。
聲明 final 方法的主要目的是防止該方法的內容被修改。
abstract 修飾符
抽象類:
抽象類不能用來實例化對象,聲明抽象類的唯一目的是為了將來對該類進行擴充。
一個類不能同時被 abstract 和 final 修飾。如果一個類包含抽象方法,那么該類一定要聲明為抽象類,否則將出現編譯錯誤。
抽象類可以包含抽象方法和非抽象方法。
抽象方法
抽象方法是一種沒有任何實現的方法,該方法的的具體實現由子類提供。
抽象方法不能被聲明成 final 和 static。
任何繼承抽象類的子類必須實現父類的所有抽象方法,除非該子類也是抽象類。
如果一個類包含若干個抽象方法,那么該類必須聲明為抽象類。抽象類可以不包含抽象方法。
抽象方法的聲明以分號結尾,例如:public abstract sample();。
synchronized 修飾符
synchronized 關鍵字聲明的方法同一時間只能被一個線程訪問。synchronized 修飾符可以應用於四個訪問修飾符。
transient 修飾符
序列化的對象包含被 transient 修飾的實例變量時,java 虛擬機(JVM)跳過該特定的變量。
該修飾符包含在定義變量的語句中,用來預處理類和變量的數據類型。
volatile 修飾符
volatile 修飾的成員變量在每次被線程訪問時,都強制從共享內存中重新讀取該成員變量的值。而且,當成員變量發生變化時,會強制線程將變化值回寫到共享內存。這樣在任何時刻,兩個不同的線程總是看到某個成員變量的同一個值。
一個 volatile 對象引用可能是 null。
Java 運算符
短路邏輯運算符
當使用與邏輯運算符時,在兩個操作數都為true時,結果才為true,但是當得到第一個操作為false時,其結果就必定是false,這時候就不會再判斷第二個操作了。
instanceof 運算符
該運算符用於操作對象實例,檢查該對象是否是一個特定類型(類類型或接口類型)。
instanceof運算符使用格式如下:
( Object reference variable ) instanceof (class/interface type)
如果運算符左側變量所指的對象,是操作符右側類或接口(class/interface)的一個對象,那么結果為真。
下面是一個例子:
String name = "James";boolean result = name instanceof String; // 由於 name 是 String 類型,所以返回真
Java運算符優先級
一元 |
+ + - !〜 |
從右到左 |
條件 |
?: |
從右到左 |
賦值 |
= + = - = * = / =%= >> = << =&= ^ = | = |
從右到左 |
Java 增強 for 循環
Java5 引入了一種主要用於數組的增強型 for 循環。
Java 增強 for 循環語法格式如下:
for(聲明語句 : 表達式){ //代碼句子}int [] numbers = {10, 20, 30, 40, 50}; for(int x : numbers ){ System.out.print( x ); System.out.print(","); }
聲明語句:聲明新的局部變量,該變量的類型必須和數組元素的類型匹配。其作用域限定在循環語句塊,其值與此時數組元素的值相等。
表達式:表達式是要訪問的數組名,或者是返回值為數組的方法。
Java switch case 語句
switch case 執行時,一定會先進行匹配,匹配成功返回當前 case 的值,再根據是否有 break,判斷是否繼續輸出,或是跳出判斷。
如果 case 語句塊中沒有 break 語句時,JVM 並不會順序輸出每一個 case 對應的返回值,而是繼續匹配,匹配不成功則返回默認 case。
如果當前匹配成功的 case 語句塊沒有 break 語句,則從當前 case 開始,后續所有 case 的值都會輸出,如果后續的 case 語句塊有 break 語句則會跳出判斷。
Java Number & Math 類
所有的包裝類(Integer、Long、Byte、Double、Float、Short)都是抽象類 Number 的子類。
當 x 被賦為整型值時,由於x是一個對象,所以編譯器要對x進行裝箱。然后,為了使x能進行加運算,所以要對x進行拆箱。
Math 的方法都被定義為 static 形式,通過 Math 類可以在主函數中直接調用。
序號 |
方法與描述 |
1 |
將 Number 對象轉換為xxx數據類型的值並返回。 |
2 |
將number對象與參數比較。 |
3 |
判斷number對象是否與參數相等。 |
4 |
返回一個 Number 對象指定的內置數據類型 |
5 |
以字符串形式返回值。 |
6 |
將字符串解析為int類型。 |
10 |
返回與參數最接近的整數。返回類型為double。 |
intValue() :以 int 形式返回指定的數值。
l Integer valueOf(int i):返回一個表示指定的 int 值的 Integer 實例。
l Integer valueOf(String s):返回保存指定的 String 的值的 Integer 對象。
l Integer valueOf(String s, int radix): 返回一個 Integer 對象,該對象中保存了用第二個參數提供的基數進行解析時從指定的 String 中提取的值。
Integer b = Integer.valueOf("444",16); // 使用 16 進制,=1092
Java Character 類
將一個char類型的參數傳遞給需要一個Character類型參數的方法時,那么編譯器會自動地將char類型參數轉換為Character對象。 這種特征稱為裝箱,反過來稱為拆箱。
序號 |
方法與描述 |
1 |
是否是一個字母 |
2 |
是否是一個數字字符 |
3 |
是否是一個空白字符 |
4 |
是否是大寫字母 |
5 |
是否是小寫字母 |
6 |
指定字母的大寫形式 |
7 |
指定字母的小寫形式 |
8 |
toString() 返回字符的字符串形式,字符串的長度僅為1 |
Java String 類
創建字符串
創建字符串最簡單的方式如下:
String greeting = "菜鳥教程";
在代碼中遇到字符串常量時,這里的值是 "菜鳥教程"",編譯器會使用該值創建一個 String 對象。
和其它對象一樣,可以使用關鍵字和構造方法來創建 String 對象。
String 類有 11 種構造方法,這些方法提供不同的參數來初始化字符串,比如提供一個字符數組參數:
注意:String 類是不可改變的,所以你一旦創建了 String 對象,那它的值就無法改變了(詳看筆記部分解析)。
如果需要對字符串做很多修改,那么應該選擇使用 StringBuffer & StringBuilder 類。
StringBuffer 方法
以下是 StringBuffer 類支持的主要方法:
序號 |
方法描述 |
1 |
public StringBuffer append(String s) 將指定的字符串追加到此字符序列。 |
2 |
public StringBuffer reverse() 將此字符序列用其反轉形式取代。 |
3 |
public delete(int start, int end) 移除此序列的子字符串中的字符。 |
4 |
public insert(int offset, int i) 將 int 參數的字符串表示形式插入此序列中。 |
5 |
replace(int start, int end, String str) 使用給定 String 中的字符替換此序列的子字符串中的字符。 |
創建格式化字符串
我們知道輸出格式化數字可以使用 printf() 和 format() 方法。
String 類使用靜態方法 format() 返回一個String 對象而不是 PrintStream 對象。
String 類的靜態方法 format() 能用來創建可復用的格式化字符串,而不僅僅是用於一次打印輸出。
如下所示:
System.out.printf("浮點型變量的值為 " + "%f, 整型變量的值為 " + " %d, 字符串變量的值為 " + "is %s", floatVar, intVar, stringVar);//你也可以這樣寫String fs;fs = String.format("浮點型變量的值為 " + "%f, 整型變量的值為 " + " %d, 字符串變量的值為 " + " %s", floatVar, intVar, stringVar);
String 方法
下面是 String 類支持的方法,更多詳細,參看 Java String API 文檔:
SN(序號) |
方法描述 |
1 |
返回指定索引處的 char 值。 |
2 |
把這個字符串和另一個對象比較。 |
3 |
int compareTo(String anotherString) 按字典順序比較兩個字符串。 |
4 |
int compareToIgnoreCase(String str) 按字典順序比較兩個字符串,不考慮大小寫。 |
5 |
將指定字符串連接到此字符串的結尾。 |
6 |
boolean contentEquals(StringBuffer sb) 當且僅當字符串與指定的StringBuffer有相同順序的字符時候返回真。 |
7 |
static String copyValueOf(char[] data) 返回指定數組中表示該字符序列的 String。 |
9 |
boolean endsWith(String suffix) 測試此字符串是否以指定的后綴結束。 |
10 |
boolean equals(Object anObject) 將此字符串與指定的對象比較。 |
11 |
boolean equalsIgnoreCase(String anotherString) 將此 String 與另一個 String 比較,不考慮大小寫。 |
16 |
返回指定字符在此字符串中第一次出現處的索引。 |
17 |
int indexOf(int ch, int fromIndex) 返回在此字符串中第一次出現指定字符處的索引,從指定的索引開始搜索。 |
18 |
返回指定子字符串在此字符串中第一次出現處的索引。 |
19 |
int indexOf(String str, int fromIndex) 返回指定子字符串在此字符串中第一次出現處的索引,從指定的索引開始。 |
21 |
返回指定字符在此字符串中最后一次出現處的索引。 |
22 |
int lastIndexOf(int ch, int fromIndex) 返回指定字符在此字符串中最后一次出現處的索引,從指定的索引處開始進行反向搜索。 |
23 |
返回指定子字符串在此字符串中最右邊出現處的索引。 |
24 |
int lastIndexOf(String str, int fromIndex) 返回指定子字符串在此字符串中最后一次出現處的索引,從指定的索引開始反向搜索。 |
25 |
返回此字符串的長度。 |
26 |
告知此字符串是否匹配給定的正則表達式。 |
29 |
String replace(char oldChar, char newChar) 返回一個新的字符串,它是通過用 newChar 替換此字符串中出現的所有 oldChar 得到的。 |
30 |
String replaceAll(String regex, String replacement) 使用給定的 replacement 替換此字符串所有匹配給定的正則表達式的子字符串。 |
31 |
String replaceFirst(String regex, String replacement) 使用給定的 replacement 替換此字符串匹配給定的正則表達式的第一個子字符串。 |
32 |
根據給定正則表達式的匹配拆分此字符串。 |
33 |
String[] split(String regex, int limit) 根據匹配給定的正則表達式來拆分此字符串。 |
34 |
boolean startsWith(String prefix) 測試此字符串是否以指定的前綴開始。 |
35 |
boolean startsWith(String prefix, int toffset) 測試此字符串從指定索引開始的子字符串是否以指定前綴開始。 |
36 |
CharSequence subSequence(int beginIndex, int endIndex) 返回一個新的字符序列,它是此序列的一個子序列。 |
37 |
String substring(int beginIndex) 返回一個新的字符串,它是此字符串的一個子字符串。 |
38 |
String substring(int beginIndex, int endIndex) 返回一個新字符串,它是此字符串的一個子字符串。 |
39 |
將此字符串轉換為一個新的字符數組。 |
40 |
使用默認語言環境的規則將此 String 中的所有字符都轉換為小寫。 |
41 |
String toLowerCase(Locale locale) 使用給定 Locale 的規則將此 String 中的所有字符都轉換為小寫。 |
42 |
返回此對象本身(它已經是一個字符串!)。 |
43 |
使用默認語言環境的規則將此 String 中的所有字符都轉換為大寫。 |
44 |
String toUpperCase(Locale locale) 使用給定 Locale 的規則將此 String 中的所有字符都轉換為大寫。 |
45 |
Java 數組
注意: 建議使用 dataType[] arrayRefVar 的聲明風格聲明數組變量。 dataType arrayRefVar[] 風格是來自 C/C++ 語言 ,在Java中采用是為了讓 C/C++ 程序員能夠快速理解java語言。
java 里面為什么數組都需要new一下?而C++不需要
java 數組所引用的值,是在堆里的,
java 數組是引用對象,引用對象都需要開辟內存空間,
new 關鍵字在java里是實例化對象,也是為對象開辟內存空間
其實也不一定要new, int[] arr = {}; 這樣也是可以的
如果大括號里不賦值,就是個空數組,大括號里賦幾個值,這個數組就是多大
c / c++ 也是這樣用
int arr1[] = {1,2,3,4,5,6};
int arr2[50] = {-23,34,56,100,234,-9,0,45,10002};
只是,c/c++ 聲明時可以指定大小,
JAVA 里面的數組名是一個引用變量,引用變量是放在是放在一個棧里面,而JAVA數組本身就是對象,Java中對象是在堆中的,因此數組無論保存原始類型還是其他對象類型,數組對象本身是在堆中的。所以如果不new一下,就無法得到這個數組,即引用變量沒有引用的對象。而在C++中,數組名實際上是數組的首地址,是一個指針,數組在聲明之后就已經生成了這個數組對象。就不用new了
下面的語句首先聲明了一個數組變量 myList,接着創建了一個包含 10 個 double 類型元素的數組,並且把它的引用賦值給 myList 變量。
// 數組大小 int size = 10; // 定義數組 double[] myList = new double[size]; myList[0] = 5.6;//……
引用和指針的區別?
指針是一個變量,只不過這個變量存儲的是一個地址,指向內存的一個存儲單元;而引用跟原來的變量實質上是同一個東西,只不過是原變量的一個別名而已。
本質:引用是別名,指針是地址,具體的:
①從現象上看,指針在運行時可以改變其所指向的值,而引用一旦和某個對象綁定后就不再改變。這句話可以理解為:指針可以被重新賦值以指向另一個不同的對象。但是引用則總是指向在初始化時被指定的對象,以后不能改變,但是指定的對象其內容可以改變。
②從內存分配上看,程序為指針變量分配內存區域,而不為引用分配內存區域,因為引用聲明時必須初始化,從而指向一個已經存在的對象。引用不能指向空值。
注:標准沒有規定引用要不要占用內存,也沒有規定引用具體要怎么實現,具體隨編譯器 http://bbs.csdn.net/topics/320095541
③ 從編譯上看,程序在編譯時分別將指針和引用添加到符號表上,符號表上記錄的是變量名及變量所對應地址。指針變量在符號表上對應的地址值為指針變量的地址值,而引用在符號表上對應的地址值為引用對象的地址值。符號表生成后就不會再改,因此指針可以改變指向的對象(指針變量中的值可以改),而引用對象不能改。這是使用指針不安全而使用引用安全的主要原因。從某種意義上來說引用可以被認為是不能改變的指針。
④不存在指向空值的引用這個事實,意味着使用引用的代碼效率比使用指針的要高。因為在使用引用之前不需要測試它的合法性。相反,指針則應該總是被測試,防止其為空。
⑤理論上,對於指針的級數沒有限制,但是引用只能是一級。
Arrays 類
java.util.Arrays 類能方便地操作數組,它提供的所有方法都是靜態的。
具有以下功能:
l 給數組賦值:通過 fill 方法。
l 對數組排序:通過 sort 方法,按升序。
l 比較數組:通過 equals 方法比較數組中元素值是否相等。
l 查找數組元素:通過 binarySearch 方法能對排序好的數組進行二分查找法操作。
Java 日期時間
序號 |
方法和描述 |
1 |
boolean after(Date date) 若當調用此方法的Date對象在指定日期之后返回true,否則返回false。 |
2 |
boolean before(Date date) 若當調用此方法的Date對象在指定日期之前返回true,否則返回false。 |
3 |
Object clone( ) 返回此對象的副本。 |
4 |
int compareTo(Date date) 比較當調用此方法的Date對象和指定日期。兩者相等時候返回0。調用對象在指定日期之前則返回負數。調用對象在指定日期之后則返回正數。 |
5 |
int compareTo(Object obj) 若obj是Date類型則操作等同於compareTo(Date) 。否則它拋出ClassCastException。 |
6 |
boolean equals(Object date) 當調用此方法的Date對象和指定日期相等時候返回true,否則返回false。 |
7 |
long getTime( ) 返回自 1970 年 1 月 1 日 00:00:00 GMT 以來此 Date 對象表示的毫秒數。 |
8 |
int hashCode( ) 返回此對象的哈希碼值。 |
9 |
void setTime(long time)
用自1970年1月1日00:00:00 GMT以后time毫秒數設置時間和日期。 |
10 |
String toString( ) 把此 Date 對象轉換為以下形式的 String: dow mon dd hh:mm:ss zzz yyyy 其中: dow 是一周中的某一天 (Sun, Mon, Tue, Wed, Thu, Fri, Sat)。 |
使用 SimpleDateFormat 格式化日期
Date dNow = new Date( );SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");System.out.println("當前時間為: " + ft.format(dNow));
使用printf格式化日期
printf 方法可以很輕松地格式化時間和日期。使用兩個字母格式,它以 %t 開頭並且以下面表格中的一個字母結尾。
轉 換 符 |
說 明 |
示 例 |
c |
包括全部日期和時間信息 |
星期六 十月 27 14:21:20 CST 2007 |
F |
"年-月-日"格式 |
2007-10-27 |
D |
"月/日/年"格式 |
10/27/07 |
r |
"HH:MM:SS PM"格式(12時制) |
02:25:51 下午 |
T |
"HH:MM:SS"格式(24時制) |
14:28:16 |
R |
"HH:MM"格式(24時制) |
14:28 |
解析字符串為時間
SimpleDateFormat 類有一些附加的方法,特別是parse(),它試圖按照給定的SimpleDateFormat 對象的格式化存儲來解析字符串。
Java 正則表達式
java.util.regex 包主要包括以下三個類:
l Pattern 類:
pattern 對象是一個正則表達式的編譯表示。Pattern 類沒有公共構造方法。要創建一個 Pattern 對象,你必須首先調用其公共靜態編譯方法,它返回一個 Pattern 對象。該方法接受一個正則表達式作為它的第一個參數。
l Matcher 類:
Matcher 對象是對輸入字符串進行解釋和匹配操作的引擎。與Pattern 類一樣,Matcher 也沒有公共構造方法。你需要調用 Pattern 對象的 matcher 方法來獲得一個 Matcher 對象。
l PatternSyntaxException:
PatternSyntaxException 是一個非強制異常類,它表示一個正則表達式模式中的語法錯誤。
注意:在 Java 中正則表達式中則需要有兩個反斜杠才能被解析為其他語言中的轉義作用。也可以簡單的理解在 Java 的正則表達式中,兩個 \\ 代表其他語言中的一個 \,這也就是為什么表示一位數字的正則表達式是 \\d,而表示一個普通的反斜杠是 \\\\。
根據 Java Language Specification 的要求,Java 源代碼的字符串中的反斜線被解釋為 Unicode 轉義或其他字符轉義。因此必須在字符串字面值中使用兩個反斜線,表示正則表達式受到保護,不被 Java 字節碼編譯器解釋。例如,當解釋為正則表達式時,字符串字面值 "\b" 與單個退格字符匹配,而 "\\b" 與單詞邊界匹配。字符串字面值 "\(hello\)" 是非法的,將導致編譯時錯誤;要與字符串 (hello) 匹配,必須使用字符串字面值 "\\(hello\\)"。
// 按指定模式在字符串查找 String line = "This order was placed for QT3000! OK?"; String pattern = "(\\D*)(\\d+)(.*)"; // 創建 Pattern 對象 Pattern r = Pattern.compile(pattern); // 現在創建 matcher 對象 Matcher m = r.matcher(line);
matches 和 lookingAt 方法
matches 和 lookingAt 方法都用來嘗試匹配一個輸入序列模式。它們的不同是 matches 要求整個序列都匹配,而lookingAt 不要求。
lookingAt 方法雖然不需要整句都匹配,但是需要從第一個字符開始匹配。
replaceFirst 和 replaceAll 方法
replaceFirst 和 replaceAll 方法用來替換匹配正則表達式的文本。不同的是,replaceFirst 替換首次匹配,replaceAll 替換所有匹配。
appendReplacement 和 appendTail 方法
Matcher 類也提供了appendReplacement 和 appendTail 方法用於文本替換
Java 方法
System.out.println(),那么它是什么呢?
l println() 是一個方法。
l System 是系統類。
l out 是標准輸出對象。
命令行參數的使用
有時候你希望運行一個程序時候再傳遞給它消息。這要靠傳遞命令行參數給main()函數實現。
命令行參數是在執行程序時候緊跟在程序名字后面的信息。
public class CommandLine { public static void main(String args[]){ for(int i=0; i<args.length; i++){ System.out.println("args[" + i + "]: " + args[i]); } }}$ javac CommandLine.java $ java CommandLine this is a command line 200 -100 args[0]: this args[1]: is args[2]: a args[3]: command args[4]: line args[5]: 200 args[6]: -100
構造方法
當一個對象被創建時候,構造方法用來初始化該對象。構造方法和它所在類的名字相同,但構造方法沒有返回值。
通常會使用構造方法給一個類的實例變量賦初值,或者執行其它必要的步驟來創建一個完整的對象。
不管你是否自定義構造方法,所有的類都有構造方法,因為Java自動提供了一個默認構造方法,默認構造方法的訪問修改符和類的訪問修改符相同(類為 public,構造函數也為 public;類改為 private,構造函數也改為 private)。
一旦你定義了自己的構造方法,默認構造方法就會失效。
可變參數
JDK 1.5 開始,Java支持傳遞同類型的可變參數給一個方法。
方法的可變參數的聲明如下所示:
typeName... parameterName
在方法聲明中,在指定參數類型后加一個省略號(...) 。
一個方法中只能指定一個可變參數,它必須是方法的最后一個參數。任何普通的參數必須在它之前聲明。
public class VarargsDemo { public static void main(String args[]) { // 調用可變參數的方法 printMax(34, 3, 3, 2, 56.5); printMax(new double[]{1, 2, 3}); } public static void printMax( double... numbers) { if (numbers.length == 0) { System.out.println("No argument passed"); return; } double result = numbers[0]; for (int i = 1; i < numbers.length; i++){ if (numbers[i] > result) { result = numbers[i]; } } System.out.println("The max value is " + result); } }
finalize() 方法
Java 允許定義這樣的方法,它在對象被垃圾收集器析構(回收)之前調用,這個方法叫做 finalize( ),它用來清除回收對象。
例如,你可以使用 finalize() 來確保一個對象打開的文件被關閉了。
在 finalize() 方法里,你必須指定在對象銷毀時候要執行的操作。
finalize() 一般格式是:
protected void finalize(){ // 在這里終結代碼}
關鍵字 protected 是一個限定符,它確保 finalize() 方法不會被該類以外的代碼調用。
當然,Java 的內存回收可以由 JVM 來自動完成。如果你手動使用,則可以使用上面的方法。
Java 流(Stream)、文件(File)和IO
http://www.runoob.com/java/java-files-io.html
讀取控制台輸入
Java 的控制台輸入由 System.in 完成。
為了獲得一個綁定到控制台的字符流,你可以把 System.in 包裝在一個 BufferedReader 對象中來創建一個字符流。
下面是創建 BufferedReader 的基本語法:
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
BufferedReader 對象創建后,我們便可以使用 read() 方法從控制台讀取一個字符,或者用 readLine() 方法讀取一個字符串。
從控制台讀取多字符輸入
從 BufferedReader 對象讀取一個字符要使用 read() 方法,它的語法如下:
int read( ) throws IOException
每次調用 read() 方法,它從輸入流讀取一個字符並把該字符作為整數值返回。 當流結束的時候返回 -1。該方法拋出 IOException。
從控制台讀取字符串
從標准輸入讀取一個字符串需要使用 BufferedReader 的 readLine() 方法。
它的一般格式是:
String readLine( ) throws IOException
JDK 5 后的版本我們也可以使用 Java Scanner 類來獲取控制台的輸入。
控制台輸出
在此前已經介紹過,控制台的輸出由 print( ) 和 println() 完成。這些方法都由類 PrintStream 定義,System.out 是該類對象的一個引用。
PrintStream 繼承了 OutputStream類,並且實現了方法 write()。這樣,write() 也可以用來往控制台寫操作。
PrintStream 定義 write() 的最簡單格式如下所示:
void write(int byteval)
該方法將 byteval 的低八位字節寫到流中。
注意:write() 方法不經常使用,因為 print() 和 println() 方法用起來更為方便。
讀寫文件
如前所述,一個流被定義為一個數據序列。輸入流用於從源讀取數據,輸出流用於向目標寫數據。
FileInputStream
該流用於從文件讀取數據,它的對象可以用關鍵字 new 來創建。
有多種構造方法可用來創建對象。
可以使用字符串類型的文件名來創建一個輸入流對象來讀取文件:
InputStream f = new FileInputStream("C:/java/hello");
也可以使用一個文件對象來創建一個輸入流對象來讀取文件。我們首先得使用 File() 方法來創建一個文件對象:
File f = new File("C:/java/hello");InputStream out = new FileInputStream(f);
FileOutputStream
該類用來創建一個文件並向文件中寫數據。
如果該流在打開文件進行輸出前,目標文件不存在,那么該流會創建該文件。
有兩個構造方法可以用來創建 FileOutputStream 對象。
使用字符串類型的文件名來創建一個輸出流對象:
OutputStream f = new FileOutputStream("C:/java/hello")
也可以使用一個文件對象來創建一個輸出流來寫文件。我們首先得使用File()方法來創建一個文件對象:
File f = new File("C:/java/hello"); OutputStream f = new FileOutputStream(f);
文件和I/O
還有一些關於文件和I/O的類,我們也需要知道:
Java中的目錄
創建目錄:
File類中有兩個方法可以用來創建文件夾:
l mkdir( )方法創建一個文件夾,成功則返回true,失敗則返回false。失敗表明File對象指定的路徑已經存在,或者由於整個路徑還不存在,該文件夾不能被創建。
l mkdirs()方法創建一個文件夾和它的所有父文件夾。
注意:linux文件路徑分隔符為 / ,windows的文件路徑分隔符為 \ 。 Java 在 UNIX 和 Windows 自動按約定分辨文件路徑分隔符。如果你在 Windows 版本的 Java 中使用分隔符 (/) ,路徑依然能夠被正確解析。
讀取目錄
一個目錄其實就是一個 File 對象,它包含其他文件和文件夾。
如果創建一個 File 對象並且它是一個目錄,那么調用 isDirectory() 方法會返回 true。
可以通過調用該對象上的 list() 方法,來提取它包含的文件和文件夾的列表。
刪除目錄或文件
刪除文件可以使用 java.io.File.delete() 方法。
以下代碼會刪除目錄 /tmp/java/,需要注意的是當刪除某一目錄時,必須保證該目錄下沒有其他文件才能正確刪除,否則將刪除失敗。
Java Scanner 類
java.util.Scanner 是 Java5 的新特征,我們可以通過 Scanner 類來獲取用戶的輸入。
下面是創建 Scanner 對象的基本語法:
Scanner s = new Scanner(System.in);
接下來我們演示一個最簡單的數據輸入,並通過 Scanner 類的 next() 與 nextLine() 方法獲取輸入的字符串,在讀取前我們一般需要 使用 hasNext 與 hasNextLine 判斷是否還有輸入的數據
next() 與 nextLine() 區別
next():
l 1、一定要讀取到有效字符后才可以結束輸入。
l 2、對輸入有效字符之前遇到的空白,next() 方法會自動將其去掉。
l 3、只有輸入有效字符后才將其后面輸入的空白作為分隔符或者結束符。
l next() 不能得到帶有空格的字符串。
nextLine():
l 1、以Enter為結束符,也就是說 nextLine()方法返回的是輸入回車之前的所有字符。
l 2、可以獲得空白。
Java 異常處理
要理解Java異常處理是如何工作的,你需要掌握以下三種類型的異常:
l 檢查性異常:最具代表的檢查性異常是用戶錯誤或問題引起的異常,這是程序員無法預見的。例如要打開一個不存在文件時,一個異常就發生了,這些異常在編譯時不能被簡單地忽略。
l 運行時異常: 運行時異常是可能被程序員避免的異常。與檢查性異常相反,運行時異常可以在編譯時被忽略。
l 錯誤: 錯誤不是異常,而是脫離程序員控制的問題。錯誤在代碼中通常被忽略。例如,當棧溢出時,一個錯誤就發生了,它們在編譯也檢查不到的。
Exception 類的層次
所有的異常類是從 java.lang.Exception 類繼承的子類。
Exception 類是 Throwable 類的子類。除了Exception類外,Throwable還有一個子類Error 。
Java 程序通常不捕獲錯誤。錯誤一般發生在嚴重故障時,它們在Java程序處理的范疇之外。
Error 用來指示運行時環境發生的錯誤。
例如,JVM 內存溢出。一般地,程序不會從錯誤中恢復。
異常類有兩個主要的子類:IOException 類和 RuntimeException 類。
在 Java 內置類中(接下來會說明),有大部分常用檢查性和非檢查性異常。
Java 內置異常類
Java 語言定義了一些異常類在 java.lang 標准包中。
標准運行時異常類的子類是最常見的異常類。由於 java.lang 包是默認加載到所有的 Java 程序的,所以大部分從運行時異常類繼承而來的異常都可以直接使用。
Java 根據各個類庫也定義了一些其他的異常,下面的表中列出了 Java 的非檢查性異常。
異常方法
下面的列表是 Throwable 類的主要方法:
序號 |
方法及說明 |
1 |
public String getMessage() 返回關於發生的異常的詳細信息。這個消息在Throwable 類的構造函數中初始化了。 |
2 |
public Throwable getCause() 返回一個Throwable 對象代表異常原因。 |
3 |
public String toString() 使用getMessage()的結果返回類的串級名字。 |
4 |
public void printStackTrace() 打印toString()結果和棧層次到System.err,即錯誤輸出流。 |
5 |
public StackTraceElement [] getStackTrace() 返回一個包含堆棧層次的數組。下標為0的元素代表棧頂,最后一個元素代表方法調用堆棧的棧底。 |
6 |
public Throwable fillInStackTrace() 用當前的調用棧層次填充Throwable 對象棧層次,添加到棧層次任何先前信息中。 |
注意下面事項:
l catch 不能獨立於 try 存在。
l 在 try/catch 后面添加 finally 塊並非強制性要求的。
l try 代碼后不能既沒 catch 塊也沒 finally 塊。
l try, catch, finally 塊之間不能添加任何代碼。
聲明自定義異常
在 Java 中你可以自定義異常。編寫自己的異常類時需要記住下面的幾點。
l 所有異常都必須是 Throwable 的子類。
l 如果希望寫一個檢查性異常類,則需要繼承 Exception 類。
l 如果你想寫一個運行時異常類,那么需要繼承 RuntimeException 類。
通用異常
在Java中定義了兩種類型的異常和錯誤。
l JVM(Java虛擬機) 異常:由 JVM 拋出的異常或錯誤。例如:NullPointerException 類,ArrayIndexOutOfBoundsException 類,ClassCastException 類。
l 程序級異常:由程序或者API程序拋出的異常。例如 IllegalArgumentException 類,IllegalStateException 類。
Java 繼承
繼承的特性
l 子類擁有父類非 private 的屬性、方法。
l 子類可以擁有自己的屬性和方法,即子類可以對父類進行擴展。
l 子類可以用自己的方式實現父類的方法。
l Java 的繼承是單繼承,但是可以多重繼承,單繼承就是一個子類只能繼承一個父類,多重繼承就是,例如 A 類繼承 B 類,B 類繼承 C 類,所以按照關系就是 C 類是 B 類的父類,B 類是 A 類的父類,這是 Java 繼承區別於 C++ 繼承的一個特性。
l 提高了類之間的耦合性(繼承的缺點,耦合度高就會造成代碼之間的聯系越緊密,代碼獨立性越差)。
inal關鍵字
final 關鍵字聲明類可以把類定義為不能繼承的,即最終類;或者用於修飾方法,該方法不能被子類重寫:
l 聲明類:
final class 類名 {//類體}
l 聲明方法:
修飾符(public/private/default/protected) final 返回值類型 方法名(){//方法體}
注:實例變量也可以被定義為 final,被定義為 final 的變量不能被修改。被聲明為 final 類的方法自動地聲明為 final,但是實例變量並不是 final
構造器(構造方法)
子類是不繼承父類的構造器(構造方法或者構造函數)的,它只是調用(隱式或顯式)。如果父類的構造器帶有參數,則必須在子類的構造器中顯式地通過 super 關鍵字調用父類的構造器並配以適當的參數列表。
如果父類構造器沒有參數,則在子類的構造器中不需要使用 super 關鍵字調用父類構造器,系統會自動調用父類的無參構造器。
Java 重寫(Override)與重載(Overload)
重寫(Override)
重寫是子類對父類的允許訪問的方法的實現過程進行重新編寫, 返回值和形參都不能改變。即外殼不變,核心重寫!
重寫的好處在於子類可以根據需要,定義特定於自己的行為。 也就是說子類能夠根據需要實現父類的方法。
重寫方法不能拋出新的檢查異常或者比被重寫方法申明更加寬泛的異常。例如: 父類的一個方法申明了一個檢查異常 IOException,但是在重寫這個方法的時候不能拋出 Exception 異常,因為 Exception 是 IOException 的父類,只能拋出 IOException 的子類異常。
class Animal{ public void move(){ System.out.println("動物可以移動"); } } class Dog extends Animal{ public void move(){ System.out.println("狗可以跑和走"); } public void bark(){ System.out.println("狗可以吠叫"); } } public class TestDog{ public static void main(String args[]){ Animal a = new Animal(); // Animal 對象 Animal b = new Dog(); // Dog 對象 a.move();// 執行 Animal 類的方法 b.move();//執行 Dog 類的方法 b.bark();//報錯 } }
以上實例編譯運行結果如下:
TestDog.java:30: cannot find symbol symbol : method bark() location: class Animal b.bark();
方法的重寫規則
l 參數列表必須完全與被重寫方法的相同;
l 返回類型必須完全與被重寫方法的返回類型相同;
l 訪問權限不能比父類中被重寫的方法的訪問權限更低。例如:如果父類的一個方法被聲明為public,那么在子類中重寫該方法就不能聲明為protected。
l 父類的成員方法只能被它的子類重寫。
l 聲明為final的方法不能被重寫。
l 聲明為static的方法不能被重寫,但是能夠被再次聲明。
l 子類和父類在同一個包中,那么子類可以重寫父類所有方法,除了聲明為private和final的方法。
l 子類和父類不在同一個包中,那么子類只能夠重寫父類的聲明為public和protected的非final方法。
l 重寫的方法能夠拋出任何非強制異常,無論被重寫的方法是否拋出異常。但是,重寫的方法不能拋出新的強制性異常,或者比被重寫方法聲明的更廣泛的強制性異常,反之則可以。
l 構造方法不能被重寫。
l 如果不能繼承一個方法,則不能重寫這個方法。
重載(Overload)
重載(overloading) 是在一個類里面,方法名字相同,而參數不同。返回類型可以相同也可以不同。
每個重載的方法(或者構造函數)都必須有一個獨一無二的參數類型列表。
最常用的地方就是構造器的重載。
重載規則:
l 被重載的方法必須改變參數列表(參數個數或類型不一樣);
l 被重載的方法可以改變返回類型;
l 被重載的方法可以改變訪問修飾符;
l 被重載的方法可以聲明新的或更廣的檢查異常;
l 方法能夠在同一個類中或者在一個子類中被重載。
l 無法以返回值類型作為重載函數的區分標准。
重寫和重寫的區別
方法的重寫(Overriding)和重載(Overloading)是java多態性的不同表現,重寫是父類與子類之間多態性的一種表現,重載可以理解成多態的具體表現形式。
l (1)方法重載是一個類中定義了多個方法名相同,而他們的參數的數量不同或數量相同而類型和次序不同,則稱為方法的重載(Overloading)。
l (2)方法重寫是在子類存在方法與父類的方法的名字相同,而且參數的個數與類型一樣,返回值也一樣的方法,就稱為重寫(Overriding)。
l (3)方法重載是一個類的多態性表現,而方法重寫是子類與父類的一種多態性表現。
Java 多態
多態是同一個行為具有多個不同表現形式或形態的能力。
多態就是同一個接口,使用不同的實例而執行不同操作
多態性是對象多種表現形式的體現。
現實中,比如我們按下 F1 鍵這個動作:
l 如果當前在 Flash 界面下彈出的就是 AS 3 的幫助文檔;
l 如果當前在 Word 下彈出的就是 Word 幫助;
l 在 Windows 下彈出的就是 Windows 幫助和支持。
同一個事件發生在不同的對象上會產生不同的結果。
多態存在的三個必要條件
l 繼承
l 重寫
l 父類引用指向子類對象
虛方法
我們將介紹在Java中,當設計類時,被重寫的方法的行為怎樣影響多態性。
我們已經討論了方法的重寫,也就是子類能夠重寫父類的方法。
當子類對象調用重寫的方法時,調用的是子類的方法,而不是父類中被重寫的方法。
要想調用父類中被重寫的方法,則必須使用關鍵字super。
public class Employee{}public class Salary extends Employee{}Salary s = new Salary("員工 A", "北京", 3, 3600.00);Employee e = new Salary("員工 B", "上海", 2, 2400.00);s.mailCheck(); e.mailCheck(); //運行時調用Salary 類中的 mailCheck() 方法。
在編譯的時候,編譯器使用 Employee 類中的 mailCheck() 方法驗證該語句, 但是在運行的時候,Java虛擬機(JVM)調用的是 Salary 類中的 mailCheck() 方法。
Java中所有的方法都能以這種方式表現,因此,重寫的方法能在運行時調用,不管編譯的時候源代碼中引用變量是什么數據類型。
Java虛方法你可以理解為java里所有被overriding的方法都是virtual的,所有重寫的方法都是override的。
虛方法就是java類在繼承中,在上轉型中,java類對象實際調用的方法是子類重寫的方法;也就是編譯器和jvm調用的不是同一個類的方法;
多態的實現方式
方式一:重寫:
這個內容已經在上一章節詳細講過,就不再闡述,詳細可訪問:Java 重寫(Override)與重載(Overload)。
方式二:接口
l 1. 生活中的接口最具代表性的就是插座,例如一個三接頭的插頭都能接在三孔插座中,因為這個是每個國家都有各自規定的接口規則,有可能到國外就不行,那是因為國外自己定義的接口類型。
l 2. java中的接口類似於生活中的接口,就是一些方法特征的集合,但沒有方法的實現。具體可以看 java接口 這一章節的內容。
方式三:抽象類和抽象方法
Java 抽象類
在面向對象的概念中,所有的對象都是通過類來描繪的,但是反過來,並不是所有的類都是用來描繪對象的,如果一個類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類就是抽象類。
抽象類除了不能實例化對象之外,類的其它功能依然存在,成員變量、成員方法和構造方法的訪問方式和普通類一樣。
由於抽象類不能實例化對象,所以抽象類必須被繼承,才能被使用。也是因為這個原因,通常在設計階段決定要不要設計抽象類。
父類包含了子類集合的常見的方法,但是由於父類本身是抽象的,所以不能使用這些方法。
在Java中抽象類表示的是一種繼承關系,一個類只能繼承一個抽象類,而一個類卻可以實現多個接口。
抽象方法
如果你想設計這樣一個類,該類包含一個特別的成員方法,該方法的具體實現由它的子類確定,那么你可以在父類中聲明該方法為抽象方法。
Abstract 關鍵字同樣可以用來聲明抽象方法,抽象方法只包含一個方法名,而沒有方法體。
抽象方法沒有定義,方法名后面直接跟一個分號,而不是花括號。
public abstract double computePay();
聲明抽象方法會造成以下兩個結果:
l 如果一個類包含抽象方法,那么該類必須是抽象類。
l 任何子類必須重寫父類的抽象方法,或者聲明自身為抽象類。
繼承抽象方法的子類必須重寫該方法。否則,該子類也必須聲明為抽象類。最終,必須有子類實現該抽象方法,否則,從最初的父類到最終的子類都不能用來實例化對象。
抽象類總結規定
l 1. 抽象類不能被實例化(初學者很容易犯的錯),如果被實例化,就會報錯,編譯無法通過。只有抽象類的非抽象子類可以創建對象。
l 2. 抽象類中不一定包含抽象方法,但是有抽象方法的類必定是抽象類。
l 3. 抽象類中的抽象方法只是聲明,不包含方法體,就是不給出方法的具體實現也就是方法的具體功能。
l 4. 構造方法,類方法(用 static 修飾的方法)不能聲明為抽象方法。
l 5. 抽象類的子類必須給出抽象類中的抽象方法的具體實現,除非該子類也是抽象類。
Java 封裝
在面向對象程式設計方法中,封裝(英語:Encapsulation)是指一種將抽象性函式接口的實現細節部份包裝、隱藏起來的方法。
封裝可以被認為是一個保護屏障,防止該類的代碼和數據被外部類定義的代碼隨機訪問。
要訪問該類的代碼和數據,必須通過嚴格的接口控制。
封裝最主要的功能在於我們能修改自己的實現代碼,而不用修改那些調用我們代碼的程序片段。
適當的封裝可以讓程式碼更容易理解與維護,也加強了程式碼的安全性。
封裝的優點
l 1. 良好的封裝能夠減少耦合。
l 2. 類內部的結構可以自由修改。
l 3. 可以對成員變量進行更精確的控制。
l 4. 隱藏信息,實現細節。
實現Java封裝的步驟
1. 修改屬性的可見性來限制對屬性的訪問(一般限制為private)
2. 對每個值屬性提供對外的公共方法訪問,也就是創建一對賦取值方法,用於對私有屬性的訪問(getter和setter方法)
Java 接口
接口(英文:Interface),在JAVA編程語言中是一個抽象類型,是抽象方法的集合,接口通常以interface來聲明。一個類通過繼承接口的方式,從而來繼承接口的抽象方法。
接口並不是類,編寫接口的方式和類很相似,但是它們屬於不同的概念。類描述對象的屬性和方法。接口則包含類要實現的方法。
除非實現接口的類是抽象類,否則該類要定義接口中的所有方法。
接口無法被實例化,但是可以被實現。一個實現接口的類,必須實現接口內所描述的所有方法,否則就必須聲明為抽象類。另外,在 Java 中,接口類型可用來聲明一個變量,他們可以成為一個空指針,或是被綁定在一個以此接口實現的對象。
接口與類相似點
l 一個接口可以有多個方法。
l 接口文件保存在 .java 結尾的文件中,文件名使用接口名。
l 接口的字節碼文件保存在 .class 結尾的文件中。
l 接口相應的字節碼文件必須在與包名稱相匹配的目錄結構中。
接口與類的區別
l 接口不能用於實例化對象。
l 接口沒有構造方法。
l 接口中所有的方法必須是抽象方法。
l 接口不能包含成員變量,除了 static 和 final 變量。
l 接口不是被類繼承了,而是要被類實現。
l 接口支持多繼承。
接口特性
l 接口中每一個方法也是隱式抽象的,接口中的方法會被隱式的指定為 public abstract(只能是 public abstract,其他修飾符都會報錯)。
l 接口中可以含有變量,但是接口中的變量會被隱式的指定為 public static final 變量(並且只能是 public,用 private 修飾會報編譯錯誤)。
l 接口中的方法是不能在接口中實現的,只能由實現接口的類來實現接口中的方法。
抽象類和接口的區別
l 1. 抽象類中的方法可以有方法體,就是能實現方法的具體功能,但是接口中的方法不行。
l 2. 抽象類中的成員變量可以是各種類型的,而接口中的成員變量只能是 public static final 類型的。
l 3. 接口中不能含有靜態代碼塊以及靜態方法(用 static 修飾的方法),而抽象類是可以有靜態代碼塊和靜態方法。
l 4. 一個類只能繼承一個抽象類,而一個類卻可以實現多個接口。
重寫接口中聲明的方法時,需要注意以下規則:
l 類在實現接口的方法時,不能拋出強制性異常,只能在接口中,或者繼承接口的抽象類中拋出該強制性異常。
l 類在重寫方法時要保持一致的方法名,並且應該保持相同或者相兼容的返回值類型。
l 如果實現接口的類是抽象類,那么就沒必要實現該接口的方法。
在實現接口的時候,也要注意一些規則:
l 一個類可以同時實現多個接口。
l 一個類只能繼承一個類,但是能實現多個接口。
l 一個接口能繼承另一個接口,這和類之間的繼承比較相似。
接口的多繼承
在Java中,類的多繼承是不合法,但接口允許多繼承。
在接口的多繼承中extends關鍵字只需要使用一次,在其后跟着繼承接口。 如下所示:
public interface Hockey extends Sports, Event
以上的程序片段是合法定義的子接口,與類不同的是,接口允許多繼承,而 Sports及 Event 可能定義或是繼承相同的方法
標記接口
最常用的繼承接口是沒有包含任何方法的接口。
標記接口是沒有任何方法和屬性的接口.它僅僅表明它的類屬於一個特定的類型,供其他代碼來測試允許做一些事情。
標記接口作用:簡單形象的說就是給某個對象打個標(蓋個戳),使對象擁有某個或某些特權。
沒有任何方法的接口被稱為標記接口。標記接口主要用於以下兩種目的:
l 建立一個公共的父接口:
正如EventListener接口,這是由幾十個其他接口擴展的Java API,你可以使用一個標記接口來建立一組接口的父接口。例如:當一個接口繼承了EventListener接口,Java虛擬機(JVM)就知道該接口將要被用於一個事件的代理方案。
l 向一個類添加數據類型:
這種情況是標記接口最初的目的,實現標記接口的類不需要定義任何接口方法(因為標記接口根本就沒有方法),但是該類通過多態性變成一個接口類型。
Java 包(package)
為了更好地組織類,Java 提供了包機制,用於區別類名的命名空間。
包的作用
l 1、把功能相似或相關的類或接口組織在同一個包中,方便類的查找和使用。
l 2、如同文件夾一樣,包也采用了樹形目錄的存儲方式。同一個包中的類名字是不同的,不同的包中的類的名字是可以相同的,當同時調用兩個不同包中相同類名的類時,應該加上包名加以區別。因此,包可以避免名字沖突。
l 3、包也限定了訪問權限,擁有包訪問權限的類才能訪問某個包中的類。
如果在一個包中,一個類想要使用本包中的另一個類,那么該包名可以省略。
注意:類文件中可以包含任意數量的 import 聲明。import 聲明必須在包聲明之后,類聲明之前。
package 的目錄結構
類放在包中會有兩種主要的結果:
l 包名成為類名的一部分,正如我們前面討論的一樣。
l 包名必須與相應的字節碼所在的目錄結構相吻合。
通常,一個公司使用它互聯網域名的顛倒形式來作為它的包名.例如:互聯網域名是 runoob.com,所有的包名都以 com.runoob 開頭。包名中的每一個部分對應一個子目錄。
Java 數據結構
Java工具包提供了強大的數據結構。在Java中的數據結構主要包括以下幾種接口和類:
l 枚舉(Enumeration)
l 位集合(BitSet)
l 向量(Vector)
l 棧(Stack)
l 字典(Dictionary)
l 哈希表(Hashtable)
l 屬性(Properties)
序號 |
類描述 |
1 |
Vector 該類和ArrayList非常相似,但是該類是同步的,可以用在多線程的情況,該類允許設置默認的增長長度,默認擴容方式為原來的2倍。 |
2 |
Stack 棧是Vector的一個子類,它實現了一個標准的后進先出的棧。 |
3 |
Dictionary Dictionary 類是一個抽象類,用來存儲鍵/值對,作用和Map類相似。 |
4 |
Hashtable Hashtable 是 Dictionary(字典) 類的子類,位於 java.util 包中。 |
5 |
Properties Properties 繼承於 Hashtable,表示一個持久的屬性集,屬性列表中每個鍵及其對應值都是一個字符串。 |
6 |
BitSet 一個Bitset類創建一種特殊類型的數組來保存位值。BitSet中數組大小會隨需要增加。 |
枚舉(Enumeration)
枚舉(Enumeration)接口雖然它本身不屬於數據結構,但它在其他數據結構的范疇里應用很廣。 枚舉(The Enumeration)接口定義了一種從數據結構中取回連續元素的方式。
例如,枚舉定義了一個叫nextElement 的方法,該方法用來得到一個包含多元素的數據結構的下一個元素。
關於枚舉接口的更多信息,請參見枚舉(Enumeration)。
位集合(BitSet)
位集合類實現了一組可以單獨設置和清除的位或標志。
該類在處理一組布爾值的時候非常有用,你只需要給每個值賦值一"位",然后對位進行適當的設置或清除,就可以對布爾值進行操作了。
關於該類的更多信息,請參見位集合(BitSet)。
向量(Vector)
向量(Vector)類和傳統數組非常相似,但是Vector的大小能根據需要動態的變化。
和數組一樣,Vector對象的元素也能通過索引訪問。
使用Vector類最主要的好處就是在創建對象的時候不必給對象指定大小,它的大小會根據需要動態的變化。
關於該類的更多信息,請參見向量(Vector)
棧(Stack)
棧(Stack)實現了一個后進先出(LIFO)的數據結構。
你可以把棧理解為對象的垂直分布的棧,當你添加一個新元素時,就將新元素放在其他元素的頂部。
當你從棧中取元素的時候,就從棧頂取一個元素。換句話說,最后進棧的元素最先被取出。
關於該類的更多信息,請參見棧(Stack)。
堆棧除了包括由Vector定義的所有方法,也定義了自己的一些方法。
序號 |
方法描述 |
1 |
boolean empty() 測試堆棧是否為空。 |
2 |
Object peek( ) 查看堆棧頂部的對象,但不從堆棧中移除它。 |
3 |
Object pop( ) 移除堆棧頂部的對象,並作為此函數的值返回該對象。 |
4 |
Object push(Object element) 把項壓入堆棧頂部。 |
5 |
int search(Object element) 返回對象在堆棧中的位置,以 1 為基數。 |
字典(Dictionary)
字典(Dictionary) 類是一個抽象類,它定義了鍵映射到值的數據結構。
當你想要通過特定的鍵而不是整數索引來訪問數據的時候,這時候應該使用Dictionary。
由於Dictionary類是抽象類,所以它只提供了鍵映射到值的數據結構,而沒有提供特定的實現。
關於該類的更多信息,請參見字典( Dictionary)。
Dictionary類已經過時了。在實際開發中,你可以實現Map接口來獲取鍵/值的存儲功能。
哈希表(Hashtable)
Hashtable類提供了一種在用戶定義鍵結構的基礎上來組織數據的手段。
例如,在地址列表的哈希表中,你可以根據郵政編碼作為鍵來存儲和排序數據,而不是通過人名。
哈希表鍵的具體含義完全取決於哈希表的使用情景和它包含的數據。
關於該類的更多信息,請參見哈希表(HashTable)。
Hashtable是原始的java.util的一部分, 是一個Dictionary具體的實現 。
然而,Java 2 重構的Hashtable實現了Map接口,因此,Hashtable現在集成到了集合框架中。它和HashMap類很相似,但是它支持同步。
像HashMap一樣,Hashtable在哈希表中存儲鍵/值對。當使用一個哈希表,要指定用作鍵的對象,以及要鏈接到該鍵的值。
屬性(Properties)
Properties 繼承於 Hashtable.Properties 類表示了一個持久的屬性集.屬性列表中每個鍵及其對應值都是一個字符串。
Properties 類被許多Java類使用。例如,在獲取環境變量時它就作為System.getProperties()方法的返回值。
關於該類的更多信息,請參見屬性(Properties)。
迭代器 iterator 用法
Java 中的 Iterator 功能比較簡單,並且只能單向移動:
l (1) 使用方法 iterator() 要求容器返回一個 Iterator。第一次調用 Iterator 的 next() 方法時,它返回序列的第一個元素。注意:iterator() 方法是 java.lang.Iterable 接口,被 Collection 繼承。
l (2) 使用 next() 獲得序列中的下一個元素。
l (3) 使用 hasNext() 檢查序列中是否還有元素。
l (4) 使用 remove() 將迭代器新返回的元素刪除。
Java 集合框架
從上面的集合框架圖可以看到,Java 集合框架主要包括兩種類型的容器,一種是集合(Collection),存儲一個元素集合,另一種是圖(Map),存儲鍵/值對映射。Collection 接口又有 3 種子類型,List、Set 和 Queue,再下面是一些抽象類,最后是具體實現類,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等等。
集合框架是一個用來代表和操縱集合的統一架構。所有的集合框架都包含如下內容:
l 接口:是代表集合的抽象數據類型。例如 Collection、List、Set、Map 等。之所以定義多個接口,是為了以不同的方式操作集合對象
l 實現(類):是集合接口的具體實現。從本質上講,它們是可重復使用的數據結構,例如:ArrayList、LinkedList、HashSet、HashMap。
l 算法:是實現集合接口的對象里的方法執行的一些有用的計算,例如:搜索和排序。這些算法被稱為多態,那是因為相同的方法可以在相似的接口上有着不同的實現。
Set和List的區別
l 1. Set 接口實例存儲的是無序的,不重復的數據。List 接口實例存儲的是有序的,可以重復的元素。
l 2. Set檢索效率低下,刪除和插入效率高,插入和刪除不會引起元素位置改變 <實現類有HashSet,TreeSet>。
l 3. List和數組類似,可以動態增長,根據實際存儲的數據的長度自動增長List的長度。查找元素效率高,插入刪除效率低,因為會引起其他元素位置改變 <實現類有ArrayList,LinkedList,Vector> 。
集合算法
集合框架定義了幾種算法,可用於集合和映射。這些算法被定義為集合類的靜態方法。
在嘗試比較不兼容的類型時,一些方法能夠拋出 ClassCastException異常。當試圖修改一個不可修改的集合時,拋出UnsupportedOperationException異常。
集合定義三個靜態的變量:EMPTY_SET,EMPTY_LIST,EMPTY_MAP的。這些變量都不可改變。
如何使用迭代器
通常情況下,你會希望遍歷一個集合中的元素。例如,顯示集合中的每個元素。
一般遍歷數組都是采用for循環或者增強for,這兩個方法也可以用在集合框架,但是還有一種方法是采用迭代器遍歷集合框架,它是一個對象,實現了Iterator 接口或ListIterator接口。
迭代器,使你能夠通過循環來得到或刪除集合的元素。ListIterator 繼承了Iterator,以允許雙向遍歷列表和修改元素。
遍歷 Map
import java.util.*;public class Test{ public static void main(String[] args) { Map<String, String> map = new HashMap<String, String>(); map.put("1", "value1"); map.put("2", "value2"); map.put("3", "value3"); //第一種:普遍使用,二次取值 System.out.println("通過Map.keySet遍歷key和value:"); for (String key : map.keySet()) { System.out.println("key= "+ key + " and value= " + map.get(key)); } //第二種 System.out.println("通過Map.entrySet使用iterator遍歷key和value:"); Iterator<Map.Entry<String, String>> it = map.entrySet().iterator(); while (it.hasNext()) { Map.Entry<String, String> entry = it.next(); System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); } //第三種:推薦,尤其是容量大時 System.out.println("通過Map.entrySet遍歷key和value"); for (Map.Entry<String, String> entry : map.entrySet()) { System.out.println("key= " + entry.getKey() + " and value= " + entry.getValue()); } //第四種 System.out.println("通過Map.values()遍歷所有的value,但不能遍歷key"); for (String v : map.values()) { System.out.println("value= " + v); } }}
總結
Java集合框架為程序員提供了預先包裝的數據結構和算法來操縱他們。
集合是一個對象,可容納其他對象的引用。集合接口聲明對每一種類型的集合可以執行的操作。
集合框架的類和接口均在java.util包中。
任何對象加入集合類后,自動轉變為Object類型,所以在取出的時候,需要進行強制類型轉換。
Java 泛型
Java 泛型(generics)是 JDK 5 中引入的一個新特性, 泛型提供了編譯時類型安全檢測機制,該機制允許程序員在編譯時檢測到非法的類型。
泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。
假定我們有這樣一個需求:寫一個排序方法,能夠對整型數組、字符串數組甚至其他任何類型的數組進行排序,該如何實現?
答案是可以使用 Java 泛型。
使用 Java 泛型的概念,我們可以寫一個泛型方法來對一個對象數組排序。然后,調用該泛型方法來對整型數組、浮點數數組、字符串數組等進行排序。
泛型方法
你可以寫一個泛型方法,該方法在調用時可以接收不同類型的參數。根據傳遞給泛型方法的參數類型,編譯器適當地處理每一個方法調用。
下面是定義泛型方法的規則:
l 所有泛型方法聲明都有一個類型參數聲明部分(由尖括號分隔),該類型參數聲明部分在方法返回類型之前(在下面例子中的<E>)。
l 每一個類型參數聲明部分包含一個或多個類型參數,參數間用逗號隔開。一個泛型參數,也被稱為一個類型變量,是用於指定一個泛型類型名稱的標識符。
l 類型參數能被用來聲明返回值類型,並且能作為泛型方法得到的實際參數類型的占位符。
l 泛型方法體的聲明和其他方法一樣。注意類型參數只能代表引用型類型,不能是原始類型(像int,double,char的等)。
public static < E > void printArray( E[] inputArray ){} //extends"在一般意義上的意思是"extends"(類)或者"implements"(接口) public static <T extends Comparable<T>> T maximum(T x, T y, T z) {}
泛型類
泛型類的聲明和非泛型類的聲明類似,除了在類名后面添加了類型參數聲明部分。
和泛型方法一樣,泛型類的類型參數聲明部分也包含一個或多個類型參數,參數間用逗號隔開。一個泛型參數,也被稱為一個類型變量,是用於指定一個泛型類型名稱的標識符。因為他們接受一個或多個參數,這些類被稱為參數化的類或參數化的類型。
public class Box<T> {……}
類型通配符
1、類型通配符一般是使用?代替具體的類型參數。例如 List<?> 在邏輯上是List<String>,List<Integer> 等所有List<具體類型實參>的父類。
List<String> name = new ArrayList<String>(); List<Integer> age = new ArrayList<Integer>(); List<Number> number = new ArrayList<Number>(); public static void getData(List<?> data) {……}
解析: 因為getData()方法的參數是List類型的,所以name,age,number都可以作為這個方法的實參,這就是通配符的作用
2、類型通配符上限通過形如 List<? extends Number>來定義,如此定義就是通配符泛型值接受Number及其下層子類類型。
List<String> name = new ArrayList<String>(); List<Integer> age = new ArrayList<Integer>(); List<Number> number = new ArrayList<Number>(); //getUperNumber(name);//1 getUperNumber(age);//2 getUperNumber(number);//3 public static void getData(List<?> data) {……} public static void getUperNumber(List<? extends Number> data) {……}
解析: 在(//1)處會出現錯誤,因為getUperNumber()方法中的參數已經限定了參數泛型上限為Number,所以泛型為String是不在這個范圍之內,所以會報錯
3、類型通配符下限通過形如 List<? super Number>來定義,表示類型只能接受Number及其三層父類類型,如Objec類型的實例。
Java 序列化
Java 提供了一種對象序列化的機制,該機制中,一個對象可以被表示為一個字節序列,該字節序列包括該對象的數據、有關對象的類型的信息和存儲在對象中數據的類型。
將序列化對象寫入文件之后,可以從文件中讀取出來,並且對它進行反序列化,也就是說,對象的類型信息、對象的數據,還有對象中的數據類型可以用來在內存中新建對象。
整個過程都是 Java 虛擬機(JVM)獨立的,也就是說,在一個平台上序列化的對象可以在另一個完全不同的平台上反序列化該對象。
類 ObjectInputStream 和 ObjectOutputStream 是高層次的數據流,它們包含反序列化和序列化對象的方法。
ObjectOutputStream 類包含很多寫方法來寫各種數據類型,但是一個特別的方法例外:
public final void writeObject(Object x) throws IOException
上面的方法序列化一個對象,並將它發送到輸出流。相似的 ObjectInputStream 類包含如下反序列化一個對象的方法:
public final Object readObject() throws IOException, ClassNotFoundException
該方法從流中取出下一個對象,並將對象反序列化。它的返回值為Object,因此,你需要將它轉換成合適的數據類型。
請注意,一個類的對象要想序列化成功,必須滿足兩個條件:
- 該類必須實現 java.io.Serializable 對象。
- 該類的所有屬性必須是可序列化的。如果有一個屬性不是可序列化的,則該屬性必須注明是短暫的。
如果你想知道一個 Java 標准類是否是可序列化的,請查看該類的文檔。檢驗一個類的實例是否能序列化十分簡單, 只需要查看該類有沒有實現 java.io.Serializable接口。
序列化對象
ObjectOutputStream 類用來序列化一個對象,如下的 SerializeDemo 例子實例化了一個 Employee 對象,並將該對象序列化到一個文件中。
該程序執行后,就創建了一個名為 employee.ser 文件。該程序沒有任何輸出,但是你可以通過代碼研讀來理解程序的作用。
注意: 當序列化一個對象到文件時, 按照 Java 的標准約定是給文件一個 .ser 擴展名。
Employee e = new Employee(); e.name = "Reyan Ali"; e.address = "Phokka Kuan, Ambehta Peer"; e.SSN = 11122333; e.number = 101; try { FileOutputStream fileOut = new FileOutputStream("/tmp/employee.ser"); ObjectOutputStream out = new ObjectOutputStream(fileOut); out.writeObject(e); out.close(); fileOut.close(); System.out.printf("Serialized data is saved in /tmp/employee.ser"); }catch(IOException i) { i.printStackTrace(); }
反序列化對象
下面的 DeserializeDemo 程序實例了反序列化,/tmp/employee.ser 存儲了 Employee 對象。
Employee e = null; try { FileInputStream fileIn = new FileInputStream("/tmp/employee.ser"); ObjectInputStream in = new ObjectInputStream(fileIn); e = (Employee) in.readObject(); in.close(); fileIn.close(); }catch(IOException i) { i.printStackTrace(); return; }catch(ClassNotFoundException c) { System.out.println("Employee class not found"); c.printStackTrace(); return; }
這里要注意以下要點:
readObject() 方法中的 try/catch代碼塊嘗試捕獲 ClassNotFoundException 異常。對於 JVM 可以反序列化對象,它必須是能夠找到字節碼的類。如果JVM在反序列化對象的過程中找不到該類,則拋出一個 ClassNotFoundException 異常。
注意,readObject() 方法的返回值被轉化成 Employee 引用。
當對象被序列化時,屬性 SSN 的值為 111222333,但是因為該屬性是短暫的,該值沒有被發送到輸出流。所以反序列化后 Employee 對象的 SSN 屬性為 0。
public transient int SSN;
Java 網絡編程
java.net 包中提供了兩種常見的網絡協議的支持:
l TCP:TCP 是傳輸控制協議的縮寫,它保障了兩個應用程序之間的可靠通信。通常用於互聯網協議,被稱 TCP / IP。
l UDP:UDP 是用戶數據報協議的縮寫,一個無連接的協議。提供了應用程序之間要發送的數據的數據包。
Socket 編程
套接字使用TCP提供了兩台計算機之間的通信機制。 客戶端程序創建一個套接字,並嘗試連接服務器的套接字。
當連接建立時,服務器會創建一個 Socket 對象。客戶端和服務器現在可以通過對 Socket 對象的寫入和讀取來進行通信。
java.net.Socket 類代表一個套接字,並且 java.net.ServerSocket 類為服務器程序提供了一種來監聽客戶端,並與他們建立連接的機制。
以下步驟在兩台計算機之間使用套接字建立TCP連接時會出現:
l 服務器實例化一個 ServerSocket 對象,表示通過服務器上的端口通信。
l 服務器調用 ServerSocket 類的 accept() 方法,該方法將一直等待,直到客戶端連接到服務器上給定的端口。
l 服務器正在等待時,一個客戶端實例化一個 Socket 對象,指定服務器名稱和端口號來請求連接。
l Socket 類的構造函數試圖將客戶端連接到指定的服務器和端口號。如果通信被建立,則在客戶端創建一個 Socket 對象能夠與服務器進行通信。
l 在服務器端,accept() 方法返回服務器上一個新的 socket 引用,該 socket 連接到客戶端的 socket。
連接建立后,通過使用 I/O 流在進行通信,每一個socket都有一個輸出流和一個輸入流,客戶端的輸出流連接到服務器端的輸入流,而客戶端的輸入流連接到服務器端的輸出流。
TCP 是一個雙向的通信協議,因此數據可以通過兩個數據流在同一時間發送.以下是一些類提供的一套完整的有用的方法來實現 socket。
ServerSocket 類的方法
服務器應用程序通過使用 java.net.ServerSocket 類以獲取一個端口,並且偵聽客戶端請求。
創建非綁定服務器套接字。 如果 ServerSocket 構造方法沒有拋出異常,就意味着你的應用程序已經成功綁定到指定的端口,並且偵聽客戶端請求。
這里有一些 ServerSocket 類的常用方法:
序號 |
方法描述 |
1 |
public int getLocalPort() 返回此套接字在其上偵聽的端口。 |
2 |
public Socket accept() throws IOException 偵聽並接受到此套接字的連接。 |
3 |
public void setSoTimeout(int timeout) 通過指定超時值啟用/禁用 SO_TIMEOUT,以毫秒為單位。 |
4 |
public void bind(SocketAddress host, int backlog) 將 ServerSocket 綁定到特定地址(IP 地址和端口號)。 |
Socket 類的方法
java.net.Socket 類代表客戶端和服務器都用來互相溝通的套接字。客戶端要獲取一個 Socket 對象通過實例化 ,而 服務器獲得一個 Socket 對象則通過 accept() 方法的返回值。
當 Socket 構造方法返回,並沒有簡單的實例化了一個 Socket 對象,它實際上會嘗試連接到指定的服務器和端口。
下面列出了一些感興趣的方法,注意客戶端和服務器端都有一個 Socket 對象,所以無論客戶端還是服務端都能夠調用這些方法。
序號 |
方法描述 |
1 |
public void connect(SocketAddress host, int timeout) throws IOException 將此套接字連接到服務器,並指定一個超時值。 |
2 |
public InetAddress getInetAddress() 返回套接字連接的地址。 |
3 |
public int getPort() 返回此套接字連接到的遠程端口。 |
4 |
public int getLocalPort() 返回此套接字綁定到的本地端口。 |
5 |
public SocketAddress getRemoteSocketAddress() 返回此套接字連接的端點的地址,如果未連接則返回 null。 |
6 |
public InputStream getInputStream() throws IOException 返回此套接字的輸入流。 |
7 |
public OutputStream getOutputStream() throws IOException 返回此套接字的輸出流。 |
8 |
public void close() throws IOException 關閉此套接字。 |
InetAddress 類的方法
這個類表示互聯網協議(IP)地址。下面列出了 Socket 編程時比較有用的方法:
序號 |
方法描述 |
1 |
static InetAddress getByAddress(byte[] addr) 在給定原始 IP 地址的情況下,返回 InetAddress 對象。 |
2 |
static InetAddress getByAddress(String host, byte[] addr) 根據提供的主機名和 IP 地址創建 InetAddress。 |
3 |
static InetAddress getByName(String host) 在給定主機名的情況下確定主機的 IP 地址。 |
4 |
String getHostAddress() 返回 IP 地址字符串(以文本表現形式)。 |
5 |
String getHostName() 獲取此 IP 地址的主機名。 |
6 |
static InetAddress getLocalHost() 返回本地主機。 |
7 |
String toString() 將此 IP 地址轉換為 String。 |
Java 發送郵件
Java 多線程編程
Java 給多線程編程提供了內置的支持。 一條線程指的是進程中一個單一順序的控制流,一個進程中可以並發多個線程,每條線程並行執行不同的任務。
多線程是多任務的一種特別的形式,但多線程使用了更小的資源開銷。
這里定義和線程相關的另一個術語 - 進程:一個進程包括由操作系統分配的內存空間,包含一個或多個線程。一個線程不能獨立的存在,它必須是進程的一部分。一個進程一直運行,直到所有的非守護線程都結束運行后才能結束。
多線程能滿足程序員編寫高效率的程序來達到充分利用 CPU 的目的。
一個線程的生命周期
l 新建狀態:
使用 new 關鍵字和 Thread 類或其子類建立一個線程對象后,該線程對象就處於新建狀態。它保持這個狀態直到程序 start() 這個線程。
l 就緒狀態:
當線程對象調用了start()方法之后,該線程就進入就緒狀態。就緒狀態的線程處於就緒隊列中,要等待JVM里線程調度器的調度。
l 運行狀態:
如果就緒狀態的線程獲取 CPU 資源,就可以執行 run(),此時線程便處於運行狀態。處於運行狀態的線程最為復雜,它可以變為阻塞狀態、就緒狀態和死亡狀態。
l 阻塞狀態:
如果一個線程執行了sleep(睡眠)、suspend(掛起)等方法,失去所占用資源之后,該線程就從運行狀態進入阻塞狀態。在睡眠時間已到或獲得設備資源后可以重新進入就緒狀態。可以分為三種:
n 等待阻塞:運行狀態中的線程執行 wait() 方法,使線程進入到等待阻塞狀態。
n 同步阻塞:線程在獲取 synchronized 同步鎖失敗(因為同步鎖被其他線程占用)。
n 其他阻塞:通過調用線程的 sleep() 或 join() 發出了 I/O 請求時,線程就會進入到阻塞狀態。當sleep() 狀態超時,join() 等待線程終止或超時,或者 I/O 處理完畢,線程重新轉入就緒狀態。
l 死亡狀態:
一個運行狀態的線程完成任務或者其他終止條件發生時,該線程就切換到終止狀態。
線程的優先級
每一個 Java 線程都有一個優先級,這樣有助於操作系統確定線程的調度順序。
Java 線程的優先級是一個整數,其取值范圍是 1 (Thread.MIN_PRIORITY ) - 10 (Thread.MAX_PRIORITY )。
默認情況下,每一個線程都會分配一個優先級 NORM_PRIORITY(5)。
具有較高優先級的線程對程序更重要,並且應該在低優先級的線程之前分配處理器資源。但是,線程優先級不能保證線程執行的順序,而且非常依賴於平台。
創建一個線程
Java 提供了三種創建線程的方法:
l 通過實現 Runnable 接口;
l 通過繼承 Thread 類本身;
l 通過 Callable 和 Future 創建線程。
通過實現 Runnable 接口來創建線程
創建一個線程,最簡單的方法是創建一個實現 Runnable 接口的類。
為了實現 Runnable,一個類只需要執行一個方法調用 run(),聲明如下:
public void run()
你可以重寫該方法,重要的是理解的 run() 可以調用其他方法,使用其他類,並聲明變量,就像主線程一樣。
在創建一個實現 Runnable 接口的類之后,你可以在類中實例化一個線程對象。
Thread 定義了幾個構造方法,下面的這個是我們經常使用的:
Thread(Runnable threadOb,String threadName);
這里,threadOb 是一個實現 Runnable 接口的類的實例,並且 threadName 指定新線程的名字。
新線程創建之后,你調用它的 start() 方法它才會運行。
void start();
通過繼承Thread來創建線程
創建一個線程的第二種方法是創建一個新的類,該類繼承 Thread 類,然后創建一個該類的實例。
繼承類必須重寫 run() 方法,該方法是新線程的入口點。它也必須調用 start() 方法才能執行。
該方法盡管被列為一種多線程實現方式,但是本質上也是實現了 Runnable 接口的一個實例。
Thread 方法
下表列出了Thread類的一些重要方法:
序號 |
方法描述 |
1 |
public void start() 使該線程開始執行;Java 虛擬機調用該線程的 run 方法。 |
2 |
public void run() 如果該線程是使用獨立的 Runnable 運行對象構造的,則調用該 Runnable 對象的 run 方法;否則,該方法不執行任何操作並返回。 |
3 |
public final void setName(String name) 改變線程名稱,使之與參數 name 相同。 |
4 |
public final void setPriority(int priority) 更改線程的優先級。 |
5 |
public final void setDaemon(boolean on) 將該線程標記為守護線程或用戶線程。 |
6 |
public final void join(long millisec) 等待該線程終止的時間最長為 millis 毫秒。 |
7 |
public void interrupt() 中斷線程。 |
8 |
public final boolean isAlive() 測試線程是否處於活動狀態。 |
通過 Callable 和 Future 創建線程
l 1. 創建 Callable 接口的實現類,並實現 call() 方法,該 call() 方法將作為線程執行體,並且有返回值。
l 2. 創建 Callable 實現類的實例,使用 FutureTask 類來包裝 Callable 對象,該 FutureTask 對象封裝了該 Callable 對象的 call() 方法的返回值。
l 3. 使用 FutureTask 對象作為 Thread 對象的 target 創建並啟動新線程。
l 4. 調用 FutureTask 對象的 get() 方法來獲得子線程執行結束后的返回值。
創建線程的三種方式的對比
l 1. 采用實現 Runnable、Callable 接口的方式創建多線程時,線程類只是實現了 Runnable 接口或 Callable 接口,還可以繼承其他類。
l 2. 使用繼承 Thread 類的方式創建多線程時,編寫簡單,如果需要訪問當前線程,則無需使用 Thread.currentThread() 方法,直接使用 this 即可獲得當前線程。
線程的幾個主要概念
在多線程編程時,你需要了解以下幾個概念:
l 線程同步
l 線程間通信
l 線程死鎖
l 線程控制:掛起、停止和恢復
多線程的使用
有效利用多線程的關鍵是理解程序是並發執行而不是串行執行的。例如:程序中有兩個子系統需要並發執行,這時候就需要利用多線程編程。
通過對多線程的使用,可以編寫出非常高效的程序。不過請注意,如果你創建太多的線程,程序執行的效率實際上是降低了,而不是提升了。
請記住,上下文的切換開銷也很重要,如果你創建了太多的線程,CPU 花費在上下文的切換的時間將多於執行程序的時間!
Java Applet 基礎
Applet是采用Java編程語言編寫的小應用程序,該程序可以包含在 HTML(標准通用標記語言的一個應用)頁中,與在頁中包含圖像的方式大致相同。含有Applet的網頁的HTML文件代碼中部帶有<applet> 和</applet>這樣一對標記,當支持Java的網絡瀏覽器遇到這對標記時,就將下載相應的小應用程序代碼並在本地計算機上執行該Applet。
Applet 是一種 Java 程序。它一般運行在支持 Java 的 Web 瀏覽器內。因為它有完整的 Java API支持,所以Applet 是一個全功能的 Java 應用程序。
如下所示是獨立的 Java 應用程序和 applet 程序之間重要的不同:
l Java 中 Applet 類繼承了 java.applet.Applet 類。
l Applet 類沒有定義 main(),所以一個 Applet 程序不會調用 main() 方法。
l Applet 被設計為嵌入在一個 HTML 頁面。
l 當用戶瀏覽包含 Applet 的 HTML 頁面,Applet 的代碼就被下載到用戶的機器上。
l 要查看一個 Applet 需要 JVM。 JVM 可以是 Web 瀏覽器的一個插件,或一個獨立的運行時環境。
l 用戶機器上的 JVM 創建一個 Applet 類的實例,並調用 Applet 生命周期過程中的各種方法。
l Applet 有 Web 瀏覽器強制執行的嚴格的安全規則,Applet 的安全機制被稱為沙箱安全。
l Applet 需要的其他類可以用 Java 歸檔(JAR)文件的形式下載下來。
Applet的生命周期
Applet 類中的四個方法給我們提供了一個框架,你可以在該框架上開發小程序:
l init: 該方法的目的是為你的 Applet 提供所需的任何初始化。在 Applet 標記內的 param 標簽被處理后調用該方法。
l start: 瀏覽器調用 init 方法后,該方法被自動調用。每當用戶從其他頁面返回到包含 Applet 的頁面時,則調用該方法。
l stop: 當用戶從包含 Applet 的頁面移除的時候,該方法自動被調用。因此,可以在相同的 Applet 中反復調用該方法。
l destroy: 此方法僅當瀏覽器正常關閉時調用。因為 Applet 只有在 HTML 網頁上有效,所以你不應該在用戶離開包含 Applet 的頁面后遺漏任何資源。
l paint: 該方法在 start() 方法之后立即被調用,或者在 Applet 需要重繪在瀏覽器的時候調用。paint() 方法實際上繼承於 java.awt。
Applet 的調用
Applet 是一種 Java 程序。它一般運行在支持 Java 的 Web 瀏覽器內。因為它有完整的 Java API 支持,所以 Applet 是一個全功能的 Java 應用程序。
<applet> 標簽是在HTML文件中嵌入 Applet 的基礎。以下是一個調用"Hello World"applet的例子;
<html><title>The Hello, World Applet</title><hr><applet code="HelloWorldApplet.class" width="320" height="120">If your browser was Java-enabled, a "Hello, World" message would appear here.</applet><hr></html>
Java 文檔注釋
Java 支持三種注釋方式。前兩種分別是 // 和 /* */,第三種被稱作說明注釋,它以 /** 開始,以 */結束。
說明注釋允許你在程序中嵌入關於程序的信息。你可以使用 javadoc 工具軟件來生成信息,並輸出到HTML文件中。
說明注釋,使你更加方便的記錄你的程序信息。
javadoc 標簽
javadoc 工具軟件識別以下標簽:
標簽 |
描述 |
示例 |
@author |
標識一個類的作者 |
@author description |
@deprecated |
指名一個過期的類或成員 |
@deprecated description |
@param |
說明一個方法的參數 |
@param parameter-name explanation |
@return |
說明返回值類型 |
@return explanation |
@version |
指定類的版本 |
@version info |
文檔注釋
在開始的 /** 之后,第一行或幾行是關於類、變量和方法的主要描述。
之后,你可以包含一個或多個何種各樣的 @ 標簽。每一個 @ 標簽必須在一個新行的開始或者在一行的開始緊跟星號(*).
多個相同類型的標簽應該放成一組。例如,如果你有三個 @see 標簽,可以將它們一個接一個的放在一起。
下面是一個類的說明注釋的實例:
/*** 這個類繪制一個條形圖 * @author runoob * @version 1.2 */
javadoc 輸出什么
javadoc 工具將你 Java 程序的源代碼作為輸入,輸出一些包含你程序注釋的HTML文件。
每一個類的信息將在獨自的HTML文件里。javadoc 也可以輸出繼承的樹形結構和索引。
由於 javadoc 的實現不同,工作也可能不同,你需要檢查你的 Java 開發系統的版本等細節,選擇合適的 Javadoc 版本。
實例
下面是一個使用說明注釋的簡單實例。注意每一個注釋都在它描述的項目的前面。
在經過 javadoc 處理之后,SquareNum 類的注釋將在 SquareNum.html 中找到。
import java.io.*;/** * 這個類演示了文檔注釋 * @author Ayan Amhed * @version 1.2 */public class SquareNum { /** * This method returns the square of num. * This is a multiline description. You can use * as many lines as you like. * @param num The value to be squared. * @return num squared. */ public double square(double num) { return num * num; } /** * This method inputs a number from the user. * @return The value input as a double. * @exception IOException On input error. * @see IOException */ public double getNumber() throws IOException { InputStreamReader isr = new InputStreamReader(System.in); BufferedReader inData = new BufferedReader(isr); String str; str = inData.readLine(); return (new Double(str)).doubleValue(); } /** * This method demonstrates square(). * @param args Unused. * @return Nothing. * @exception IOException On input error. * @see IOException */ public static void main(String args[]) throws IOException { SquareNum ob = new SquareNum(); double val; System.out.println("Enter value to be squared: "); val = ob.getNumber(); val = ob.square(val); System.out.println("Squared value is " + val); }}
Java 實例
http://www.runoob.com/java/java-examples.html
Java 8 新特性
http://www.runoob.com/java/java8-new-features.html
Java8 新增了非常多的特性,我們主要討論以下幾個:
l Lambda 表達式 − Lambda允許把函數作為一個方法的參數(函數作為參數傳遞進方法中。
l 方法引用 − 方法引用提供了非常有用的語法,可以直接引用已有Java類或對象(實例)的方法或構造器。與lambda聯合使用,方法引用可以使語言的構造更緊湊簡潔,減少冗余代碼。
l 默認方法 − 默認方法就是一個在接口里面有了一個實現的方法。
l 新工具 − 新的編譯工具,如:Nashorn引擎 jjs、 類依賴分析器jdeps。
l Stream API −新添加的Stream API(java.util.stream) 把真正的函數式編程風格引入到Java中。
l Date Time API − 加強對日期與時間的處理。
l Optional 類 − Optional 類已經成為 Java 8 類庫的一部分,用來解決空指針異常。
l Nashorn, JavaScript 引擎 − Java 8提供了一個新的Nashorn javascript引擎,它允許我們在JVM上運行特定的javascript應用。
更多的新特性可以參閱官網:What's New in JDK 8
Java MySQL 連接
創建測試數據
CREATE TABLE `websites` ( `id` int(11) NOT NULL AUTO_INCREMENT, `name` char(20) NOT NULL DEFAULT '' COMMENT '站點名稱', `url` varchar(255) NOT NULL DEFAULT '', `alexa` int(11) NOT NULL DEFAULT '0' COMMENT 'Alexa 排名', `country` char(10) NOT NULL DEFAULT '' COMMENT '國家', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=10 DEFAULT CHARSET=utf8;
連接數據庫
Class.forName("com.mysql.jdbc.Driver"); Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/dalong?Unicode=true&characterEncoding=UTF-8", "root", "admin");
Java 9 新特性
http://www.runoob.com/java/java9-new-features.html
l 模塊系統:模塊是一個包的容器,Java 9 最大的變化之一是引入了模塊系統(Jigsaw 項目)。
l REPL (JShell):交互式編程環境。
l HTTP 2 客戶端:HTTP/2標准是HTTP協議的最新版本,新的 HTTPClient API 支持 WebSocket 和 HTTP2 流以及服務器推送特性。
l 改進的 Javadoc:Javadoc 現在支持在 API 文檔中的進行搜索。另外,Javadoc 的輸出現在符合兼容 HTML5 標准。
l 多版本兼容 JAR 包:多版本兼容 JAR 功能能讓你創建僅在特定版本的 Java 環境中運行庫程序時選擇使用的 class 版本。
l 集合工廠方法:List,Set 和 Map 接口中,新的靜態工廠方法可以創建這些集合的不可變實例。
l 私有接口方法:在接口中使用private私有方法。我們可以使用 private 訪問修飾符在接口中編寫私有方法。
l 進程 API: 改進的 API 來控制和管理操作系統進程。引進 java.lang.ProcessHandle 及其嵌套接口 Info 來讓開發者逃離時常因為要獲取一個本地進程的 PID 而不得不使用本地代碼的窘境。
l 改進的 Stream API:改進的 Stream API 添加了一些便利的方法,使流處理更容易,並使用收集器編寫復雜的查詢。
l 改進 try-with-resources:如果你已經有一個資源是 final 或等效於 final 變量,您可以在 try-with-resources 語句中使用該變量,而無需在 try-with-resources 語句中聲明一個新變量。
l 改進的棄用注解 @Deprecated:注解 @Deprecated 可以標記 Java API 狀態,可以表示被標記的 API 將會被移除,或者已經破壞。
l 改進鑽石操作符(Diamond Operator) :匿名類可以使用鑽石操作符(Diamond Operator)。
l 改進 Optional 類:java.util.Optional 添加了很多新的有用方法,Optional 可以直接轉為 stream。
l 多分辨率圖像 API:定義多分辨率圖像API,開發者可以很容易的操作和展示不同分辨率的圖像了。
l 改進的 CompletableFuture API : CompletableFuture 類的異步機制可以在 ProcessHandle.onExit 方法退出時執行操作。
l 輕量級的 JSON API:內置了一個輕量級的JSON API
l 響應式流(Reactive Streams) API: Java 9中引入了新的響應式流 API 來支持 Java 9 中的響應式編程。
更多的新特性可以參閱官網:What's New in JDK 9