1. 程式人生 > >Java核心技術第一週學習總結

Java核心技術第一週學習總結

第三章:Java的基本程式設計結構

一、基本資料型別

列舉

byte(位元組型)、short(短整型)、int(整型)、long(長整型)、float(單精度浮點型)、double(雙精度浮點型)、boolean(布林型)、char(字元型)

對應包裝類

java.lang.Byte、java.lang.Short、java.lang.Integer、java.lang.Long、java.lang.Float、java.lang.Double、java.lang.Boolean、java.lang.Character

詳細劃分

具體可分為四類

整型 byte short int long

浮點型 float double

邏輯型 boolean(它只有兩個值可取 true false)

字元型 char

二、運算子

與其他程式語言基本一樣

三、字串

1、String類

字串查詢

String提供了兩種查詢字串的方法,即indexOf與lastIndexOf方法。

 1、indexOf(String s) 

    該方法用於返回引數字串s在指定字串中首次出現的索引位置,當呼叫字串的indexOf()方法時,會從當前字串的開始位置搜尋s的位置;如果沒有檢索到字串s,該方法返回-1

1 String str ="We are students"; 2 int size = str.indexOf("a"); // 變數size的值是3

  2、lastIndexOf(String str)

    該方法用於返回字串最後一次出現的索引位置。當呼叫字串的lastIndexOf()方法時,會從當前字串的開始位置檢索引數字串str,並將最後一次出現str的索引位置返回。如果沒有檢索到字串str,該方法返回-1.

    如果lastIndexOf方法中的引數是空字串"" ,,則返回的結果與length方法的返回結果相同。

獲取指定索引位置的字元

    使用charAt()方法可將指定索引處的字元返回。

1 String str = "hello word"; 2 char mychar = str.charAt(5); // mychar的結果是w

獲取子字串

   通過String類的substring()方法可對字串進行擷取。這些方法的共同點就是都利用字串的下標進行擷取,且應明確字串下標是從0開始的。在字串中空格佔用一個索引位置。

1、substring(int beginIndex)

    該方法返回的是從指定的索引位置開始擷取知道該字串結尾的子串。

1 String str = "Hello word"; 2 String substr = str.substring(3); //獲取字串,此時substr值為lo word

2、substring(int beginIndex,  int endIndex)

    beginIndex : 開始擷取子字串的索引位置

    endIndex:子字串在整個字串中的結束位置

1 String str = "Hello word"; 2 String substr = str.substring(0,3); //substr的值為hel

去除空格

    trim()方法返回字串的副本,忽略前導空格和尾部空格。

字串替換

    replace()方法可實現將指定的字元或字串替換成新的字元或字串

   oldChar:要替換的字元或字串

  newChar:用於替換原來字串的內容

如果要替換的字元oldChar在字串中重複出現多次,replace()方法會將所有oldChar全部替換成newChar。需要注意的是,要替換的字元oldChar的大小寫要與原字串中字元的大小寫保持一致。

1 String str= "address"; 2 String newstr = str.replace("a", "A");// newstr的值為Address

判斷字串的開始與結尾

    startsWith()方法與endsWith()方法分別用於判斷字串是否以指定的內容開始或結束。這兩個方法的返回值都為boolean型別。

   1、startsWith(String prefix) 

      該方法用於判斷當前字串物件的字首是否是引數指定的字串。

   2、endsWith(String suffix) 

     該方法用於判斷當前字串是否以給定的子字串結束

判斷字串是否相等

    1、equals(String otherstr)

    如果兩個字串具有相同的字元和長度,則使用equals()方法比較時,返回true。同時equals()方法比較時區分大小寫。

   2、equalsIgnoreCase(String otherstr)

    equalsIgnoreCase()方法與equals()型別,不過在比較時忽略了大小寫。

按字典順序比較兩個字串

compareTo()方法為按字典順序比較兩個字串,該比較基於字串中各個字元的Unicode值,按字典順序將此String物件表示的字元序列與引數字串所表示的字元序列進行比較。如果按字典順序此String物件位於引數字串之前,則比較結果為一個負整數;如果按字典順序此String物件位於引數字串之後,則比較結果為一個正整數;如果這兩個字串相等,則結果為0.

1 str.compareTo(String otherstr);

字母大小寫轉換

    字串的toLowerCase()方法可將字串中的所有字元從大寫字母改寫為小寫字母,而tuUpperCase()方法可將字串中的小寫字母改寫為大寫字母。

1 str.toLowerCase(); 2 str.toUpperCase();

字串分割

    使用split()方法可以使字串按指定的分隔字元或字串對內容進行分割,並將分割後的結果存放在字元陣列中。

1 str.split(String sign);

sign為分割字串的分割符,也可以使用正則表示式。

沒有統一的對字串進行分割的符號,如果想定義多個分割符,可使用符號“|”。例如,“,|=”表示分割符分別為“,”和“=”。

1 str.split(String sign, in limit);

該方法可根據給定的分割符對字串進行拆分,並限定拆分的次數。

2、StringBuilder類和StringBuffer類

StringBuilder和StringBuffer一樣,都是繼承自抽象類AbstractStringBuilder類,也是一個可變的字元序列。StringBuilder和StringBuffer非常相似,甚至有互相相容的API,不過,StringBuilder不是執行緒安全的,這是和StringBuffer的主要區別 。

內部方法很多與String類一樣,具體可以檢視javadocs

四、陣列

1)陣列在Java中是一個物件,陣列例項同樣是使用new操作符建立的。Array.length指定了陣列長度,例如:

1

2

3

4

int[] intArray = new int[10];

System.out.println(intArray.length)

Output: 10

 

Array.length 表示陣列的容量,只要陣列建立了,每一個索引被初始化為預設值。

2)陣列索引起始為0,負數索引在Java中是無效的,會丟擲ArrayIndexOutOfBoundException ,如果你嘗試用無效的索引訪問陣列,這個無效的索引可能是一個負索引,或者是大於等於陣列長度的索引。

3)陣列儲存在Java堆的連續記憶體空間,所以如果你建立一個大的索引,你可以有足夠的堆空間直到丟擲OutofmemoryError,因為請求的記憶體大小在連續的記憶體空間不可用。

4)陣列一個固定長度 的資料結構,一旦宣告,你不能改變陣列的長度。

5)不同型別的陣列有不同的型別,例如下面例子,intArray.getClass()不同於floatArray.getClass()

1

2

int[] intArray = new int[10];

float[] floatArray = new float[10];

1

6)你不能儲存double值在int陣列中,否則導致編譯錯誤。

1

2

int[] intArray = new int[10];

int Array[5]=1.2; //compilation error

如果嘗試在執行時做這個操作,那麼Java丟擲ArrayStoreException

7)在Java陣列中可以有不同方式的建立方式,這裡就是建立陣列的例子:

1

2

3

4

int[] intArray;   //creating array without initializing or specifying size

int intArray1[];  //another int[] reference variable can hold reference of an integer array

int[] intArray2 = new int[10]; //creating array by specifying size

int[] intArray3 = new int[]{1,2,3,4}; //creating and initializing array in same line.

你既可以選擇在建立陣列的時候初始化陣列,也可以以後通過for迴圈初始化,中括號既可以在變數的前面也可以在變數後面。

第一種方法是方便的建立多個數組如:

int[] array1, array2

這裡的array1和array2是整型陣列,而第二種方法你需要放兩次括號如:

int array1[], array2[]

儘管在風格上沒有很多不同,我讀“int[] ”叫int陣列,這種寫法更容易被理解。

8)如果沒有明確的初始化陣列元素,那麼陣列就會用預設的型別值初始化,例如假若沒有初始化整型陣列,元素都將預設值為0,沒有初始化的boolean值是false,物件陣列是null。

9)你可以通過使用[]操作符訪問陣列元素,因為陣列索引起始於0,[0]返回第一個元素,[length-1]返回最後一個元素,for迴圈是一種迭代整個陣列便捷方法。你可以使用for迴圈初始化整個陣列、訪問的每個索引或更新、獲取陣列元素。Java5同樣提供了加強的for迴圈,陣列自己管理索引,防止ArrayIndexOutOfBoundException,這裡是一個迭代的例子:

傳統的方式:

1

2

3

4

5

6

7

8

9

10

11

12

int[] numbers = new int[]{10, 20, 30, 40, 50};

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

System.out.println("element at index " + i + ": " + numbers[i]);

}

Output:

element at index 0: 10

element at index 1: 20

element at index 2: 30

element at index 3: 40

element at index 4: 50

 

加強的for迴圈

1

2

3

4

5

6

7

8

9

10

for(int i: numbers){

System.out.println(i);

}

Output:

10

20

30

40

50

正如你看到的,加強的for迴圈不需要檢查陣列索引,如果你想逐個地訪問所有的元素這是一種很好的方法,但是同時因為你不能訪問索引,你就不能修改陣列元素。

10)Java中陣列可以輕易的轉換成ArrayList。ArrayList一個基於索引的集合,它是作為陣列的備選方案。ArrayList的優點是可以改變容量大小,只需要建立個更大的陣列然後拷貝內容到新陣列,但你不能改變陣列的大小。

11)Java API同樣提供了一些便捷方法通過java.utils.Arrays類去運算元組,通過使用Arrays你可以排序陣列,你可以做二分搜尋。

12)java.lang.System類提供了實用方法拷貝元素到另一個數組。在拷貝內容從一個數組到另一個數組的時候System.arrayCopy非常強大和靈活。你可以拷貝整個或子陣列,具體看你的需求。

System.arraycoy語法:

1

public static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length)

如你所見,arraycopy允許我們指定索引和長度,能很靈活給你拷貝子陣列和儲存到需要的位置或目標陣列。這裡是一個例子,拷貝前三個元素到目標陣列:

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

public static void main(String args[]) {

int[] source = new int[]{10, 20, 30, 40, 50};

int[] target = new int[5];

System.out.println("Before copying");

for(int i: target){

System.out.println(i);

}

System.arraycopy(source, 0, target, 0, 3);

System.out.println("after copying");

for(int i: target){

System.out.println(i);

}

}

Output:

Before copying

0

0

0

0

0

after copying

10

20

30

0

0

你可以看到拷貝之前所有元素是0,之後前三個元素被替換了。

13)Java同樣支援多維陣列,在表示2D和3D的時候非常有用,像行和列或矩陣。多維陣列也是一個數組的陣列,這裡是建立多維陣列的例子:

1

int[][] multiArray = new int[2][3];

這是陣列有2行3列,或者說長度是2的陣列中,它的每個元素裡儲存的是長度為3的陣列,這裡是初始化多維陣列的例子:

1

2

3

int[][] multiArray = {{1,2,3},{10,20,30}};

System.out.println(multiArray[0].length);

System.out.println(multiArray[1].length);

14)陣列是一種非常快的資料結構,如果你已經知道元素的長度,那麼就應該使用陣列而非ArrayList等資料結構。

第四章:物件與類

1、靜態域

如果將域定義為static,每個類中只有一個這樣的域。而每個物件對於所有的例項域缺都有一份自己的拷貝。

程式碼塊

/**
 * @author: ------
 * @date: 2018/11/29
 * @description:
 */
public class T {
    private static int staticId = 0;
    private int id;
}

現在每一個T的物件都有一個自己的id域,但是這個類的所有例項都將共享一個staticId域。即使沒有一個T物件,這個staticId也是存在的。它屬於類。而不屬於任何一個獨立的物件

2、靜態常量

程式碼塊

public class Math {
        public final static double PI = 3.1415926;
}

3、靜態方法

靜態方法是一種不能向物件實施操作的方法。可以認為靜態方法是一種沒有this引數的方法(在一個非靜態的方法中,this引數表示這個方法的隱式引數)。

在下面兩種情況需要使用靜態方法:

  • 一個方法不需要訪問物件狀態,其所需引數都是通過顯示引數提供

  • 一個方法只需要訪問類的靜態域

4、物件析構和finalize方法

Java有自動的垃圾回收器,不需要人工回收記憶體,所以Java不支援析構器。某些物件使用了記憶體之外的其他資源,例如。檔案或者使用了系統資源的另一個物件的控制代碼。在這種情況下,當資源不再需要的時候,將其回收和再利用將顯得十分重要。可以為任何一個類新增finalize方法,finalize方法將在垃圾回收器清楚物件之前呼叫。在實際應用中,不要依賴於十月finalize方法回收任何短缺的資源,這是因為很難找到這個方法什麼方法才能呼叫。

第五章 繼承

1、final類和方法:阻止繼承

2、多型

多型存在的三個必要條件:
一、要有繼承;
二、要有重寫;
三、父類引用指向子類物件。

Java中多型的實現方式:
介面實現
繼承父類進行方法重寫
同一個類中進行方法過載

3、列舉類

在某些情況下,一個類的物件時有限且固定的,如季節類,它只有春夏秋冬4個物件這種例項有限且固定的類,在 Java 中被稱為列舉類;

  • 在 Java 中使用 enum 關鍵字來定義列舉類,其地位與 class、interface 相同;

  • 列舉類是一種特殊的類,它和普通的類一樣,有自己的成員變數、成員方法、構造器 (只能使用 private 訪問修飾符,所以無法從外部呼叫構造器,構造器只在構造列舉值時被呼叫);

  • 一個 Java 原始檔中最多隻能有一個 public 型別的列舉類,且該 Java 原始檔的名字也必須和該列舉類的類名相同,這點和類是相同的;

  • 使用 enum 定義的列舉類預設繼承了 java.lang.Enum 類,並實現了 java.lang.Seriablizable 和 java.lang.Comparable 兩個介面;

  • 所有的列舉值都是 public static final 的,且非抽象的列舉類不能再派生子類;

  • 列舉類的所有例項(列舉值)必須在列舉類的第一行顯式地列出,否則這個列舉類將永遠不能產生例項。列出這些例項(列舉值)時,系統會自動新增 public static final 修飾,無需程式設計師顯式新增。

第六章 介面、lambda表示式與內部類


介面:在Java程式語言中是一個抽象型別(Abstract Type),它被用來要求類(Class)必須實現指定的方法,使不同類的物件可以利用相同的介面進行溝通。介面通常以interface來宣告,它僅能包含方法簽名(Method Signature)以及常量宣告(變數宣告包含了 static 及 final),一個介面不會包含方法的實現(僅有定義)。

介面無法被例項化,但是可以被實現。一個實現介面的類,必須實現介面內所描述的所有方法,否則就必須宣告為抽象類(Abstract Class)。另外,在Java中,介面型別可用來宣告一個變數,他們可以成為一個空指標,或是被繫結在一個以此介面實現的物件。

其中一個使用介面的優勢是,可以利用他們模擬多重繼承,類在JAVA中不允許多重繼承,所有在JAVA中的類必須而且僅能有一個父類,而java.lang.Object(JAVA型別系統中最頂層的型別)是唯一一個例外。

JAVA的類可以被實現許多個介面,然而一個介面則無法實現其他的介面
lambda表示式:

示例1:用lambda表示式實現Runable

開始使用Java 8時,首先做的就是使用lambda表示式替換匿名類,而實現Runnable介面是匿名類的最好示例。看一下Java 8之前的runnable實現方法,需要4行程式碼,而使用lambda表示式只需要一行程式碼。我們在這裡做了什麼呢?那就是用() -> {}程式碼塊替代了整個匿名類

程式碼塊

// Java 8之前:
new Thread(new Runnable() {
    @Override
    public void run() {
    System.out.println("Before Java8, too much code for too little to do");
    }
}).start();
//Java 8方式:
new Thread( () -> System.out.println("In Java8, Lambda expression rocks !!") ).start();
輸出:
Before Java8,too much code, for too little to do
Lambda expression rocks !!
示例2:使用lambda表示式對列表進行迭代

如果你使過幾年Java,你就知道針對集合類,最常見的操作就是進行迭代,並將業務邏輯應用於各個元素,例如處理訂單、交易和事件的列表。由於Java是命令式語言,Java 8之前的所有迴圈程式碼都是順序的,即可以對其元素進行並行化處理。如果你想做並行過濾,就需要自己寫程式碼,這並不是那麼容易。通過引入lambda表示式和預設方法,將做什麼和怎麼做的問題分開了,這意味著Java集合現在知道怎樣做迭代,並可以在API層面對集合元素進行並行處理。下面的例子裡,我將介紹如何在使用lambda或不使用lambda表示式的情況下迭代列表。你可以看到列表現在有了一個 forEach()  方法,它可以迭代所有物件,並將你的lambda程式碼應用在其中

程式碼塊

// Java 8之前:
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
for (String feature : features) {
    System.out.println(feature);
}
​
// Java 8之後:
List features = Arrays.asList("Lambdas", "Default Method", "Stream API", "Date and Time API");
features.forEach(n -> System.out.println(n));

// 使用Java 8的方法引用更方便,方法引用由::雙冒號操作符標示,
// 看起來像C++的作用域解析運算子
features.forEach(System.out::println);

示例3:使用lambda表示式和函式式介面Predicate

除了在語言層面支援函數語言程式設計風格,Java 8也添加了一個包,叫做 java.util.function。它包含了很多類,用來支援Java的函數語言程式設計。其中一個便是Predicate,使用 java.util.function.Predicate 函式式介面以及lambda表示式,可以向API方法新增邏輯,用更少的程式碼支援更多的動態行為。下面是Java 8 Predicate 的例子,展示了過濾集合資料的多種常用方法。Predicate介面非常適用於做過濾。

程式碼塊

public static void main(args[]){
    List languages = Arrays.asList("Java", "Scala", "C++", "Haskell", "Lisp");

    System.out.println("Languages which starts with J :");
    filter(languages, (str)->str.startsWith("J"));

    System.out.println("Languages which ends with a ");
    filter(languages, (str)->str.endsWith("a"));

    System.out.println("Print all languages :");
    filter(languages, (str)->true);

    System.out.println("Print no language : ");
    filter(languages, (str)->false);

    System.out.println("Print language whose length greater than 4:");
    filter(languages, (str)->str.length() > 4);
}

public static void filter(List names, Predicate condition) {
    for(String name: names)  {
        if(condition.test(name)) {
            System.out.println(name + " ");
        }
    }
}
​

輸出:

程式碼塊

Languages which starts with J :
Java
Languages which ends with a
Java
Scala
Print all languages :
Java
Scala
C++
Haskell
Lisp
Print no language :
Print language whose length greater than 4:
Scala
Haskell
​
// 更好的辦法
public static void filter(List names, Predicate condition) {
    names.stream().filter((name) -> (condition.test(name))).forEach((name) -> {
        System.out.println(name + " ");
    });
}

可以看到,Stream API的過濾方法也接受一個Predicate,這意味著可以將我們定製的 filter() 方法替換成寫在裡面的內聯程式碼,這就是lambda表示式的魔力。另外,Predicate介面也允許進行多重條件的測試,下個例子將要講到

示例4:Java 8中使用lambda表示式的Map和Reduce示例

本例介紹最廣為人知的函數語言程式設計概念map。它允許你將物件進行轉換。例如在本例中,我們將 costBeforeTax 列表的每個元素轉換成為稅後的值。我們將 x -> x*x lambda表示式傳到 map() 方法,後者將其應用到流中的每一個元素。然後用 forEach() 將列表元素打印出來。使用流API的收集器類,可以得到所有含稅的開銷。有 toList() 這樣的方法將 map 或任何其他操作的結果合併起來。由於收集器在流上做終端操作,因此之後便不能重用流了。你甚至可以用流API的 reduce() 方法將所有數字合成一個,下一個例子將會講到。

程式碼塊​

// 不使用lambda表示式為每個訂單加上12%的稅
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
for (Integer cost : costBeforeTax) {
    double price = cost + .12*cost;
    System.out.println(price);
}

// 使用lambda表示式
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
costBeforeTax.stream().map((cost) -> cost + .12*cost).forEach(System.out::println);

在上個例子中,可以看到map將集合類(例如列表)元素進行轉換的。還有一個 reduce() 函式可以將所有值合併成一個。Map和Reduce操作是函數語言程式設計的核心操作,因為其功能,reduce 又被稱為摺疊操作。另外,reduce 並不是一個新的操作,你有可能已經在使用它。SQL中類似 sum()、avg() 或者 count() 的聚集函式,實際上就是 reduce 操作,因為它們接收多個值並返回一個值。流API定義的 reduceh() 函式可以接受lambda表示式,並對所有值進行合併。IntStream這樣的類有類似 average()、count()、sum() 的內建方法來做 reduce 操作,也有mapToLong()、mapToDouble() 方法來做轉換。這並不會限制你,你可以用內建方法,也可以自己定義。在這個Java 8的Map Reduce示例裡,我們首先對所有價格應用 12% 的VAT,然後用 reduce() 方法計算總和。

程式碼塊

// 為每個訂單加上12%的稅
// 老方法:
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double total = 0;
for (Integer cost : costBeforeTax) {
    double price = cost + .12*cost;
    total = total + price;
}
System.out.println("Total : " + total);

// 新方法:
List costBeforeTax = Arrays.asList(100, 200, 300, 400, 500);
double bill = costBeforeTax.stream().map((cost) -> cost + .12*cost).reduce((sum, cost) -> sum + cost).get();
System.out.println("Total : " + bill);

示例5:通過過濾建立一個String列表

過濾是Java開發者在大規模集合上的一個常用操作,而現在使用lambda表示式和流API過濾大規模資料集合是驚人的簡單。流提供了一個 filter() 方法,接受一個 Predicate 物件,即可以傳入一個lambda表示式作為過濾邏輯。下面的例子是用lambda表示式過濾Java集合,將幫助理解。

1

2

3

// 建立一個字串列表,每個字串長度大於2

List<String> filtered = strList.stream().filter(x -> x.length()> 2).collect(Collectors.toList());

System.out.printf("Original List : %s, filtered list : %s %n", strList, filtered);

輸出:

1

Original List : [abc, , bcd, , defg, jk], filtered list : [abc, bcd, defg]

另外,關於 filter() 方法有個常見誤解。在現實生活中,做過濾的時候,通常會丟棄部分,但使用filter()方法則是獲得一個新的列表,且其每個元素符合過濾原則。

 

示例6:對列表的每個元素應用函式

我們通常需要對列表的每個元素使用某個函式,例如逐一乘以某個數、除以某個數或者做其它操作。這些操作都很適合用 map() 方法,可以將轉換邏輯以lambda表示式的形式放在 map() 方法裡,就可以對集合的各個元素進行轉換了,如下所示。

程式碼塊

// 將字串換成大寫並用逗號連結起來
List<String> G7 = Arrays.asList("USA", "Japan", "France", "Germany", "Italy", "U.K.","Canada");
String G7Countries = G7.stream().map(x -> x.toUpperCase()).collect(Collectors.joining(", "));
System.out.println(G7Countries);

示例7:計算集合元素的最大值、最小值、總和以及平均值

IntStream、LongStream 和 DoubleStream 等流的類中,有個非常有用的方法叫做 summaryStatistics() 。可以返回 IntSummaryStatistics、LongSummaryStatistics 或者 DoubleSummaryStatistic s,描述流中元素的各種摘要資料。在本例中,我們用這個方法來計算列表的最大值和最小值。它也有 getSum() 和 getAverage() 方法來獲得列表的所有元素的總和及平均值。

程式碼塊

//獲取數字的個數、最小值、最大值、總和以及平均值
List<Integer> primes = Arrays.asList(2, 3, 5, 7, 11, 13, 17, 19, 23, 29);
IntSummaryStatistics stats = primes.stream().mapToInt((x) -> x).summaryStatistics();
System.out.println("Highest prime number in List : " + stats.getMax());
System.out.println("Lowest prime number in List : " + stats.getMin());
System.out.println("Sum of all prime numbers : " + stats.getSum());
System.out.println("Average of all prime numbers : " + stats.getAverage());

 

 

lambda部分引入:http://www.importnew.com/16436.html