JAVA SE 學習筆記
Java SE-北京聖思園教學視訊
1. Java的分類:
l Java SE:Java Standard Edition
l Java ME: Java Micro Edition
l Java EE:Java Enterprise Edition
2. 相關術語:
JDK:Java Development Kit (Java開發必備)
JRE:Java Runtime Environment (Java執行環境)
JDK包含了JRE。
3. Java程式執行步驟:
Java程式的執行過程分為兩步:
1. 編譯:java **.java
2. 執行:javac **(注意,
Class檔案是位元組碼檔案,程式最終執行的就是這個位元組碼(bytecode)檔案。
4. Java是跨平臺的語言,真正執行的不是二進位制程式碼,而是位元組碼。
JVM(Java Virtual Machine,Java虛擬機器)
Java是跨平臺的,而JVM不是跨平臺的(JVM是由C語言編寫的)
Java之所以能夠做到跨平臺,本質原因在於JVM不是跨平臺的。
5. Java資料型別分為兩類:
原生資料型別和引用資料型別。
Java中原生資料型別供8種:
l byte(8bit) 、int(32bit)、short(16bit) 、long(64bit)、float、double、char、boolean
6. 型別相互賦值問題:
可以將小範圍的變數賦值給大範圍的變數,大範圍的賦值給小範圍的,必須通過強制型別轉換。
7. 當多種變數參與運算時,結果取決於最高範圍變數的型別。
8. 取模運算的符號總是與被除數相同,例如5%-3=2;
9. 邏輯運算子的短路特性:
邏輯與:如果第一個運算元為false,結果肯定為false。因此,不執行後面的運算。
邏輯或:如果第一個為true,結果肯定為true。因此,不執行後面的操作。
10. 三元表示式:
Type d = a ? b : c;
11. do while 與while的區別:
do while 至少執行一次,while則需要根據判定條件決定是否能夠執行一次。
12. 面向物件特徵:封裝(Encapsulation)、繼承(Inheritence)、多型(Polymorphism)
13. 封裝:將資料與操縱資料的方法放在一個類中就構成了封裝。
|-屬性定義在類中,又稱之為成員變數;定義在方法中的變數叫做區域性變數。區域性變數在使用的時候必須進行宣告並賦值;成員變數在使用前必須宣告,但是可以不賦值,其值由Java編譯器視其型別而定。
|-每個類物件都有自己的屬性,但無論一個類有多少個物件,這些物件共享一個方法。(屬性一個物件一份,方法共享一份)
|-Java中的方法引數傳遞,無論是原生型別還是引用型別,傳遞的型別都是傳值(這裡需要注意的是,對於引用型別,傳值傳遞的是其地址值,Java中沒有傳引用的概念)。Person p1 = new Person(); Person p2 = p1;這裡的賦值指的是物件地址的賦值。例子如下:
public class Test { Public void change(Person person, Person person2) { Person.name=”lisi”; Person2.name=”wangwu”; } Public static void main(String[] args) { Person person = new Person(); Person.name=”zhangsan”; Person person2 = person;//這裡是傳地址 Test test = new Test(); System.out.println(person.name); } } |
結果輸出為wangwu。 |
|-構造方法用於完成物件屬性的初始化工作,其特點如下:
1. 構造方法的名稱與類名相同;
2. 構造方法沒有返回值;
3. 如果定義一個類時沒有宣告構造方法,那麼編譯器會自動生成預設的建構函式,無引數,無函式體。如果定義類的時候自定義一了構造方法,那麼編譯器就不會生成預設的無參構造函數了。
4. 構造方法不能顯式呼叫,可以通過new關鍵字隱式呼叫。
|-new關鍵字完成的工作:
1. 為物件開闢記憶體
2. 呼叫類的構造方法
3. 將生成的類物件的地址返回
|-一個原始檔中可以定義多個類,但是隻有一個類的修飾為public,並且該檔案的名字為public的類名.java。
14. 方法過載:
同一個類中,兩個或者多個方法的名字形同,引數不同(引數個數不同,引數型別不同,引數順序不同)。方法的返回值對於過載沒有任何影響。在構造方法中呼叫另外一個建構函式,可以使用this()的方式呼叫,其中括號中的引數表示傳遞給該構造方法的引數,並且this語句必須是當前方法的第一行語句。
15. 繼承(Inheritance):
|-Java是單繼承的,使用extends完成子類繼承父類。Java預設繼承java.lang.Objece類。
|-當生成子類時,Java預設呼叫父類不帶引數的構造方法。如想呼叫父類特定的一個構造方法,可以使用super()方法,其中,括號中表示傳遞給父類的構造方法的引數值。與this()相同,super()方法也必須是方法語句塊中的第一句。
|-父類有的,子類一定有;父類沒有的,子類可以增加;父類有的,子類可以改變。
|-構造方法不能被繼承,方法和屬性可以被繼承。
16. 重寫(override):父類和子類方法中,返回型別、方法名稱、引數相同的方法稱之為方法的重寫。重寫也被稱為覆寫。如果子類的方法名與父類相同,但引數不同,不構成重寫。但是現在子類中完成了方法的過載。子類中可以通過super.方法名()語句呼叫父類的方法,並且該super語句不用放在語句塊的第一句(調用構造方法this、super必須放第一句,非構造放不不用必須放在第一句)。
17. 多型(Polymorphism):多型的本質含義是父類的引用可以指向子類的物件。多型是在執行期間(不是編譯期間)決定資料的型別。
18. Parent p = new Child(); p.sing(); 其中,child繼承Parent,child中有sing方法,但是parent中沒有,這樣就會產生呼叫的錯誤,Parent型別中必須含有sing方法,然後子類自動呼叫自己的sing方法。這裡一定要看清楚物件的型別。
19. 父類與子類進行強制型別轉換時,被轉換的物件可以被強轉換為其實際指向的型別(Animal a = new Cat(); Cat c = (Cat)a; a實際指向的是Cat型別,因此可以轉換Cat。
20. 一共有兩種型別的強制型別轉換:
|-向上型別轉換(Upcast):子類轉換成父類(Cat c = new Cat(); Animal a = cat;)可以不用寫強制型別轉換。
|-向下型別轉換(Downcast):將父型別轉換成子型別。必須寫強制型別轉換。例如:Animal a = new Cat(); Cat c = (Cat)a;
21. 對於Animal a= new Cat(); Cat c = (Cat) a;的理解:
|-a是Animal型別的;
|-a指向的是Cat型別;
|-a呼叫方法的時候看物件指向的型別,呼叫指向物件的方法;
|-型別轉換的時候,看a具體是什麼型別。
22. 編寫程式說明多型是Runtime的:
Public class test { Public static void main(String[] args) { A a = null; If(args[0].equals(“1”)) { a = new B(); } Else if(args[0].equals(“2”)) { a = new C(); } a.method(); } } |
其中,A是B、C的父類。 |
23. 抽象類(Abstract Class):
|-使用關鍵字abstract進行宣告。抽象類無法例項化,不能通過new建立一個抽象類的物件。
|-抽象方法:使用abstract修飾的方法。抽象方法有宣告,無實現。
|-抽象方法一定要定義在抽象類中,不能定義在其他類中。
|-如果一個類包含抽象方法,則該類一定是抽象類。
|-如果一個類是抽象類,其可以包含具體的方法,也可以不包含抽象方法。
|-子類繼承父類(抽象類),則子類必須實現父類所有的抽象方法。否則,該子類必須也定義成抽象方法,此時子類中也可以有具體的實現類(實現抽象方法),甚至可以和父類的抽象方法名稱相同(重寫抽象方法)。
24. 介面(interface):
|-介面的地位等同於class,使用interface宣告,介面中的方法全部是abstract方法,但是abstract可以省略不寫。
|-介面可以視為特殊的抽象類,沒有任何具體的方法的抽象類。
|-類實現介面,使用關鍵字implements。子類必須實現介面的所有的方法。但是如果此類為抽象類,則其不必實現介面中的所有方法。
|-Java是單繼承的,但是一個類可以實現多個介面。
|-介面中的方法全是public方法,介面可以定義屬性。其屬性全部public static final的。
25.Static關鍵字:
可以修飾類、成員變數、成員方法;
|-修飾類:靜態類。
|-修飾屬性:靜態屬性。無論一個類生成了多少物件,所有這些物件使用唯一一份靜態成員變數,只要有一個物件改變了該成員變數,所有物件的成員變數都發生了改變。此時的成員屬性可以通過類名.靜態屬性名呼叫,也可以通過物件.靜態屬性名呼叫。
|-修飾方法:靜態方法。可通過類或者類物件呼叫該方法。
|-code:
Public class test { Public static void main(String[] args) { M m = new N(); m.output(); } } Class M { Public static void output() { System.out.println(“M”); } } Class N extends M { Public static void output() { System.out.println(“N”); } } |
此時,輸出的結果是M,而不是m指向的型別N的輸出方法輸出的N。因為子類不能重寫父類的靜態方法。如果M中的output方法不是static的,而繼承M的N的output是static,編譯就會報錯。因為靜態方法不能重寫,稱之為隱藏。現在N中的output方法是static,編譯成功。但父類的方法仍然存在,呼叫的時候要看呼叫物件的型別是什麼就呼叫誰的方法。
|-靜態的不能覆蓋非靜態,非靜態也不能覆蓋靜態。
|-靜態方法不能重寫,只能隱藏。呼叫時看呼叫者的型別而不是指向的型別。
static靜態程式碼塊:
|-static程式碼塊的執行順序高於建構函式。在子類繼承父類的情況下也是如此,靜態程式碼塊優先於所有的建構函式(子類的靜態程式碼塊優先與父類的建構函式),靜態程式碼塊之間的執行順序按照父類-子類的呼叫順序。
|-靜態程式碼塊只調用一次。每次生成物件,都會呼叫構造方法。
|-靜態程式碼塊是類載入時執行,建構函式是類生成物件是執行。
|-靜態方法只能訪問靜態成員變數。非靜態方法可以呼叫靜態成員變數。
|-不能在靜態方法中使用this,因為this是非靜態的成員變數。
25. final關鍵字:可以修飾屬性、方法、類。修飾的東西不能被改動。
|-修飾類:表示此類為終態類,不能被繼承;
|-修飾方法:表示該方法為終態方法,不能被重寫(override);
|-修飾屬性:表示該屬性不能被改寫,此屬性為常量。
Public class test { Public static void main(String[] args) { People people = new People(); people.age = 20; // error ,final型別的屬性不能被改變 people.address = new Address(); //error, final屬性不能被改變,這裡new Address後,原先people的address屬性的地址就發生了變化 people.address.name = “Shanghai”; //right, 因為address的地址並沒有發生變化 } } Class People { Final int age = 10; Final Address address = new Address(); } Class Address { String name = “Beijing”; } |
Final修飾原生資料型別時,表示該原生資料型別的值不能發生變化,final修飾引用型別時,表示該引用型別不能再指向其他物件,但該對物件指向的內容是可以變化的。
|-final修飾成員變數的初始化賦值可以有兩種:一種是定義的時候直接賦值,最常用;另一種是宣告的時候不賦值,然後在每個成員方法中都要賦值。
|-public abstract final class Test{}是錯誤的,因為abstract要求子類繼承,而final約定此類不能被繼承,矛盾。因此,一個類不能即是final又是abstract。
26. 設計模式之單例模式(Singleton):一個類只會生成唯一一個可以使用的物件。
//實現一 Public class SingletonTest { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); System.out.println(s1==s2);//同一物件,地址相同 } Class Singleton { Private static Singleton singleton = new Singleton(); Private Singleton() { } Public static Singleton getInstance() { Return singleton; } } |
//實現二,但在多執行緒中可能出錯 Public class SingletonTest { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); System.out.println(s1==s2);//同一物件,地址相同 } Class Singleton { Private static Singleton singleton; Private Singleton() { } Public static Singleton getInstance() { If(singleton==null) { singleton = new Singleton(); } Return singleton; } } |
27. 包(package):用於將不同功能的類放在不同的目錄(包)下。包的命名規則:公司域名反轉,用“.”分隔,全部小寫。包使用package關鍵字。匯入使用import關鍵字。例如有包aa.bb.cc,如果我們import aa.bb.*,系統不會匯入cc中的類。編譯帶有package宣告的Java原始檔有兩種方法:
|-直接編譯,然後根據類中所定義的包名,逐一手工建立目錄,最後將.class檔案放到該目錄下。
|-使用編譯引數“-d”,方式為:javac –d . 原始檔.java。這樣編譯器自動處理。
28. 訪問修飾符(access modifier):
|-public(公共的):所有的類都可以訪問。
|-private(私有的):被private修飾的屬性和方法只能在類內訪問。
|-protected(受保護的):類內部、相同包及其該類子類可以訪問。
|-預設(不加任何訪問修飾符):類內以及相同包的類可以訪問。
29. instanceof:判斷物件是否是某個類的例項。使用方法為:引用名 instanceof 類名。
People p = new Man(); p instanceof People; True。Man m=new Man(); m instanceof People;同樣也是True!因為Man是People的子類,子類就是父類,因此man是people的例項。
31.相等性的比較:
|-符號“==”
|-對於原生資料型別,比較的是左右的值是否相等;
|-對於引用資料型別,比較的是左右是否指向同一個物件,即左右的引用地址是否相同。
|-equals
|-比較物件的實際值,類物件呼叫。對於Object,比較的是兩個物件的地址。對於String,比較的是兩個物件的內容是否相同。
32. java.lang.Object類:一共9大方法
|-equals:測試類物件的值是否相同。Object預設使用==判斷兩個物件地址是否相同,即是否為同一個物件。
|-toString:列印引用時,會預設呼叫Object的toString()方法。toString返回:類名+“@”+物件的16進位制雜湊碼(相當於地址)。
33. String類:
|-重寫equals方法:如果str.equals(str),即跟自己比較,返回真;如果str不是字串,返回false。然後逐個字元比較字串,完全相同則返回true。總結為判斷該字串與傳進來的字串是否相同。
|-對於字串的相等性判斷,需要使用equals,而不能使用==。
|-String是final類,不能被繼承。
|-任何一個字串都是String的例項,String是constant(常量),建立之後不能被改變。因此String s1 = “Hello”; String s2 = “World”; String s3 = s1+s2;其中的s3為新生成的String物件,為“Hello World”。“字串1”+“字串2”會生成3個String物件。使用+號拼接字串時會生成新的字串物件,而不是原有字串的拼加。
|-對於使用字串賦值String a = “aaa”;:Java對於String維護著一個String Pool(字串池,位於棧中)。對於直接使用字串賦值的String,Java首先檢查池中有沒有改字串的物件,沒有就建立該物件。如果已經含有,就不會再建立新物件,而是直接返回原有的物件地址。因此:String s1 = “a”;Stirng s2=”a”;str == str4為true。S2那句程式碼沒有建立物件。但是String a = new String(“a”); String b = new String(“a”);則建立了a、b兩個物件,因為使用了new關鍵字,建立了物件,a、b是引用。
|-對於使用new(”aaa”)的方式:首先查詢String Pool中有無aaa的String物件,沒有就在String Pool棧中建立該字串,然後也在堆中建立該字串物件,最後將堆中物件地址返回到棧中(多在棧中建立了物件)。如果有,就不在棧中建立aaa物件,但依然在堆中建立一個String物件,並直接將String Pool棧中的字串返回給堆中的新物件。總結:使用new建立字串,堆中一定建立物件,並將其加入到棧中的String Pool。New方式建立的字串,返回的地址是堆中的地址,因此String s1=new(”a”);String s2=new(”a”); s1!=s2;
|-“Hello”.intern(),如果String Pool中有Hello字串,就將該字串返回;如果沒有,則新增Hello到String Pool並返回其引用物件。
|-其餘型別與字串運算時,都會首先變成字串。
|-理解以下程式:
String hello = “Hello ”, lo = “lo”; hello == “Hello” ->true Other.hello == “Hello” ->true(Other是另一個類,含有一個hello屬性) hello == (“Hel”+”lo”)->true hello==(“Hel”+lo)->false 常量+變數,形成一個新的字串常量,特別記憶 hello == (“Hel”+lo).intern()->true |
34. StringBuffer(執行緒安全):
|-final class,不能被繼承;
|-String是常量,建立後不能改;StringBuffer是變數,建立後可以改,可以追加。
|-使用append追加字串並返回當前字串物件。
|-使用其toString()方法返回該StringBuffer中的資料。
此外還有StringBuilder,非執行緒安全,效能>StringBuffr。
35. 包裝類(Wrapper Class):針對原生資料包裝成物件。所有的包裝類都位於java.lang包下,都是final class。
Integer、Byte、Short、Long、Boolean、Character、Float、Double
原生->包裝類:Integer I = new Integer(100);
包裝類->原生:i.intValue();
36. 陣列(Array):相同型別的資料集合叫做陣列。Java中,陣列是物件。
|-定義陣列:資料型別[] 陣列名 = new 資料型別[陣列長度];int [] a = new int[12];
|-包含length屬性,表示陣列的長度。
|-陣列也是引用,繼承Object,因此陣列繼承Object的equals方法,比較陣列是否相同不能使用equals方法。
|-陣列名是陣列的引用,其值等於陣列首個元素的地址。
|-二維陣列定義方式:type[][] 陣列名 = new type[行數] [列數];
37. 不使用中間變數完成變數值交換:
int a = 3; int b = 4; a = a+b; b = a-b; a= a-b; |
38. 如下語句:
I[] i = new I[2]; True,可以編譯通過,通過i[0] = new C()初始化陣列; I i = new I(); False,介面不能例項化 Interface I{} Class C implements I{} |
39. Arrays類:
|-位於java.util包下;
|-用於操縱陣列,包括查詢、排序,將陣列轉換成list等;
|-所有方法都是靜態方法(Static)
40. 陣列拷貝可以使用System.arrayCopy方法,程式碼如下:System.arrayCopy (a,0,b,0,4);引數依次為:起始陣列,起始地址,目標陣列,起始地址,拷貝長度。
41. 排序問題:
氣泡排序(複雜度O(N^2)):1跟2比,2跟3比,3跟4比…
public static int[] order(int[] a) { int tmp; for(int i=0;i<a.length;i++) { for(int j=0;j<a.length-i-1;j++) { if(a[j]>a[j+1]) { tmp = a[j]; a[j] = a[j+1]; a[j+1] = tmp; } } return a; } } |
選擇排序(複雜度O(N^2)):對待排序的記錄序列進行n-1遍的處理,第1遍處理是將L[1..n]中最小者與L[1]交換位置,第2遍處理是將L[2..n]中最小者與L[2]交換位置,......,第i遍處理是將L[i..n]中最小者與L[i]交換位置。這樣,經過i遍處理之後,前i個記錄的位置就已經按從小到大的順序排列好了。
public static int[] Select(int[] a) { int tmp; for(int i=0;i<a.length;++i) { int samllLocation =i; tmp = a[i]; for(int j=i+1;j<a.length;++j) { if(a[j]<tmp) { tmp = a[j]; samllLocation = j; } } a[samllLocation] = a[i]; a[i] = tmp; } return a; } |
插入排序(複雜度O(N^2)):基本思想是,經過i-1遍處理後,L[1..i-1]己排好序。第i遍處理僅將L[i]插入L[1..i-1]的適當位置,使得L[1..i]又是排好序的序列。要達到這個目的,我們可以用順序比較的方法。首先比較L[i]和L[i-1],如果L[i-1]≤
L[i]說明[1..i]已排好序,第i遍處理就結束了;否則交換L[i]與L[i-1]的位置,繼續比較L[i-1]和L[i-2],直到找到某一個位置j(1≤j≤i-1),使得L[j]
≤L[j+1]時為止。
簡言之,插入排序就是每一步都將一個待排資料按其大小插入到已經排序的資料中的適當位置,直到全部插入完畢。
//插入排序 public static int[] Insert(int[] a) { for(int i=1;i<a.length;++i) { int tmp = a[i]; int j = i; while(a[j-1]>tmp) { a[j] = a[j-1]; j--; if(j<=0) break; } a[j] = tmp; } return a; } |
42. 查詢問題:
|-直接查詢
|-二分查詢(BinarySearch):待查詢陣列必須要有序
public static int search(int[] a,int b) { int low = 0; int high = tmp.length; int mid = 0; while(low <= high) { mid = (low + high)/2; if(tmp[mid]==b) { return mid; } if(b<tmp[mid]) { high = mid -1; } if(b>tmp[mid]) { low = mid +1; } return -1; } return 0; } } |
43. 隨機生成50個數,每個數的範圍是[10,50],統計每個數字出現的次數以及出現次數最多的數字和他的個數,最後將每個數字及其出現的次數打印出來,出現次數為0不列印。
public static void main(String[] args) { //生成50個數字,位於區間[10-50]並統計字數、列印 Random random = new Random(); int[] gennum = new int[41];//一共能生成41種數字 for(int i = 0;i<50;++i) { //Java中返回資料都是[),左開右閉 int num =(random.nextInt(41))+10; gennum[num-10]++; //很關鍵,利用陣列的下標 } for(int i=0;i<gennum.length;++i) { if(0==gennum[i]) { continue; } System.out.println((10+i)+"出現次數為:"+gennum[i]); } int max = gennum[0]; for(int i=0;i<gennum.length;++i) { if(max<gennum[i]) { max = gennum[i]; } } for(int i=0;i<gennum.length;++i) { if(max==gennum[i]) { System.out.println(i+10); } } } |
44. Java中的常量都用大寫字母命名,如果有多個單詞,之間用下劃線連線。Java中的常量一般都是 public static final型別的。之所以用static是因為這樣每個物件只維護一份即可。專案中一般將常量統一維護在一個類中,如訪問許可權管理。
45. 集合(Collection):Java中的重中之重!
集合框架介面(以下都是介面),集合中存放的還是引用;類似於Arrays類至於陣列,Collection對應Collections類提供對集合的輔助功能。例如Collections.reverseOrder返回一個比較器,Collections.sort用於排序,Collectins.shuffle用於打亂順序,Collections.min/max返回最大值等。
Collection
|-Set
|-SortedSet/HashSet
|-List:有序集合;
Map
|-SortedMap/HashMap
46. List
|-ArrayList
|-LinkedList
47. ArrayList:陣列實現,順序表。
|-add方法新增元素
|-get方法取出元素,根據元素的索引,類似於陣列,從0開始
|-可以儲存重複的元素
|-size返回列表中元素的個數