類變數: 什麼是類變數? 一個可以被一個類所有對象共用的變數 類變數關鍵字? static 類變數語法? 訪問修飾符 static 數據類型 變數名; [推薦使用] static 訪問修飾符 數據類型 變數名; 入門案例: count被child1和child2共用,只要是Child類的對象都可以共 ...
類變數:
- 什麼是類變數? 一個可以被一個類所有對象共用的變數
- 類變數關鍵字? static
- 類變數語法? 訪問修飾符 static 數據類型 變數名; [推薦使用]
- static 訪問修飾符 數據類型 變數名;
- 入門案例:
- count被child1和child2共用,只要是Child類的對象都可以共用該變數
-
public class Test { public static void main(String[] args) { Child child1 = new Child("jack"); child1.join(); Child.count++; Child child2 = new Child("king"); child2.join(); Child.count++; } } class Child{ String name; public static int count = 0; public Child(String name) { this.name = name; } public void join(){ System.out.println(name); } }
-
類變數的記憶體發佈:
-
類變數細節:
- 類變數也叫靜態變數
- 類變數可以通過 - 類名.類變數名 或 對象名.類變數,來訪問
- 類變數是在類載入時初始化,就算沒有創建對象,只要類載入,就可以訪問類變數 - 重要
- 類變數的生命周期是隨著類載入開始,類消亡而銷毀
-
public class Test { public static void main(String[] args) {
//類變數,可以通過類名.類變數名稱,或對象名.類變數來訪問
System.out.println(Child.count);} } class Child{ static int count = 0; }
類方法:
- 什麼是類方法?和類變數一樣通過關鍵字static來實現共用
- 類方法的語法?訪問修飾符 static 數據返回類型 方法名(); - 推薦使用
- static 訪問修飾符 數據返回類型 方法名();
- 類方法的使用場景?一般做為工具類來使用或者通用的方法(如:列印數組Arrays),來提高開發效率,通過類名去調用
- 案例:
-
public class Test { public static void main(String[] args) { Child jack = new Child("jack"); Child.payFee(1000); Child kind = new Child("kind"); Child.payFee(2000); Child.showFee();//3000 } } class Child{ private String name; //累加學費 public static double fee = 0; public Child(String name) { this.name = name; } //靜態方法 public static void payFee(double fee){ Child.fee += fee; } //靜態方法 public static void showFee(){ System.out.println(fee); } }
-
類方法細節:
- 類方法和普通方法都是隨著類的載入而載入,將結構存儲在方法區
- 類方法中不能使用this和super
- 類方法中只能訪問類變數或類方法
- 普通成員方法,即可以訪問非靜態成員,也可以訪問靜態成員
-
class Child{ String name; //類方法中不能使用this和super public static void payFee(double fee){ System.out.println(this.name); //錯誤 System.out.println(super.clone());//錯誤 //類方法中只能訪問類變數或類方法 showFee();//錯誤 System.out.println(name);//錯誤 } public void showFee(){ //普通成員方法,即可以訪問非靜態成員,也可以訪問靜態成員 System.out.println(name);//正確 payFee(11.1);//正確 } }
main方法的理解:
- main方法本虛擬機調用
- java虛擬機需要調用類的main方法,使用main方法訪問許可權為public
- java虛擬機在執行main方法時不必創建對象,所以是static
- main方法的字元串類型數組參數,是在執行程式時傳遞
-
細節:
- main方法中,可以直接調用main方法所在類的的靜態方法和靜態屬性
- 不能直接調用非靜態成員,必須創建一個實例底對象後才能調用
-
public class Test { private String name = "king"; private static int age = 18; public static void show(){ System.out.println("我可以被main調用"); } public void show2(){ System.out.println("我不是靜態方法"); } public static void main(String[] args) { show();//直接調用 System.out.println(age); //直接調用 Test test = new Test(); test.show2(); //創建對象調用 System.out.println(test.name);//創建對象調用 } }
- 如果在idea給main方法傳參數
代碼塊:
- 什麼是代碼塊?可以把它看成一個方法,可以在代碼塊中寫邏輯語句,但它沒有返回體,沒有方法名,就在一個花括弧中
- 基本語法?[ 修飾符 ]{ 代碼 }; - 分號可寫可不寫
- 修飾符:只能是static或者不寫(有static的叫靜態代碼塊,沒有的叫普通代碼塊)
- 案例:
-
class A{ //靜態代碼塊,隨著類的載入而載入,只執行一次 static{ System.out.println("我是代碼塊A"); //2 }; //普通代碼塊,隨著對象實例的創建而載入,創建一個對象,執行一次 { System.out.println("我是代碼塊B"); //3 }; }
-
細節(多看記住):
- 靜態代碼塊隨著類的載入而執行,只會執行一次
- 普通代碼塊在創建對象時而執行,創建一個對象執行一次
- 類的載入情況:
- 創建對象實例(new)
- 創建子類對象實例,父類也會被載入(沒父哪來的子)
- 使用類的靜態成員
-
public class Test { public static void main(String[] args) { // System.out.println(A.name); //輸出結果:1.把鍵盤敲爛 2.king // A a = new A();//輸出結果 1.把鍵盤敲爛 2.king 3.普普通通 B b = new B();//輸出結果:1.把鍵盤敲爛 2.B代碼塊 3.普普通通 } } class A{ public static String name = "king"; //靜態代碼塊隨著類的載入而執行,只會執行一次 static{ System.out.println("把鍵盤敲爛"); }; { System.out.println("普普通通"); }; } //創建子類對象實例,父類也會被載入 class B extends A{ static{ System.out.println("B代碼塊"); } }
- 創建對象時,類中的調用順序:
- 先調用靜態代碼塊和靜態屬性的初始化
- 如果有多個靜態代碼塊和靜態屬性變數初始化,則按照定義順序執行,因為它們優先順序一樣
- 在調用普通代碼塊和普通屬性的初始化
- 如果有多個普通代碼塊和普通屬性初始化,則按照定義順序執行,因為它們優先順序一樣、
- 最後調用構造器方法
- 先調用靜態代碼塊和靜態屬性的初始化
-
public class Test { public static void main(String[] args) { A a = new A(); } } class A{ public static String name = "show()"; //1 public static int a = show(); //1 public int b = show2(); //3 public A(int b) { System.out.println("可憐的構造器被最後調用"); //5 } static{ System.out.println("把鍵盤敲爛"); //2 }; { System.out.println("普普通通"); //4 }; public static int show(){ System.out.println("我是show"); return 0; } public int show2(){ System.out.println("我是show2"); return 0; } }
- 構造器中 在預設隱藏了super( )和調用普通代碼塊 - 這是父子類都沒有靜態代碼塊或靜態屬性的執行流程
- 理解:有繼承關係,就先執行完父類的才執行到自己的
-
public class Test { public static void main(String[] args) { B b = new B(); } } class A{ { System.out.println("A代碼塊");//1 } public A() { //super() //調用本類代碼塊 System.out.println("A無參構造");//2 } } class B extends A{ { System.out.println("B代碼塊");//3 } public B() { //super() //調用本類代碼塊 System.out.println("B無參構造");//4 } }
-
繼承關係:父類和子類都有靜態代碼和靜態屬性,普通代碼塊和普通屬性和構造器,類的執行流程是?:
-
執行父類的靜態代碼塊和靜態屬性(優先順序一樣,按順序執行)
-
執行子類的靜態代碼塊和靜態屬性(優先順序一樣,按順序執行)
-
執行父類的普通代碼塊和普通屬性(優先順序一樣,按順序執行)
- 執行父類的構造器方法
-
執行子類的普通代碼塊和普通屬性(優先順序一樣,按順序執行)
-
執行子類的構造器方法
-
-
public class Test { public static void main(String[] args) { new B02();//對象 } } class A02 { //父類 private static int n1 = getVal01(); static { System.out.println("A02的一個靜態代碼塊..");//(2) } { System.out.println("A02的第一個普通代碼塊..");//(5) } public int n3 = getVal02();//普通屬性的初始化 public static int getVal01() { System.out.println("getVal01");//(1) return 10; } public int getVal02() { System.out.println("getVal02");//(6) return 10; } public A02() {//構造器 //隱藏 //super() //普通代碼和普通屬性的初始化...... System.out.println("A02的構造器");//(7) } } class B02 extends A02 { private static int n3 = getVal03(); static { System.out.println("B02的一個靜態代碼塊..");//(4) } public int n5 = getVal04(); { System.out.println("B02的第一個普通代碼塊..");//(9) } public static int getVal03() { System.out.println("getVal03");//(3) return 10; } public int getVal04() { System.out.println("getVal04");//(8) return 10; } public B02() {//構造器 //隱藏了 //super() //普通代碼塊和普通屬性的初始化... System.out.println("B02的構造器");//(10) // TODO Auto-generated constructor stub } }
單例設計模式:
- 什麼是單例設計模式? 單個實例的意思,就是採取某些辦法讓類的實例對象只有一個(餓漢式-懶漢式,就是經典的單例模式)
- 什麼是設計模式? 在大量的實踐中總結出的代碼結構,編程風格,已經解決問題的思考方式
-
餓漢式:
- 什麼是餓漢式? 類載入的時,就已經創建對象實例 - 十分著急
- 餓漢式實現步驟:
- 所有化構造器
- 類的內部創建對象
- 向外部暴露一個靜態的公共方法
-
public class Test { public static void main(String[] args) { King show = King.show(); System.out.println(show);//com.Variable.King@1540e19d //類載入只載入一次 King show2 = King.show(); System.out.println(show);//com.Variable.King@1540e19d } } class King{ private String name; private static King king = new King("jack"); private King(String name) { System.out.println("構造器被調用"); this.name = name; } public static King show(){ return king; } }
- 懶漢式:
- 什麼是懶漢式? 需要到創建對象實例,才會創建 - 不著急
- 懶漢是實現步驟,和餓漢是一樣,都是細節不一樣
-
public class Test { public static void main(String[] args) { Idler show = Idler.show(); System.out.println(show);//com.Variable.Idler@1540e19d //類載入只載入一次 Idler show2 = Idler.show(); System.out.println(show);//com.Variable.Idler@1540e19d } } class Idler{ private String name; private static Idler idler; private Idler(String name) { this.name = name; } public static Idler show(){ if (idler == null){ idler = new Idler("jack"); } return idler; } }
-
餓漢式和懶漢式對比:
- 兩種模式,都是為了對象的一個實例,只是創建時機不同
- 餓漢式不存線上程安全問題,懶漢式存線上程安全問題
- 餓漢式存在資源浪費問題,如果沒有使用到它但它創建對象實例了,就浪費了,懶漢式是使用時才創建,不存在該問題
final關鍵字:
- 什麼是final關鍵字? 表示最終的意思,可以用來修飾類、屬性、方法和局部變數
- 使用場景? - 總結:不希望本類被子類繼承
- 不希望本類被子類繼承
- 當類的屬性不希望被修改時
- 當局部變數不希望本修改時
- 當類的方法不需希望本子類覆蓋/重寫時
-
final class AA{ } //當類不希望被繼承時,可以使用final修飾 class BB extends AA{} class CC{ private final String Name = "jack"; public final void show(){ //當類的某個屬性不希望被修改時,可以用final修飾 Name = "king"; } public void show2(){ //當局部變數不希望被修改時,可以使用final修飾符 final int i = 10; } } class DD extends CC{ //當父類的方法不想被子類覆蓋/重寫 @Override public void show() { super.show(); } }
-
細節:
- final修飾的屬性又叫常量,一般用什XX_XX_XX來命名
- final修飾屬性時,必須賦值,標簽以後不能修改,賦值可以在下麵的其中一個:
- 直接屬性賦值 如:public final int i = 10;
- 構造器賦值
- 代碼塊賦值
- final修飾屬性時,如果是靜態屬性,賦值可以在下麵其中一個:
- 直接賦值
- 靜態代碼塊
- final不能被繼承,但可以本實例化
- 類不是final類,但是含有final方法,則該方法雖然不能被覆蓋/重寫,但可以繼承
- final不能修飾構造器
- final和static搭配使用,效率更高,因為不會導致類的載入(底層編譯器做了優化)
- 是final類了,就沒有必要將類中方法修飾為final方法(因為類不會本繼承,方法也不會被覆蓋/重寫)
- 包裝類(Integer,Double,Float,Boolean等但是final),String也是final類
-
public class Test { public static void main(String[] args) { //final類不能繼承但能實例化對象 CC cc = new CC(); //不是final類,但是是方法是final方法,不可以本覆蓋/重寫,但可以本繼承 EE ee = new EE(); ee.show(); //被繼承的表示 //用了final和static,不會導致類載入 System.out.println(GG.i); } } class GG{ public static final int i = 10; static { System.out.println("用了final和static,不會導致類載入"); } } class FF{ //final不能修改構造器方法 public final FF() { } } final class CC{} class DD{ public final void show(){ System.out.println("敲壞鍵盤"); } } class EE extends DD{ } //普通屬性賦值時 class AA{ //1.直接都有時賦值 public final double TAX_RATE; //2.構造器賦值 public AA(){ TAX_RATE = 99.99; } //3.代碼塊賦值 { TAX_RATE = 66.66; } } //靜態屬性賦值時 class BB{ //1.直接都有時賦值 public static final double TAX_RATE = 88.88; //2.靜態代碼塊賦值 static{ TAX_RATE = 99.99; } }
抽象類:
- 什麼是抽象類?當父類的某些方法,需要聲明,但不確定方法用來做什麼的時候,就可以用抽象,那麼方法就叫抽象方法,類就是抽象類、
- 例:就是我的父類有一個方法,不知道具體用來做什麼,但是要聲明這個方法,然後用子類去基礎並實現該方法
- 語法?方法:訪問修飾符 abstract 返回類型 方法保名(); - - 沒有方法體 類:abstract 類名{};
- 抽象類的用途?抽象類的作用更多在於設計,設計者設計號後,讓子類繼承並實現。在框架和設計模式使用比較多
-
abstract class Employee{ //抽象類 //抽象方法 public abstract void work(); } class Manager extends Employee{ //實現抽象方法 @Override public void work() { System.out.println("經理/普通員工"+super.name+"工作中"); } }
-
細節:
- 抽象類不能本實例化(類載入可以)
- 抽象類庫可以不包含abstract方法,就是抽象類可以沒有抽象方法
- 類中又了抽象方法,該類就必須聲明為抽象類
- abstract只能修飾類和方法,不能修飾屬性和其它
- 抽象類可以又任意成員(抽象類還是類)
- 抽象方法不能有主體
- 一個類繼承了抽象類就必須實現抽象方法,否則就把自己也聲明為抽象方法就不用實現了
- 抽象類不能使用,static、find、private來修飾,這些關鍵字和重寫想違背
- 重新類最佳實際 - 模板設計
- 什麼是模板設計?把公共的區域提取出來封裝到一起
-
public class Test { public static void main(String[] args) { BB bb = new BB(); //繼承理所應當的calculateTime方法也繼承 bb.calculateTime(); CC cc = new CC(); cc.calculateTime(); } } abstract class AA{ public abstract void obj(); public void calculateTime(){ long start = System.currentTimeMillis(); obj(); //但調用到該方法時,動態綁定機制就上場了,會去看子類有沒有,有就調用 long end = System.currentTimeMillis(); System.out.println("總共耗時:"+(end-start)); } } class BB extends AA{ public void obj(){ long k = 0; for (int i = 1; i <= 900000; i++) { k+=i; } } } class CC extends AA{ public void obj(){ long k = 0; for (int i = 1; i <= 900000; i++) { k+=i; } } }
介面:
- 什麼是介面?1.介面是java單繼承的一種補充,2.介面規則了實現方法,實現介面的類必須實現方法
- 例:1.小猴子只會爬樹-這是繼承老猴子的,小猴子學游泳是學魚的-這就是實現介面,單繼承補充
- 語法:interface 介面名{....} -- 定義介面 ,class 類名 implements 介面名{....} -- 實現介面
- 用途:定義規範例:我寫一個介面規則資料庫只能用統一的介面名實現,那麼不管連接什麼資料庫的方法名都得到了統一等等
-
案例演示:
-
public interface Usb { int i = 10; //介面可以有屬性 void show(); //抽象方法 } class King implements Usb{ int a = 20; //定義自己的屬性 @Override public void show() { //實現介面中的抽象方法 System.out.println(Usb.i); //獲取屬性 } public void show2(){ System.out.println("定義自己的方法"); } }
-
-
jdk7.0和jdk8.0介面的改變:
- jdk7.0以前介面在是不能有預設方法和靜態方法
- jdk8.0以後介面在是可以有預設方法和靜態方法
- 預設方法需要加上default關鍵字
-
public interface Usb { void show(); default public void show3(){ System.out.println("jdk8以後可以寫普通屬性"); } public static void show4(){ System.out.println("jdk8以後可以寫靜態方法"); } }
-
細節:
- 介面不能實例化
- 介面的寫的抽象方法是不用寫abstract關鍵字的
- 介面中所有的方法是public方法,介面在抽象方法,可以不用abstract修飾
- 普通類實現介面,必須將該介面的所有方法都實現
- 抽象類實現介面,不用實現介面方法 - 因為介面的里的方法就是抽象方法
- 一個類可以同時實現多個介面
- 介面中的屬性只能是final的
-
//介面的修飾符只能是public和預設的,和了類的修飾符一樣 public interface Usb { //介面中的屬性只能是find int i = 10; //等價於 int final static i = 10; //不用abstract來修飾方法為抽象方法 void connect(); //介面中的方法都是public方法 //private void interrupt(); default void interrupt(){ //介面的訪問通過介面名.屬性名 System.out.println(Usb.i); } } //介面不能繼承其它類,但是可以繼承多個別的介面 interface Usb3 extends Usb{} //一個類同時實現多個介面 class A_ implements Usb,Usb3{ int a = 10; //一個普通類實現介面必須把介面方法都實現了 //當然抽象類不用 @Override public void connect() { System.out.println("連接Usb——A"); } @Override public void interrupt() { System.out.println("連接Usb——A"); } }
-
實現介面VS繼承類:
- 問題?介面是讓實現它的類去實現它的抽象方法,繼承是讓它的子類去繼承它的屬性方法(遵守訪問修飾符),感覺上是差不多,那實際是什麼樣
- 繼承的價值:解決代碼的復用性和可維護性
- 介面的價值:設計 - 設計好合作規範(方法)讓其它類去實現這些方法,比較靈活
- 繼承需要滿足is-a的關係 - 就是小狗的繼承類必須是動物,是有保存聯繫的
- 介面只需要滿足like-a的關係 - 就是小狗類但是我也可以去實現某個介面,如該介面中有游泳的方法,小狗就實現了游泳
-
介面的多態:
- 介面的多態和類的多態是一樣的父類可以接收所有子類,介面就是可以接收實現它的類
-