JDK5.0新特性
雖然JDK已經到了1.8 但是1.5(5.0)的變化是最大的
1. 增強for循環
foreach語句 foreach簡化了迭代器
作用: 對存儲對象的容器進行迭代 (數組, collection, map)
1> 格式
增強for循環括號里寫兩個參數 第一個是聲明一個變量 第二個就是需要迭代的容器
for( 元素類型 變量名 : Collection集合 & 數組 ) {
...
}
2> 增強for循環和傳統for循環的區別
a. 增強for循環在使用時 必須要明確被遍歷的目標 這個目標 可以是Collection集合或者數組 如果遍歷Collection集合 在遍歷過程中還需要對元素進行操作 比如刪除 需要使用迭代器
b. 如果遍歷數組 還需要對數組元素進行操作 建議用傳統for循環因為可以定義角標通過角標操作元素 如果只為遍歷獲取 可以簡化成增強for循環 它的出現為了簡化書寫
3> 增強for循環迭代數組 String[] arr = {"a", "b", "c"}; //數組的靜態定義方式 只適用於數組首次定義的時候 for(String s : arr) { System.out.println(s); } 4> 增強for循環迭代單列集合 Collection List list = new ArrayList(); list.add("aaa"); // 增強for循環 沒有使用泛型的集合也能使用增強for循環迭代 for(Object obj : list) { String s = (String) obj; System.out.println(s); } 5> 增強for循環迭代雙列集合 Map 注意: 增強for循環不可以直接遍歷map集合 但是可以將map轉成set后再使用foreach語句 Map map = new HashMap(); map.put("a", "aaa"); // 傳統方式 Set entrys = map.entrySet(); // 獲得所有的鍵值對Entry對象 iter = entrys.iterator(); // 迭代出所有的entry while(iter.hasNext()) { Map.Entry entry = (Entry) iter.next(); String key = (String) entry.getKey(); // 分別獲得key和value String value = (String) entry.getValue(); System.out.println(key + "=" + value); } // 增強for循環迭代 原則上map集合是無法使用增強for循環來迭代的 因為增強for循環只能針對實現了Iterable接口的集合進行迭代 Iterable是jdk5中新定義的接口 就一個方法iterator方法 只有實現了Iterable接口的類 才能保證一定有iterator方法 java有這樣的限定是因為增強for循環內部還是用迭代器實現的 而實際上 我們可以通過某種方式來使用增強for循環 for(Object obj : map.entrySet()) { Map.Entry entry = (Entry) obj; // obj 依次表示Entry System.out.println(entry.getKey() + "=" + entry.getValue()); }
6> 集合迭代注意問題
在迭代集合的過程中 不能對集合進行增刪操作(會報並發訪問異常) 可以用迭代器的方法進行操作(子類listIterator 有增刪的方法)
7> 增強for循環注意問題
在使用增強for循環時 不能對元素進行賦值
int[] arr = {1, 2, 3};
for(int num : arr) {
num = 0; //不能改變數組的值
}
System.out.println(arr[1]); //2 還是原來的值
2. 可變參數 (...)
用到函數的參數上 當要操作的同一個類型元素個數不確定的時候 可是用這個方式 這個參數可以接受任意個數的同一類型的數據
和以前接收數組不一樣的是
以前定義數組類型 需要先創建一個數組對象 再將這個數組對象作為參數傳遞給函數 現在 直接將數組中的元素作為參數傳遞即可 底層其實是將這些元素進行數組的封裝 而這個封裝動作 是在底層完成的 被隱藏了 所以簡化了用戶的書寫 少了調用者定義數組的動作
如果在參數列表中使用了可變參數 可變參數必須定義在參數列表結尾(也就是必須是最后一個參數 否則編譯會失敗)
如果要獲取多個int數的和 可以使用將多個int數封裝到數組中 直接對數組求和即可
3. 靜態導入
導入了類中的所有靜態成員 簡化靜態成員的書寫
import static java.util.Collections.*; //導入了Collections類中的所有靜態成員
4. 枚舉 enum
問題: 對象的某個屬性的值不能是任意的 必須為固定的一組取值其中的某一個
解決辦法: (使用枚舉)
1> 在setGrade方法中做判斷 不符合格式要求就拋出異常
2> 直接限定用戶的選擇 通過自定義類模擬枚舉的方式來限定用戶的輸入 寫一個Grade類 私有構造函數 對外提供5個靜態的常量表示類的實例
3> jdk5中新定義了枚舉類型 專門用於解決此類問題
4> 枚舉就是一個特殊的java類 可以定義屬性, 方法, 構造函數, 實現接口, 繼承類
5. 自動拆裝箱
java中數據類型分為兩種: 基本數據類型, 引用數據類型(對象)
在java程序中所有的數據都需要當做對象來處理 針對8種基本數據類型提供了包裝類 如下
int --> Integer
byte --> Byte
short --> Short
long --> Long
char --> Character
double --> Double
float --> Float
boolean --> Boolean
jdk5以前基本數據類型和包裝類之間需要互轉
基本---引用 Integer x = new Integer(x);
引用---基本 int num = x.intValue();
1> Integer x = 1; x = x + 1; 裝箱 ---> 拆箱 ---> 裝箱
2> 為了優化 虛擬機為包裝類提供了緩沖池 Integer池的大小 -128~127 一個字節的大小
3> String池 Java為了優化字符串操作 提供了一個緩沖池
6. 泛型
jdk1.5版本以后出現的一個安全機制 表現格式: < >
只要帶有<>的類或者接口 都屬於帶有類型參數的類或者接口 在使用這些類或者接口時必須給<>中傳遞一個具體的引用數據類型
1> 好處
a. 將運行時期的問題ClassCastException問題轉換成了編譯失敗 體現在編譯時期 程序員就可以解決問題
b. 避免了強制轉換的麻煩
2> 泛型技術的本質
其實是 應用在編譯時期 給編譯器使用的技術 到了運行時期 泛型就不存在了
泛型的擦除: 也就是說 編輯器檢查了泛型的類型正確后 在生成的類文件中是沒有泛型的
泛型的補償: 因為存儲的時候 類型已經確定了是同一個類型的元素 所以在運行時 只要獲取到該元素的類型 在內部進行一次轉換即可 所以使用者不用再做轉換動作了
3> 什么時候用泛型類呢?
當類中的操作的引用數據類型不確定的時候 以前用的Object來進行擴展的 現在可以用泛型來表示 這樣可以避免強轉的麻煩 而且將運行問題轉移到的編譯時期
4> 泛型在程序定義上的體現
//泛型類 將泛型定義在類上 class Tool<Q> { private Q obj; public void setObject(Q obj) { this.obj = obj; } public Q getObject() { return obj; } } //當方法操作的引用數據類型不確定的時候 可以將泛型定義在方法上 public <W> void method(W w) { System.out.println("method:" + w); } //靜態方法上的泛型 靜態方法無法訪問類上定義的泛型 如果靜態方法操作的引用數據類型不確定的時候 必須要將泛型定義在方法上 public static <Q> void function(Q t) { System.out.println("function:" + t); } //泛型接口 interface Inter<T> { void show(T t); } class InterImpl<R> implements Inter<R> { public void show(R r) { System.out.println("show:" + r); } }
5> 泛型中的通配符
可以解決當具體類型不確定的時候 這個通配符就是 ? 當操作類型時 不需要使用類型的具體功能時 只使用Object類中的功能 那么可以用 ? 通配符來表未知類型
6> 泛型限定
上限: ?extends E 可以接收E類型或者E的子類型對象
下限: ?super E 可以接收E類型或者E的父類型對象
上限什么時候用: 往集合中添加元素時 既可以添加E類型對象 又可以添加E的子類型對象 因為取的時候 E類型既可以接收E類對象 又可以接收E的子類型對象
下限什么時候用: 當從集合中獲取元素進行操作的時候 可以用當前元素的類型接收 也可以用當前元素的父類型接收
7> 泛型的細節
a. 泛型到底代表什么類型取決於調用者傳入的類型 如果沒傳 默認是Object類型
b. 使用帶泛型的類創建對象時 等式兩邊指定的泛型必須一致 因為編譯器檢查對象調用方法時只看變量 然而程序運行期間調用方法時就要考慮對象具體類型了
c. 等式兩邊可以在任意一邊使用泛型 在另一邊不使用(考慮向后兼容)
ArrayList<String> al = new ArrayList<Object>(); //錯 要保證左右兩邊的泛型具體類型一致就可以了 這樣不容易出錯
ArrayList<? extends Object> al = new ArrayList<String>();
al.add("aa"); //錯 因為集合具體對象中既可存儲String 也可以存儲Object的其他子類 所以添加具體的類型對象不合適 類型檢查會出現安全問題 ?extends Object 代表Object的子類型不確定 不能添加具體類型的對象
public static void method(ArrayList<? extends Object> al) {
al.add("abc"); //錯 只能對al集合中的元素調用Object類中的方法 具體子類型的方法都不能用 因為子類型不確定
}