java入門

1.基礎語法

基本數據類型

Java有8種基本數據類型,分別是byte、short、int、long、float、double、char、boolean。這8種類型又可以劃分為4個小類,每一個類型佔據不同的內存空間,詳細見下表:

img

整數類型

整數類型的最高位存放正負符號,1表示負、0表示非負,其餘位置存放整數值。所以,根據不同整數類型的位數,我們可以推算出它的數據範圍:

img

浮點類型

浮點類型採用科學計數法來表示數值,對於任意的小數,我們都可以採用統一的科學計數形式表示它。

0.0123 = 0.123 * 10^-1

12.345 = 0.12345 * 10^2

-123.45 = -0.12345 * 10^3

這種表示數字的形式包含三個要素:符號、指數、尾數。

img

浮點類型,就是將小數轉換為科學計數法的形式,再將一串二進制的整數分為三段,分別存儲小數的符號、尾數、指數。所以,float和double的表數範圍如下:

img

字符類型

字符類型的本質也是整數,它採用16位的二進制整數來對字符進行編碼,在Unicode字符集下,16位整數可以表示出65535個字符。其最小值為u0000,最大值為uffff。

布爾類型

布爾類型只包含兩個值:true、false。所以實際上它只需要一位的存儲空間即可,但Java虛擬機並沒有規定布爾類型的具體實現,很多虛擬機實際是採用int來實現的布爾類型,這是出於性能的考慮。

類型轉換

除了布爾類型之外,其餘7種類型均為數字,所以它們之間可以相互轉換。而轉換的關鍵是數據類型的範圍,下圖給出了7種類型由小到大的數據範圍。

img

由小到大地轉換是沒有風險的,可以直接轉,這叫自動類型轉換。由大到小轉換則存在風險,很有可能會在轉換時出現數據溢出的情況,所以需要進行強制轉換。

// 自動類型轉換

int a = 5;

double b = a;

// 強制類型轉換

double c = 3.14;

int d = (int) c;

運算符

Java支持7類運算符:算術運算符、關係運算符、邏輯運算符、賦值運算符、三元運算符、字符串運算符、位運算符。

算術運算符

img

關係運算符

img

邏輯運算符

img

賦值運算符

img

三元運算符

// 語法

布爾表達式 ? 表達式1 : 表達式2

// 示例

age < 18 ? “未成年” : “已成年”

字符串運算符

// 語法

字符串 + 任意類型數據

// 示例

int age = 20;

String str = “我今年” + age + “歲”;

位運算符

img

分支

Java的分支語句有兩種形式:if語句、switch語句。

if 語句語法

// 第一種形式

if (邏輯表達式) {

}

// 第二種形式

if (邏輯表達式) {

} else {

}

// 第三種形式(else if 可以出現任意多次)

if (邏輯表達式) {

} else if (邏輯表達式) {

} else {

}

switch 語句語法

switch (表達式) {

case 值1: {

break;

}

case 值2: {

break;

}

default: {

}

}

// 1. 表達式可以返回如下類型:byte, short, int, char, String, Enum

// 2. case語句可以出現任意多次

// 3. default語句可以省略

// 4. 內層的花括號均可以省略

循環

Java中的循環有三種形式:while循環、do while循環、for循環。

while循環

語法:

while (循環條件) {

[迭代語句]

}

語法:

img

do while循環

語法:

do {

[迭代語句]

} while (循環條件);

流程:

img

for循環

語法:

for (初始化語句; 循環條件; 迭代語句) {

}

流程:

img

三種循環方式的區別

  1. for循環:結構穩定,不容易遺漏任何循環要素,適合處理循環次數固定的場景。
  2. while循環:先判斷循環條件,再執行循環體,適合處理「當…」的業務場景。
  3. do while循環:先執行循環體,再判斷循環條件,適合處理「直到…」的業務場景。

break與continue關鍵字

– break用於結束循環,強制跳出循環體。一旦遇到break,系統將結束該循環,開始執行循環之後的代碼。

– continue用於忽略本次循環剩下的語句,接着開始下一次循環,並不會終止循環。

數組

數組是一種常見的數據結構,用於存儲多個數據。在Java中,數組中的元素具有相同的數據類型,數組本身是一種引用數據類型。數組中的元素按線性方式排列,可以通過編號來訪問數組中的每個元素。一旦初始化完成,數組在內存中所佔的空間就固定下來,即數組的長度不可改變。數組既可以存基本類型的數據,也可以存引用類型的數據,只要類型相同即可。

數組的聲明

type[] arrayName;

type arrayName[];

數組的初始化

// 靜態初始化

// 動態初始化

arrayName = new type[length];

數組的訪問

// 訪問數組的元素

arrayName[index]; // index是數組的索引,是一個從0開始的整數。

// 獲取數組的長度

arrayName.length;

數組的遍歷

// for循環

for (int i = 0; i < array.length; i++) {

System.out.println(array[i]);

}

// foreach循環

for (type variableName : array | collection) {

System.out.println(variableName);

}

多維數組

// 聲明二維數組

type[][] arrayName;

// 初始化二維數組

arrayName = new type[] [] { {…}, {…}, … }; // 靜態初始化

arrayName = new type[outerLength] [innerLength]; // 動態初始化

// 訪問二維數組

arrayName[outerIndex] [innerIndex]; // 訪問數組的元素

arrayName.length; // 訪問外層數組的長度

arrayName[outerIndex].length; // 訪問內層數組的長度

2.面向對象

封裝

封裝可以隱藏類的實現細節,讓使用者只能通過事先預定的方法來訪問數據,從而可以在該方法里加入控制邏輯,限制對成員變量的不合理訪問。通過封裝,我們還可以在訪問數據時進行檢查,從而有利於保證對象信息的完整性。另外,合理封裝的程序便於修改,可以提高代碼的可維護性。

封裝的實現依賴於訪問修飾符,Java提供了3種訪問修飾符,分別是private、protected、public。這三種訪問修飾符以及不加修飾符的情況,一共形成了4種訪問級別:private、default、protected、public。訪問修飾符與類中成員的訪問級別如下表所示:

img

常見的封裝方式是,將一個類中的成員變量私有化,即使用private修飾成員變量,從而避免它被直接訪問到。然後為該成員變量增加賦值(set)方法和取值(get)方法,並使用public修飾這兩個方法,使得外界可以通過這兩個訪問來訪問該成員變量。在這兩個方法中,我們可以增加任意的數據處理邏輯。

class Foo {

private int count;

public void setCount(int count) {

​ this.count = count;

}

public int getCount() {

​ return count;

}

}

繼承

Java採用extends關鍵字實現繼承,實現繼承的類叫子類,被繼承的類叫父類。任何類都只能有一個直接的父類,和無數個間接的父類,而多個類可以繼承於同一個父類。若一個類沒有顯式地指定父類,則這個類默認繼承於java.lang.Object類。

重寫

子類繼承父類後,還可以從寫父類中的方法。所謂重寫,是指在子類中,定義與父類同名的方法,用來覆蓋父類中這個方法的邏輯。在重寫時,要遵守如下規範:

\1. 子類方法的名稱、參數列表與父類相同。

\2. 子類方法的返回類型與父類相同或更小。

\3. 子類方法聲明的異常與父類相同或更小。

\4. 子類方法的訪問權限與父類相同或更大。

this關鍵字

this關鍵字用於指代當前對象,它包含如下作用:調用當前對象的構造方法、調用當前對象的成員變量、調用當前對象的成員方法。在成員變量和形參的名稱產生衝突時,可以通過this來區分二者:

class Foo {

private int count;

public Foo(int count) {

​ this.count = count;

}

public void setCount(int count) {

​ this.count = count;

}

public int getCount() {

​ return count;

}

}

super關鍵字

super關鍵字包含如下作用:調用父類的成員變量、調用父類的成員方法、調用父類的構造方法。注意,super關鍵字也是指代當前對象,但用於調用該對象在父類中的成員。通過super調用構造方法時,並不會創建一個新對象。父類構造方法會在子類構造方法之前調用,並且總會被調用一次。

class Base {

void method1() {}

}

class Sub extends Base {

void method1() {}

void method2() { super.method1(); }

}

多態

在程序運行時,相同類型的變量可以呈現出不同的行為特徵,這就是多態。多態的作用在於,它可以提高程序的擴展性。需要注意,在編寫Java代碼時,我們只能調用聲明變量時所用的類型中包含的成員變量與方法。

class Base { }

class Sub1 extends Base { }

class Sub2 extends Base { }

class Sub3 extends Base { }

class Foo {

// 調用該方法時,可以傳入Base的實例,也可以傳入其任意子類的實例。

public void doSomething(Base base) { }

}

在上面的示例中,方法的參數為父類Base,而實際傳入的可能是子類的實例。如果在方法內部,需要判定該實例具體屬於哪一個子類,則可以採用instanceof關鍵字。instanceof的語法如下,它的含義是判斷變量是否符合後面的類型,或者符合後面的類型的子類、實現類。

變量 instanceof 類型

如果判定實例屬於某一個具體的子類,那麼我們就可以將其強制轉型為這個子類型。注意,這種強制類型轉換,只能在具有繼承關係的兩個類型之間進行,若試圖將符類型對象轉換為子類型,則這個對象必須實際上是子類的實例才行。

(類型) 變量;

接口和抽象類

抽象類

使用abstract關鍵字修飾的類叫抽象類,使用abstract關鍵字修飾的方法叫抽象方法,抽象方法不能有方法體。抽象類有如下規範:

\1. 抽象類中可以沒有抽象方法,但是包含抽象方法的類必須聲明為抽象類。

\2. 若子類是抽象類,可以不實現父類的抽象方法,否則必須實現父類的抽象方法。

\3. 抽象類允許有構造方法,可以在子類中調用,但是不能調用它來實例化抽象類。

接口

接口是從多個相似的類中抽象出來的規範,體現了規範和實現分離的設計哲學。接口不提供任何實現,它不能包含普通方法,接口內部定義的所有的方法都是抽象方法。而Java 8對接口進行了改進,允許在接口中定義默認方法和靜態方法,這兩類方法是可以提供方法實現的。

– 接口的定義:

[修飾符] interface 接口名 extends 父接口1, 父接口2, … { }

– 接口的成員:

接口中可以定義成員變量、成員方法(抽象方法、默認方法、靜態方法):

a. 接口中所有的成員都是public訪問權限,而public修飾符可以省略。

b. 接口中的成員變量都是靜態常量,而static final關鍵字可以省略。

c. 接口中的普通成員方法必須是抽象的,而abstract關鍵字可以省略。

d. 接口中的默認方法必須使用default修飾,靜態方法必須使用static修飾,均不能省略。

– 接口的使用

// 1. 一個類可以實現一個或多個接口,使用implements關鍵字。

// 2. 實現與繼承類似,可以獲得被實現接口裡定義的常量、方法。

// 3. 如果這個類不是抽象類,那麼它就必須實現這些接口裡所定義的全部抽象方法。

[修飾符] class 類名 extends 父類 implements 接口1, 接口2, … { }

static和final關鍵字

static

Java類中可以包含成員變量、成員方法、構造方法、初始化塊、內部類,static可以修飾其中的成員變量、成員方法、初始化塊、內部類。被static修飾的成員是類的成員,該成員屬於類,不屬於單個對象。需要注意的是,類成員不能訪問實例成員,因為可能出現類成員已經初始化完成,但實例成員還未初始化的情況。

\1. 類變量:以static修飾的成員變量叫類變量(靜態變量),類變量屬於類,它隨類的信息存儲在方法區中,而不是隨着對象存儲在堆中。類變量可以通過類名來訪問,也可以通過對象名來訪問,建議通過類名來訪問。

\2. 類方法:以static修飾的方法叫類方法(靜態方法),類方法屬於類,可以通過類名訪問,也可以通過對象名訪問,建議通過類名來訪問。

\3. 靜態塊:以static修飾的初始化塊叫靜態初始化塊,靜態塊屬於類,它在類加載的時候被隱式調用一次,之後便再也不會被調用了。

\4. 靜態內部類:被static修飾的成員內部類叫靜態內部類,靜態內部類可以包含靜態成員,也可以包含非靜態成員。靜態內部類不能訪問外部類的實例成員,只能訪問它的靜態成員。外部類的所有方法、初始化塊都能訪問其內部定義的靜態內部類。

final

final關鍵字可以用於修飾類、方法、變量。被final修飾的類不可以被繼承,被final修飾的方法不可以被重寫,被final修飾的變量,一旦獲得了初始值,就不可以被修改。

對於基本類型的變量,若final修飾的是靜態變量,則可以在聲明變量時指定初始值,也可以在靜態初始化塊中指定初始值。若final修飾的是實例變量,可以在聲明變量時指定初始值,也可以在普通初始化塊或構造方法中指定初始值。若final修飾的是局部變量,可以在聲明變量時指定初始值,也可以在後面的代碼中指定初始值。

對於引用類型的變量,由於保存的僅僅是一個引用(地址),所以final只能保證這個引用類型變量所引用的地址不會改變,但這個對象的內容是可以發生改變的。

3.常用API

String

String類是final的,所以它不存在子類。另外,String類是不可變類,就是在創建String對象後,其內部的字符序列是無法修改的。通常需要採用如下三種手段,來保證一個類的不可變:

  1. 使用private和final修飾成員變量。
  2. 提供帶參數的構造器,用於初始化上述成員變量。
  3. 僅提供獲取成員變量的方法,不提供修改的方法。

String類中定義了大量處理字符串的方法,下表列舉了比較常用的方法。其中,有很多方法是修改字符串的方法,其底層並不是真正改變了原始字符串,而是生成了新的字符串,這是字符串不可變的本意。

img

此外,String類還提供了一些支持正則表達式的方法,用於增強字符串的處理能力:

  1. boolean matches(String regex)判斷此字符串是否與指定的正則表達式(regex)匹配。
  2. String[] split(String regex)以正則表達式(regex)匹配的內容作為分隔符,將此字符串分隔成多個子串。
  3. String replaceFirst(String regex, String replacement)將此字符串中,第一個與正則表達式(regex)匹配的子串替換成目標(replacement)。
  4. String replaceAll(String regex, String replacement)將此字符串中,每一個與正則表達式(regex)匹配的子串替換成目標(replacement)。

包裝類

我們都知道,Java是面向對象的編程語言,在Java中一切皆對象。但是八種基本數據類型卻是例外的,它們不具備對象的特性。為了解決這個問題,Java為每個基本類型都定義了一個對應的引用類型,它們就是對應的基本類型的包裝類了。

img

基本類型與包裝類之間的轉換

– JDK 1.5之前:通過包裝類提供的構造器,可以將基本類型轉為包裝類型的對象。通過包裝類提供的xxxValue()方法,可以獲得該對象中包裝的數據。

– JDK 1.5之後:JDK 1.5提供了自動裝箱、自動拆箱功能。所謂自動裝箱,就是可以把一個基本類型的數據直接賦值給對應的包裝類型。所謂自動拆箱,就是可以把一個包裝類型的對象直接賦值給對應的基本類型。

包裝類的常用API

– 字符串轉為基本類型(以Integer為例)

public Integer (String s) { }

public static int parseInt(String s) { }

// 注意,Character類中沒有定義上述構造方法和靜態方法。

– 比較兩個數據的大小(以Integer為例)

public static int compare(int x, int y) { }

包裝類是不可變類

包裝類都是不可變類,就是說該類被實例化後,它的實例變量是不可改變的。通常需要採用如下三種手段,來保證一個類的不可變:

  1. 使用private和final修飾成員變量。

  2. 提供帶參數的構造器,用於初始化上述成員變量。

  3. 僅提供獲取成員變量的方法,不提供修改的方法。

包裝類的父類

img

包裝類中的靜態常量

  1. MAX_VALUE,表示該類型的最大值。

  2. MIN_VALUE,表示該類型的最小值。

Byte、Short、Integer、Long、Float、Double、Character均定義了上述常量。

數學工具

Math

算術運算符用於處理基本的數學運算,而Math類用於處理複雜的數學運算。

  1. Math類不能被實例化,它的所有成員都是靜態的,直接通過類名來訪問。

  2. Math類提供了兩個靜態常量,分別是E(自然對數的基數)和PI(圓周率)。

  3. Math類提供了對數運算、指數運算、三角函數運算等一系列支持數學運算的方法。

Random

Random類專門用於生成一個偽隨機數。

  1. 偽隨機數就是基於一個「種子」,採用特定算法計算而來的數字。

  2. 每次計算的結果將作為新的「種子」,用於生成下一個偽隨機數。

  3. Random類有兩個構造器:

– 無參構造器,使用默認的種子,即當前時間的毫秒數。

– 有參構造器,使用指定的種子,需要調用者顯式地傳入long型的整數。

Random

Random類專門用於生成一個偽隨機數。

  1. 偽隨機數就是基於一個「種子」,採用特定算法計算而來的數字。

  2. 每次計算的結果將作為新的「種子」,用於生成下一個偽隨機數。

  3. Random類有兩個構造器:

– 無參構造器,使用默認的種子,即當前時間的毫秒數。

– 有參構造器,使用指定的種子,需要調用者顯式地傳入long型的整數。

BigDecimal

浮點數是不精確的,若要精確地表示和計算浮點數,則需要使用BigDecimal類。該類提供了一系列用於精確計算的方法,例如:add()、subtract()、multiply()、divide()、pow()等。有多種創建BigDecimal實例的辦法,它們的區別如下:

// 建議使用該構造器,它的結果是可以預知的。

public BigDeclmal(String val) { }

// 不建議使用該構造器,因為它的參數是一個近似值。

public BigDecimal(double val) { }

// 若必須使用double型參數創建對象,建議使用這個靜態方法來創建實例。

public static BigDecimal valueOf(double val) { }

NumberFormat

NumberFormat用於實現數值的格式化。它提供了format()方法,可以將傳入的數值格式化為字符串。還提供了parse()方法,可以將傳入的格式字符串解析成數值。有多種創建NumberFormat實例的辦法,區別如下:

// 返回默認地區的貨幣格式器

public final static NumberFormat getCurrencyInstance() { }

// 返回默認地區的數值格式器

public final static NumberFormat getNumberInstance() { }

// 返回默認地區的百分數格式器

public final static NumberFormat getPercentInstance() { }

// 此外,上述方法均有重載方法,可以顯示地傳入參數以指定地區。

日期工具

Date

Date類用來處理日期和時間,但是該類的大部分構造器、方法均以過時。

– 常用的構造方法

// 創建代表當前時間的Date對象,底層調用System類獲取當前時間毫秒數。

public Date() { }

// 根據指定的時間毫秒數創建Date對象,參數為時間的毫秒數。

public Date(long date) { }

– 常用的成員方法

// 判斷該時間是否在指定時間之後

public boolean after(Date when) { }

// 判斷該時間是否在指定時間之前

public boolean before(Date when) { }

// 返回該時間的毫秒數

public long getTime() { }

// 以毫秒數的形式,設置該Date對象所代表的時間。

public void setTime(long time) { }

Calendar

相比於Date類,Calendar類可以更好地處理日期和時間。Calendar是一個抽象類,所以不能通過構造器創建Calendar對象。Calendar類提供了靜態方法getInstance(),用以創建實例。

– Calendar類提供了與Date互轉的方法

// 返回Date

public final Date getTime() { }

// 將Date轉為Calendar

public final void setTime(Date date) { }

– Calendar類常用的成員方法

// 返回指定字段的值

public int get(int field) {}

// 給指定的字段設置一個值

public void set(int field, int amount) {}

// 設置年月日的值

public void set(int year, int month, int date) {}

// 設置年月日時分秒的值

public void set(int year, int month, int date, int hourOfDay, int minute, int second) {}

– Calendar類常用的靜態變量

YEAR, MONTH, DATE, HOUR, MINITE, SECOND, MILLISECOND。

DateFormat

DateFormat用於實現日期的格式化,它是一個抽象類,提供了如下靜態方法以創建實例:

// 返回日期格式器

public final static DateFormat getDateInstance() {}

// 返回時間格式器

public final static DateFormat getTimeInstance() {}

// 返回日期時間格式器

public final static DateFormat getDateTimeInstance() {}

同時,DateFormat提供了如下常用的成員方法:

// 將傳入的日期格式化為字符串

public final String format(Date date) {}

// 將傳入的格式字符串解析為日期

public Date parse(String source) throws ParseException {}

SimpleDateFormat

SimpleDateFormat是DateFormat的子類,提供了更簡單的格式化方案,該類提供了如下常用的構造器,常用的成員方法則與DateFormat一致。

// pattern是一個日期模板字符串,如「yyyy-MM-dd HH:mm:ss」

public SimpleDateFormat(String pattern) {}

異常處理

Java語言具有如下的異常處理機制:當程序運行出現意外情形時,系統會自動生成一個異常對象來通知程序。在程序中,我們可以使用特定的語句來捕獲異常對象,讀取對象中的信息,進而做出處理。也可以使用特定的語句拋出異常對象,將這個異常對象交給程序的調用者處理。

異常的繼承體系

img

– 所有的非正常情況被分為兩類:

錯誤(Error)和異常(Exception),其中Error代表虛擬機相關問題,一般無法處理,也無需處理。

– 所有的 Exception 被分為兩類

a. RuntimeException,代表運行時異常,程序可以顯式處理這種異常,也可以不處理,而是交給頂層調用者統一處理。

b. 非運行時異常(Checked異常),程序必須顯式地處理這種異常,否則在編譯階段會發生錯誤,導致程序無法通過編譯。

捕獲異常

語法:

try {

​ 業務邏輯代碼

}

catch (AException e) {

​ A異常的處理代碼

}

catch (BException e) {

​ B異常的處理代碼

}

finally {

​ 回收資源代碼

}

說明:

  1. 無論哪行代碼發生異常,系統都會生成一個異常對象,這與try…catch…語句沒有關係;

  2. 若程序沒有對這個異常對象做任何處理,則程序在此退出;

  3. 創建異常對象後,JVM會尋找可以處理它的catch塊,並將異常對象交給這個catch塊去處理;

  4. 程序應該先處理小異常、再處理大異常,即將處理父類異常的catch塊放在處理子類異常的catch塊之後;

  5. finally塊中代碼總是會被執行,它必須位於try、catch之後,通常用來釋放資源;

  6. try是必須的,catch、finally是可選的,但catch、finally二者之中至少要出現一個。

聲明拋出異常

語法:

throws ExceptionClass1, ExceptionClass2, …

說明:

  1. throws語句用於標識某方法可能拋出的異常,它必須位於方法簽名之後;

  2. throws語句聲明拋出異常後,程序中舊無需使用try語句捕獲該異常了;

  3. 在重寫時,子類方法聲明拋出的異常類型不能比父類方法聲明拋出的異常類型大。

拋出異常

語法:

throw ExceptionInstance;

說明:

  1. throw語句用於在程序中主動拋出一個異常;

  2. throw語句拋出的不是異常類型,而是一個異常實例;

  3. 對於主動拋出的異常,也可以採用try塊捕獲,或者採用throws語句向外拋出。

異常的處理原則

  1. 不要多度的使用異常:

不要用異常處理代替錯誤處理代碼,不要用異常處理代替流程控制語句;

  1. 不要忽略捕獲的異常:

對於捕獲到的異常,要進行合適的修復,對於不能處理的部分,應該拋出新的異常;

  1. 不要直接捕獲所有的異常:

應對不同的異常做出有針對性的處理,而捕獲所有的異常,容易壓制(丟失)異常;

  1. 不要使用過於龐大的try塊:

龐大的try塊會導致業務過於複雜,不利於分析異常的原因,也不利於程序的閱讀及維護。

4.集合類

Set

Set接口代表無序不可重複集合。Set集合通常記不住元素的添加順序,並且Set集合不允許包含相同的元素,向Set中加入相同元素時會失敗,即方法返回false。Set接口常用的實現類有:HashSet、TreeSet。

HashSet是Set接口的典型實現,它具有以下特點:

  1. HashSet不能保證元素的排列順序;

  2. HashSet集合元素的值可以是 null;

  3. HashSet是非線程安全的,多線程環境下須通過代碼來保證其同步。

TreeSet可以保證元素的排列順序,它比HashSet多了一些方法:

  1. 返回集合中第一個/最後一個元素;

  2. 返回集合中位於指定元素之前/之後的元素;

  3. 返回集合中某個限定範圍內的元素組成的子集。

TreeSet採用紅黑樹的數據結構來存儲元素,它支持兩種排序方式:自然排序、定製排序。

  1. 自然排序:

– 添加時,調用元素的compareTo方法比較元素的大小,並按照升序排列元素;

– 添加到TreeSet中的對象必須實現Comparable接口,該接口定義了compareTo方法;

– Java提供的很多類型均已經實現了Comparable接口,如包裝類、String、Date等。

  1. 定製排序:

– 創建TreeSet時,傳入Comparator接口的實例;

– Comparator接口定義了compare方法,用於比較兩個對象的大小;

– TreeSet不再調用compareTo方法,轉而調用compare方法比較大小。

List

List接口代表有序集合,它提供了根據索引來訪問集合的方法:

  1. 將元素插入到集合中指定的索引處;

  2. 將指定索引處的元素從集合中刪除;

  3. 從集合中返回指定索引處的元素;

  4. 返回某個元素在集合中的索引值;

  5. 從集合中,返回起始索引和結束索引之間的元素所組成的子集。

List還提供了一個listIterator方法,以返回一個ListIterator對象。ListIterator是一個接口,它繼承於Iterator接口,並增加了如下的方法:

boolean hasPrevious(); // 判斷迭代器指向的元素是否有上一個元素

E previous(); // 返回該迭代器所指向的元素的上一個元素

boolean hasNext(); // 判斷迭代器指向的元素是否有下一個元素

E next(); // 返回該迭代器所指向的元素的下一個元素

void add(E e); // 在迭代器所指向的元素位置插入一個元素

List接口常用實現類有ArrayList、LinkedList,ArrayList是採用數組實現有序集合,LinkedList是採用鏈表實現的有序集合。數組和鏈表的區別在於:

– 數組需要佔據連續的內存空間,訪問效率高、增刪效率低;

– 鏈表不必佔據連續的內存空間,增刪效率高、訪問效率低,它以指針維護元素的順序,即上一個元素會指向下一個元素。

Queue

Queue接口用於模擬隊列,它是一種先進先出(FIFO)的容器,常用的方法見下方表格:

img

Queue接口包含如下子接口和實現類:

img

  1. PriorityQueue是一種不標準的隊列實現,它不是按照加入的順序來保存元素,而是按照元素的大小排序來保存元素;

  2. Deque接口代表雙端隊列,它允許你從隊列頭/尾的任何一端,來進行入隊/出隊操作,甚至還支持入棧/出棧的操作;

  3. ArrayDeque、LinkedList是Deque接口的實現類,前者採用數組實現雙端隊列,而後者採用鏈表結構實現雙端隊列

Map

Map接口用於保存具有映射關係的數據(key-value),key和value之間存在單向一對一關係,通過指定的key,總能找到確定的value。Map的key不允許重複,同一個Map的任何兩個key通過equals比較總返回false。

如下圖,Map接口具有如下實現類,其中較為常用的是HashMap和TreeMap。

img

HashMap

HashMap是Map接口的典型實現:

  1. HashMap是非線程安全的,其性能高於Hashtable;

  2. HashMap允許使用null作為key/value,而Hashtable不允許存入null。

TreeMap

TreeMap是一個紅黑樹的數據結構,在存儲鍵值對時,它按照key對鍵值對排序。

  1. 自然排序:對key進行比較,並根據key按照由小到大的順序排列鍵值對。所有的key應該是同一個類型,且必須實現Comparable接口。

  2. 定製排序:創建TreeMap時,傳入一個Comparator類型的對象,該對象負責對所有的key進行比較,此時不要求key實現Comparable接口。

Collections

Collections是一個操作集合的工具類,它提供了4類集合操作:

  1. 強大的排序功能:針對List集合提供了眾多排序方法;

  2. 查找與替換功能:針對Collection提供了眾多查找和替換元素的方法;

  3. 創建不可變集合:提供3類方法(空的/唯一/只讀)來創建一個不可變的集合;

  4. 線程同步的集合:將指定的集合包裝成線程同步的集合,以解決線程安全問題。