JDK1.5新特性: 1.自動拆裝箱. 2.泛型 3.可變參數 4.靜態導入 5.增強for迴圈 6.互斥鎖 7.枚舉 8.註解 JDK1.6新特性: 1.Desktop類和SystemTray類 2.使用JAXB2來實現對象與XML之間的映射 3.StAX 4.使用Compiler API 5.輕 ...
JDK1.5新特性:
1.自動拆裝箱.
2.泛型
3.可變參數
4.靜態導入
5.增強for迴圈
6.互斥鎖
7.枚舉
8.註解
JDK1.6新特性:
1.Desktop類和SystemTray類
2.使用JAXB2來實現對象與XML之間的映射
3.StAX
4.使用Compiler API
5.輕量級Http Server API
6.插入式註解處理API(Pluggable Annotation Processing API)
7.用Console開發控制台程式
8.對腳本語言的支持
9.Common Annotations
JDK1.7新特性:
1 對集合類的語言支持;
2 自動資源管理;
3 改進的通用實例創建類型推斷;
4 數字字面量下劃線支持;
5 switch中使用string;
6 二進位字面量0b001;
7 簡化可變參數方法調用。
8 泛型簡化,出現菱形泛型
9 異常的多個catch合併,每個異常用或|
10 try-with-resources 語句
JDK1.8 新特性:
一、介面的預設方法:Java 8允許我們給介面添加一個非抽象的方法實現,只需要使用 default關鍵字即可,這個特征又叫做擴展方法,
二、Lambda 表達式:Collections.sort(names, (a, b) -> b.compareTo(a));Java編譯器可以自動推導出參數類型,所以你可以不用再寫一次類型。
三、函數式介面:每一個lambda表達式都對應一個類型,通常是介面類型。而“函數式介面”是指僅僅只包含一個抽象方法的介面,每一個該類型的lambda表達式都會被匹配到這個抽象方法。
因為 預設方法 不算抽象方法,所以你也可以給你的函數式介面添加預設方法。
四、方法與構造函數引用:Java 8 允許你使用 :: 關鍵字來傳遞方法或者構造函數引用,上面的代碼展示瞭如何引用一個靜態方法,我們也可以引用一個對象的方法:
五、Lambda 作用域:在lambda表達式中訪問外層作用域和老版本的匿名對象中的方式很相似。你可以直接訪問標記了final的外層局部變數,或者實例的欄位以及靜態變數。
六、訪問局部變數:lambda表達式中訪問外層的局部變數
七、訪問對象欄位與靜態變數:lambda內部對於實例的欄位以及靜態變數是即可讀又可寫。該行為和匿名對象是一致的:
八、訪問介面的預設方法:Lambda表達式中是無法訪問到預設方法的
九、Date API:Java 8 在包java.time下包含了一組全新的時間日期API。新的日期API和開源的Joda-Time庫差不多,但又不完全一樣
十、Annotation 註解:在Java 8中支持多重註解了,Java 8允許我們把同一個類型的註解使用多次,只需要給該註解標註一下@Repeatable即可,
斷言的使用方式:
斷言是一種測試和調測階段所使用的戰術工具.
斷言的初衷:在一個具有自我保護能力的程式中,斷言很常用.假設確信某個屬性符合要求,並且代碼的執行依賴於這個屬性.例如,需要計算
double y = Math.sqrt(x);
我們確信,這裡的x是一個非負數的值.原因是:是另外一個計算的結果,而這個結果不可能是負值;或者x是一個方法的參數,而這個方法要求它的調用者只能提供一個正整數.
然而,還是希望進行檢查,以避免讓"不是一個數"的數值參與計算操作.當然,也可以拋出一個異常:
if(x<0) throw new IllegalArgumentException("x<0");
但是需要註意的是,這段代碼會一直保留在程式中,即使測試完畢也不會自動的刪除.如果在程式中包含有大量的這種檢查,程式運行起來會相當慢.
斷言機制允許在測試期間向代碼中插入一些檢查語句.當代碼發佈時,這些插入的檢查語句將會被自動的移走.
開啟斷言:2.在myEclipse中,Windows -> Preferences ->Java ->Installed JREs ->點擊正使用的JDK ->Edit ->Default VM Arguments文本框中輸入:-ea或者-enableassertions
斷言的格式:
java中語音引入關鍵字assert.這個關鍵字有兩種表現形式:
1.assert 條件: 例如:assert x>=0; 想要斷言x是一個非負數值,只需要簡單的使用這條語句.
2.assert 條件:表達式; 例如:assert x>=0 : x; 或者將x的實際值傳遞給AssertionError對象,從而可以在後面顯示出來.
這兩個格式都會對條件進行檢測,如果結果為false,則拋出一個AssertionError異常.
在第二種格式中,表達式將被傳入AssertionEeror的構造器,並轉換成一個消息字元串.
註釋:"表達式"部分的唯一目的是產生一個消息字元串.AssertionErro對象並不存儲表達式的值,因此,不可能在以後得到它.正如JDK文檔所描述的那樣:如果使用表達式的值,
就會鼓勵程式員試圖從斷言中恢復程式的運行,這不符合斷言機制的初衷.
啟用和禁用斷言
在預設情況下,斷言是被禁用的。可以在程式運行時用-enableassertions或-ea選項啟用它:
java -enableassertions MyApp
啟用或者禁用斷言不必重新編譯程式。啟動或者禁用斷言是類載入器的功能。當斷言被禁用時,類載入器將跳過斷言代碼,因此,不會降低程式的運行速度。
也可以在某個類或者某個包中使用斷言,例如:
java -ea:MyClass -ea:com.mycompany.mylib... MyApp
這條命令將開啟MyClass類以及在com.mycompany.mylib包和它的子包中的所有類的斷言。選項-ea將開啟預設包中的所有類的斷言。
也可以使用-disableassertions或-da禁用某個特定的類和包的斷言:
java -ea:... -da:MyClass MyApp
有些類不是由類載入器載入,而是直接由虛擬機載入。可以使用這些開關有選擇地啟用或禁用哪些類中的斷言。
然而,啟用和禁用所有斷言的-ea和-da開關並不能應用到那些沒有類載入器的“系統類”上。對於這些系統類而言,需要使用-enablesystemassertions/-esa開關啟動斷言。
使用斷言完成參數檢查
API:java.long.ClassLoader 1.0 子類MLet
void setDefaultAssertionStatus(Boolean b) //1.4
對於通過類載入器載入的所有類來說,如果沒有顯示的說明類或者包的斷言 狀態,就啟用或禁用斷言.
void setClassAssertionSatus(String className,boolean b) //1.4
對於給定的類和它的內部類,啟用或禁用斷言.
void setPackageAssertionStatus(String packageName,boolean b) //1.4
對於給定包和其子包中的所有類,啟用或禁用斷言.
void clearAssertionStatus() //1.4
移去所有類和包的顯示斷言狀態設置,並禁用所有通過這個類載入器載入的類的斷言.
java中的3中處理系統錯誤的機制:
拋出一個異常
日誌
使用斷言
什麼時候應該使用斷言呢?
斷言失敗是致命的、不可恢復的錯誤
斷言檢查只用於開發和測試階段
因此,不應該使用斷言向程式的其他部分通告發生了可恢復性的錯誤,或者,不應該作為程式向用戶通告問題的手段。斷言只應該是在測試階段確定程式內部錯誤的位置。
斷言是一種測試和調試階段所使用的戰術性工具;而日誌記錄是一種在程式的整個生命周期都可以使用的策略性工具。
public class App
{
public static void main( String[] args )
{
int a = -1;
assert a > 0 : "liuni是笨蛋";
System.out.println( "Hello World!" );
}
}
程式中記錄日誌一般有兩個目的:Troubleshooting和顯示程式運行狀態。好的日誌記錄方式可以提供我們足夠多定位問題的依據。日誌記錄大家都會認為簡單,但如何通過日誌可以高效定位問題並不是簡單的事情。這裡列舉下麵三個方面的內容,輔以代碼示例,總結如何寫好日誌,希望對他人有所啟發和幫助:
怎樣記日誌可以方便Troubleshooting
程式運行狀態可以記哪些
應該避免怎樣的日誌方式
怎樣記日誌可以方便Troubleshooting?
1. 對外部的調用封裝
程式中對外部系統與模塊的依賴調用前後都記下日誌,方便介面調試。出問題時也可以很快理清是哪塊的問題
[java] view plain copy
LOG.debug("Calling external system:" + parameters);
Object result = null;
try {
result = callRemoteSystem(params);
LOG.debug("Called successfully. result is " + result);
} catch (Exception e) {
LOG.warn("Failed at calling xxx system . exception : " + e);
}
2.狀態變化
程式中重要的狀態信息的變化應該記錄下來,方便查問題時還原現場,推斷程式運行過程
[java] view plain copy
boolean isRunning;
isRunning = true;
LOG.info("System is running");
//...
isRunning = false;
LOG.info("System was interrupted by " + Thread.currentThread().getName());
3.系統入口與出口:
這個粒度可以是重要方法級或模塊級。記錄它的輸入與輸出,方便定位
[java] view plain copy
void execute(Object input) {
LOG.debug("Invoke parames : " + input);
Object result = null;
//business logic
LOG.debug("Method result : " + result);
}
4.業務異常:
任何業務異常都應該記下來:
[java] view plain copy
try {
//business logical
} catch (IOException e) {
LOG.warn("Description xxx" , e);
} catch (BusinessException e) {
LOG.warn("Let me know anything");
} catch (Exception e) {
LOG.error("Description xxx", e);
}
5.非預期執行:
為程式在“有可能”執行到的地方列印日誌。如果我想刪除一個文件,結果返回成功。但事實上,那個文件在你想刪除之前就不存在了。最終結果是一致的,但程式得讓我們知道這種情況,要查清為什麼文件在刪除之前就已經不存在
[java] view plain copy
int myValue = xxxx;
int absResult = Math.abs(myValue);
if (absResult < 0) {
LOG.info("Original int " + myValue + "has nagetive abs " + absResult);
}
6.很少出現的else情況:
else可能吞掉你的請求,或是賦予難以理解的最終結果
[java] view plain copy
Object result = null;
if (running) {
result = xxx;
} else {
result = yyy;
LOG.debug("System does not running, we change the final result");
}
日誌記錄:
程式運行狀態可以記哪些?
程式在運行時就像一個機器人,我們可以從它的日誌看出它正在做什麼,是不是按預期的設計在做,所以這些正常的運行狀態是要有的。
1. 程式運行時間:
[java] view plain copy
long startTime = System.currentTime();
// business logical
LOG.info("execution cost : " + (System.currentTime() - startTime) + "ms");
2. 大批量數據的執行進度:
[java] view plain copy
LOG.debug("current progress: " + (currentPos * 100 / totalAmount) + "%");
3.關鍵變數及正在做哪些重要的事情:
執行關鍵的邏輯,做IO操作等等
[java] view plain copy
String getJVMPid() {
String pid = "";
// Obtains JVM process ID
LOG.info("JVM pid is " + pid);
return pid;
}
void invokeRemoteMethod(Object params) {
LOG.info("Calling remote method : " + params);
//Calling remote server
}
應該避免怎樣的日誌方式?
1. 混淆信息的Log
日誌應該是清晰準確的: 當看到日誌的時候,你知道是因為連接池取不到連接導致的問題麽?
[java] view plain copy
Connection connection = ConnectionFactory.getConnection();
if (connection == null) {
LOG.warn("System initialized unsuccessfully");
}
2. 記錯位置
產品代碼中,使用console記錄日誌,導致沒有找到日誌。
[java] view plain copy
} catch (ConfigurationException e) {
e.printStackTrace();
}
3. 記錯級別
記錯級別常常發生,常見的如:混淆代碼錯誤和用戶錯誤,如登錄系統中,如果惡意登錄,那系統內部會出現太多WARN,從而讓管理員誤以為是代碼錯誤。可以反饋用戶以錯誤,但是不要記錄用戶錯誤的行為,除非想達到控制的目的。
[java] view plain copy
LOG.warn("Failed to login by "+username+");
4. 遺漏信息
這裡可能包含兩種情況:(1)用戶自己少寫了信息,導致毫無參考價值;(2)用戶調用log的方式導致丟失信息,如下例,沒有stack trace.
[java] view plain copy
} catch (Exception ex) {
log.error(ex);
}
*/
----------String--------------
構造:
String(String original):把字元串數據封裝成字元串對象
String(char[] value):把字元數組的數據封裝成字元串對象
String(char[] value, int index, int count):把字元數組中的一部分數據
方法:
判斷功能:
boolean equals(Object obj):比較字元串的內容是否相同
boolean equalsIgnoreCase(String str):比較字元串的內容是否相同,忽略大小寫
boolean startsWith(String str):判斷字元串對象是否以指定的str開頭
boolean endsWith(String str):判斷字元串對象是否以指定的str結尾
獲取功能:
int length():獲取字元串的長度,其實也就是字元個數
char charAt(int index):獲取指定索引處的字元
int indexOf(String str):獲取str在字元串對象中第一次出現的索引
String substring(int start):從start開始截取字元串
String substring(int start,int end):從start開始,到end結束截取字元串。包括start,不包括end
轉換功能:
char[] toCharArray():把字元串轉換為字元數組
String toLowerCase():把字元串轉換為小寫字元串
String toUpperCase():把字元串轉換為大寫字元串
String replace(char oldChar, char newChar)通過用 newChar 替換此字元串中出現的所有 oldChar ,返回處理後的字元串。
其它功能:
String trim():去除字元串兩端空格
String[] split(String str):按照指定符號分割字元串
--------StringBuider(可變字元串)------------
構造:
就一個
方法:
public int capacity():返回當前容量 (理論值)
public int length():返回長度(已經存儲的字元個數)
public StringBuilder append( 任意類型 ):添加數據,並返回添加的數據
public StringBuilder reverse():反轉功能
StringBuilder replace(int start, int end, String str) 使用給定 String 中的字元替換此序列的子字元串中的字元。
--------Integer(包裝類)---------------
構造:
不需要,直接類名.方法名調用,如下
方法:
Integer.parseInt(String str):將字元串轉int類型(只能數字內容的字元串,不然報錯)
---------ArrayList(集合)-------------------
構造:
ArrayList();就學了空參創建
方法:
public boolean add(E e):添加元素,成功返回true,就業班學false
public void add(int index,E element):在指定的索引處添加一個元素
public E get(int index):返回指定索引處的元素
public E set(int index,E element):修改指定索引處的元素,返回被修改的元素
public int size():返回集合中的元素的個數
public boolean remove(Object o):刪除指定的元素,返回刪除是否成功
E remove(int index) 移除此列表中指定位置上的元素,並返回刪除的數據。
---------FileWriter(輸出普通流)-----------
構造:
FileWriter(String fileName); 傳入一個文件的路徑
方法:
void write(int c) 寫入一個字元,int類型傳入
void write(String str) 寫入一個字元串
void write(String str, int startIndex, int len) 寫入字元串的一部分
void write(char[] cbuf) 寫入一個字元數組
void write(char[] cbuf, int startIndex, int len)寫入字元數組的一部分
void flush() 將記憶體中的數據刷新到文件中
void close() 數據刷新到文件中,關流釋放系統底層資源(關閉後永久關閉,直到下次程式運行)
---------BufferedWriter(輸出緩衝流)-----------
構造:
BufferedWriter(new FileWriter(String fileName));傳入一個FileWriter對象,FileWriter包含一個文件的路徑
方法 (同FileWriter,多了一個方法):
void newLine() 寫入換行(\r\n)
---------FileReader(輸入普通流)-----------
構造:
FileReader(String fileName); 傳入一個文件的路徑
方法:
int read() 讀取單個字元,若是讀取成功返回參數的int類型表現形式,若讀取失敗,返回-1
int read(char[] cbuf) 讀取指定char數組長度個字元,並存入char數組,若是讀到文件尾部,則停止讀取,並返回讀取字元的個數(不是char數組長度),若是一個都沒讀到,返回-1。
int read(char[] cbuf, int startIndex, int len) 讀取 startIndex 索引開始, len 個字元(length簡拼)
void reset() 重置流(刪除前面讀的記錄)
---------BufferedReader(輸入緩衝流)-----------
構造:
FileReader(String fileName); 傳入一個文件的路徑
方法 (同FileReader,多了一個方法)
String ReadLine() 一次讀一行的內容,返回讀到的內容,沒讀到返回null
-----------Arrays(工具類,考試不推薦使用)-----------------
構造:
不需要構造,因為該類不需要創建對象
方法:
String toString(各種數組,集合不行) 返回該數組的全部內容的特定格式(遍曆數組)
方法重載:
1.方法名相同
2.參數列表不同(數量、類型、順序)
方法覆蓋:
1.訪問修飾符相同或更寬
2.返回值類型相同
3.方法名相同
4.參數表相同
5.static 靜態只能覆蓋靜態 非靜態只能覆蓋非靜態
6.子類方法不能拋出比父類更多的異常
三大修飾符:
static
可以修飾屬性、方法和初始化代碼塊,不可以修飾局部變數
1. 靜態屬性、方法為全類所有,可通過類名直接調用
2. 靜態初始化代碼塊在類載入時執行,僅執行一次
final
可以修飾局部變數、成員變數、方法和類
1. final修飾的變數一旦被賦值,就不能改變
2. final修飾的方法不可以被覆蓋
3. final修飾的類不能被繼承
abstract
可以修飾類和方法
1. 抽象類只能聲明引用,不能創建對象
2. 抽象方法只有聲明,沒有實現(不寫代碼塊)
3. 如果一個類中有抽象方法,那這個類必須是抽象類
4. 子類繼承一個抽象類,如果不希望子類變成抽象類,那子類必須實現父類中的全部抽象方法
PS:多個修飾符修飾同一方法、類時的使用問題
1. abstract 不能與 final 一起修飾方法、類
抽象類、方法需要被繼承、覆蓋才可使用,final修飾的類、方法不可被繼承、覆蓋
2. abstract 不能與 private 一起修飾方法(private只能修飾內部類)
理由同上,私有方法不能被繼承
3. abstract 不能與 static 一起修飾方法(static只能修飾類的成員,不能修飾類本身)
抽象類需要有子類的實現類才能調用內部方法,而靜態類可以直接通過本類名調用內部方法
4. private 與 static 與 final 可以連用(屬性、方法都可以)
許可權修飾符:private default protect public 可以修飾方法
public default 可以修飾類
介面:interface
1. 介面是特殊的抽象類(interface 代替了 abstract class)
2. 介面中所有屬性都是公開靜態常量
3. 介面中所有方法都是公開抽象方法
4. 一個介面可以繼承多個介面(extends 多個介面,介面之間用逗號隔開)
5. 一個類只可以繼承一個父類,但是可以實現多個介面
PS: 抽象類與介面的不同點
1. 抽象類可以有構造方法,介面不可以有構造方法
2. 抽象類不可以多繼承,介面可以多繼承
介面的實現(被子類繼承):implements
1. 一個類實現介面,如果不希望作為抽象類,就必須實現介面中全部方法
介面的作用;
1. 介面與多繼承
1. 可以讓子類繼承主要類型,讓次要類型作為一個介面讓子類實現.
2. 單繼承具備簡單性(相對於多繼承),使用介面實現的多繼承並不會破壞其簡單性
2. 介面與解耦合
介面抽象出子類中的共性,利用多態來解耦合
3. 介面回調
實現某些介面,由函數庫中方法自動調用。
例:
定義實體類是實現Comrparable<E>介面(中的comepareTo方法,返回值為int)
在調用java.util.Arrays.sort數組排序方法時,可以排序存放實體類的數組
Object類:
Object是所有類的父類,如果一個類沒有定義直接繼承的父類,就會直接繼承Object類(自動加上extends Object)
所有的類都會繼承Object類中的全部公開方法。
Obeject類中的全部方法:
1. finalize
該方法在垃圾回收時,被垃圾回收器調用
(什麼是垃圾? -- 沒有引用指向的對象)
1. JVM中有自動垃圾回收機制,程式員只需要創建對象、分配空間,不需要回收垃圾
2. JVM只有在記憶體不夠用的時候才會進行垃圾回收
(可能會浪費空間,但減少了垃圾回收對CPU的占用)
2. getClass
作用:得到對象的"實際"類型
補充:instanceof 可看做是不是: 引用 instanceof 類型
該引用的實際類型 是不是 某類型
比較兩個對象的實際類型是不是相等:
1. 使用 instanceof 只能得出某對象的實際樂行是不是某類型的子類
2. 可以使用getClass得到 對象的實際類型
語法:m1.getClass() == m2.getClass()
3. equals
作用: 比較兩個對象
1. 可以在子類中覆蓋equals方法,作用為使兩個對象可以使用自定義的標準相互比較
2. 如果不覆蓋equals方法,預設比較兩個對象的地址值(即使用 == 比較兩個引用類型)
3. 字元串類覆蓋了equals方法
覆蓋equals方法的五個步驟:
1. 判斷 this == obj (地址相同直接返回true)
2. 判斷 obj == null (this一定不是null,否則無法調用equals方法)
3. 判斷 兩個對象的實際類型是否相同(使用getClass方法)
4. 強制類型轉換
5. 依次比較兩個對象的屬性是否相等
4. toString
作用:列印
在控制台列印對象時,自動調用該對象的toString方法
包裝類:
將基本數據類型封裝為對象數據類型:
int -- Integer
char -- Character
其他基本數據類型 -- 首字母大寫
int Integer String 之間的相互轉換:
1. Integer ii = new Integer( int i )
Integer ii = new Integer( String s )
2. int i = ii.intValue()
int i = Integer.paresInt( String s )
3. String s = ii.toString()
String s = String.valueOf( int i )
正則表達式:
作用: 使用正則表達式可以匹配出想要的字元串
1. [] [a-zA-Z0-9] [1235] 中括弧可以匹配多個字元,或者範圍內字元,範圍使用-分隔,多組範圍直接連著寫
2. {} {5} {5,10} 限制前一個字元內容長度,或者長度範圍,範圍使用逗號分隔
3. 特殊意義字元: \:轉義字元,想要使用\ 需要使用轉義字元 \\
+:放在字元後面,代表匹配一個或多個該字元,想要使用+,需要使用轉義字元 \\+
.:匹配任意一個字元,使用字元本身,需要轉義 \\.
\\d 匹配任意字母
\\w 匹配任意字母或者數字
( | ) 邏輯或,匹配 | 前面或者後面的字元,例:(J|j)ava 可以匹配 Java 或者 java
^: 代表必須是字元串的開頭,例:^[a-z] 字元串必須以小寫字母開頭
$: 代表前一個字元必須是匹配內容的結尾,例:^[a-z][0-9]$ 字元串必須以數字結尾
\\_ 下劃線
內部類:
成員內部類:
1. 成員內部類可以訪問外部類中所有的、靜態的、私有的屬性和方法
2. 成員內部類中不可以定義靜態的屬性和方法
3. 創建成員內部類對象,需要先創建一個外部類對象(依賴於獨立的外部類對象,因此不可以有靜態成員)
創建成員內部類對象:
外部類 out = new 外部類();
外部類.內部類 引用名 = out.new 外部類.內部類();
(類型是 外部類.內部類,作為一個外部類的成員,需要用一個外部類對象來創建)
靜態內部類:
1. 靜態內部類只能訪問外部類中所有的靜態屬性和方法
2. 靜態內部類可以定義普通的和靜態的屬性和方法
3. 創建靜態內部類對象,可以直接使用該類的類型創建(靜態成員不依賴於外部類的對象)
創建靜態內部類對象:
外部類.靜態內部類 引用名 = new 外部類.靜態內部類();
(不依賴外部類對象,直接用類型創建)
局部內部類:
作用同下
匿名內部類:
new 介面名() { 介面的實現代碼 }
用途:
需要一個僅僅使用一次的對象時,直接在方法內部創建、使用,不需要打斷思路,另開一個實現類
缺點:
代碼可讀性差
集合框架:
為什麼使用集合: 數組的擴容、插入、刪除操作十分繁瑣
集合的類型:
Collection<Object> 介面
--> List<Object> 介面
--> Set<Object> 介面
Map<Key, Value> 介面
集合中的方法:
Collecion :
add (Object obj) -- boolean 添加元素
contains (Object obj) -- boolean 查看是否包含某元素
isEmpty() -- boolean 集合是否為空
remove (Object obj) -- boolean 刪除某元素
clear() -- void 清空集合
size() -- int 查看集合中元素個數
List : 元素是對象類型,元素有下標(有順序),元素可以重覆
add (Object obj) / add (int index, Object obj)
添加元素,可以直接添加,或者插入到指定的index
get (int index) set (int index, Object obj)
根據下標,獲取或者修改元素
indexOf (Object obj) -- int
獲取元素下標
Set: 元素是對象類型,元素沒有下標(沒有順序),元素不可以重覆
Set集合沒有自己特有的方法,全部方法繼承自Collection
Map: 元素是鍵值對類型,鍵不可以重覆,值可以重覆
get (Object key) -- Object
根據鍵,獲取對應的值
put (Object key, Object value) -- void
添加一個鍵值對
remove (Object key) -- void
刪除一個鍵值對,根據值
ketSet() -- Set
獲取全部的鍵,放到一個Set裡面返回
values() -- Collection
獲取全部的值,放到一個Collection中返回
containsKey/containsValus
查看Map中是否包含某個Key/Values
size()
查看Map中鍵值對個數
isEmpty()
clear()
entrySet()
獲取全部的鍵值對(Map.Entry類型),放到Set中返回
集合的實現類:
List 的實現類:
ArrayList
1. 使用數組實現
2. 增刪慢,查詢快
LinkedList
1. 使用鏈表實現
2. 增刪快,查詢慢
Vector
1. JDK1.0遺留的產物
2. 重量級,線程安全,速度慢(多線程訪問同一對象時,不會出現同步問題)
Set 的實現類:
HashSet
1. 集合中的元素無序,不重覆(可以用來去除一組元素中重覆的數據)
2. new HashSet() 預設容量16,載入因數0.75
3. newHashSet(int 容量, float )
LinkedHashSet
1. 遍歷時可以保留添加到集合中的順序(Set集合中的元素是無序的)
Set 集合是如何實現不重覆元素的?
添加進Set集合中的元素要想做到不重覆需要:
1. 需要覆蓋 equals() 方法 -- 變成比較元素內容而不是比較元素地址
2. 需要覆蓋 hashCode() 方法 -- 使哈希碼與元素內容有關,
保證相同元素有相同哈希碼,
儘量保證不同元素哈希碼不同,
可節省運算、比較次數
如何實現元素不重覆的?
1. 每個對象都有自己的 hashCode(hashSet使用數組加鏈表實現)
-- hashCode決定對象在集合中的存放位置,
初始hashCode值由對象地址決定
2. 如果兩個對象的hashCode相同,就使用 equals() 方法進行比較,
去掉重覆元素,不重覆的掛到該hashCode對應數組位置中的鏈表裡
3. 如果兩個對象hashCode不同,那麼放入集合的位置就可能不同,
兩個對象就不會進行 equals() 方法比較的過程,因此必須修改hashCode方法
讓內容可能相同的對象hashCode相同,進行比較去重覆。
同時也要儘量保證內容不同的對象的hashCode不同,儘量加快運算速度。
equals方法:
1. 判斷兩個對象地址是否相同(直接等於)
2. 判斷參數對象是否為空
3. 判斷兩個對象類型是否相同(使用getClass方法)
使用 instanceof 有可能遇到父子類的情況
4. 將參數對象類型強轉成本類對象類型
5. 逐個比較兩個對象的屬性
Map 的實現類:
HashMap
1. 鍵不可以重覆,同樣需要覆蓋 equals 方法和 hashCode 方法
2. 允許鍵/值為 null
LinkedHashMap
1. 遍歷時,保留了鍵的放入順序
HashTable
1. 類似於 Vector ,重量級,速度慢,線程安全
2. 當鍵/值為 null 時,會拋出異常
Map 集合的三種遍歷方式:
鍵遍歷:
使用 keySet() 方法,拿到全部鍵的Set,再遍歷 Set 即可(配合 get(key) 方法拿值)
值遍歷:
使用 values() 方法,拿到全部值的Collection
鍵值對遍歷:
1.使用 entrySet() 方法,拿到全部的鍵值對Set
裝有鍵值對的Set的泛型需要註意寫法:
例: Set<Map.Entry<Integer, String>> set = map.entrySet();
鍵值對的類型為:Map.Entry , 例: Map.Entry entry = (Map.Entry)iter.next();
鍵值對的迭代器遍歷時,需要將從Set中取出
的值強轉成 Map.Entry 類型
↑↑以上是JDK5.0之前泛型沒出的時候的做法
加泛型之後,不需要在強轉了
2. 使用Map.Entry類中的 getKey() / getValue() 方法,獲取鍵值對中的鍵和值
PS:用迭代器遍歷集合
Iterator iter = list.iterator(); --> List 和 Set 中有iterator方法,獲取迭代器
//創建一個迭代器對象
while( iter.hasNext() ) {
Object value = iter.next();
//對拿到的value進行需要的操作
}
foreach遍歷
1. foreach封裝了迭代器遍歷
2. 迭代器對與集合長度及變化做了安全監測,
3. 定義了異常:ConcurrentModificationException 併發修改異常
4. 在使集合創建迭代器時,會為變數expectedModCount賦值(賦予當前modCount的值)
5. foreach遍歷集合時,先調用hasNext方法,指針後移,如果索引等於集合長度,
則結束迴圈,如果索引小於集合長度,
則通過next()取出指針指向的集合內對象地址,執行迴圈體。
6. 在next()中進行集合長度及變化的安全監測,如果索引大於集合長度,則說明在
上一次迴圈的迴圈體中,出現了修改集合長度的操作,則直接拋出
併發修改異常;集合之中有一個成員變數modCount,
記錄了集合被增刪元素的次數,next()中會先比較expectedModCount和
modCount的值是否相同,及監測集合有沒有被修改過,如果不同就拋出
併發修改異常
PS: 7. 安全監測是在next方法中進行的,因此若是刪除集合的倒數第二個元素:
在迴圈體執行刪除語句,刪除後集合長度-1,迴圈體結束進入下一次迴圈判斷
hasNext方法:索引長度剛好等於集合長度,結束迴圈,不進入next方法。
所以:可以在foreach遍歷集合中,刪除倒數第二個元素。
8. iterator的remove方法對集合修改安全監測進行了屏蔽處理,
使用iterator中的方法刪除元素,不會拋出異常
結論:Iterator做出了安全監測,集合對象不可以在foreach迴圈遍歷集合中,
做出增加刪除元素的操作,否則拋出併發修改異常。
(除了刪除倒數第二個元素)
集合工具類:
Collections :(靜態方法)
1. Collections.shuffle(list) 打亂一個List集合中元素的排列順序
2. Collections.sort(list) 按照自然順序排序一個List集合內的元素
3. Collections 只能作用於List集合
Properties:持久的屬性集
1. Properties繼承自Map集合
2. Properties中有方法可以將集合中內容保存在文本文件中
3. Properties限定泛型,只能裝String類型數據(name,value)
4. Properties中的常用方法:
1. setProperties(String, String)
2. getProperties(String key)
3. stringPropertyNames(獲取集合中全部的name的 Set 集合)
4. store(OutputStream,String comments) -- 將集合中數據通過輸出流保存在文本文件中
自定義一個輸出流,文本文件必須以.properties結尾,commetns為註釋,可以為null
5. load(InputStream) -- 通過一個輸入流將文件中內容傳入Properties對象中