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