java-day22
重載、重寫和多態的關係
- 重載是編譯時多態
- 在調用重載方法的時候,在編譯期間就要確定調用的方法到底是哪一個,如果不能確定,那麼就編譯報錯。
- 重寫是運行時多態
- 調用重寫方法的時候,在運行期間才能確定這個方法到底是哪一個對象中的。這個事情取決於調用方法的引用在運行期間到底指向的對象是誰,以及對象中有沒有重載這個方法。
- java中的方法調用,是運行時動態和對象綁定的。
JAVA的高級特性(一)
學習目標
- 靜態屬性、方法、代碼塊
- 靜態導入
- final類、方法、變量
- 訪問控制修飾符
- 抽象類和抽象方法
- 接口
- 內部類
- 區別 “ == ” 和 equals()
靜態變量
- 被所有實例變量共享
- 可被類的外面訪問
- 更像是一個全局變量
- 訪問方法:類名.靜態方法名
static修飾符
-
在類中,使用static修飾的成負變量,就是靜態變量,反正爲非靜態變量。
-
pub1ic class Student{ private static int a; private int b; }
-
-
靜態類和非靜態變量的區別
-
靜態變量是屬於類的,[可以] 使用類名來訪問,[也可以]使用對象來訪問。
-
非靜態變量是屬於對象的,[只能]使用對象來訪問
-
pub1ic class Student{ private static int a; private int b; } main: Student stu = new Student(); //使用對象訪問類中非靜態變量 System.out.println(stu.b); //使用對象訪問類中靜態變量 System.out.println(stu.a); //使用類名訪問類中靜態變量 System.out.print1n(Student.a);
-
-
靜態屬性和非靜態屬性在內存中的區別
-
一個類中的靜態屬性,在內存中只有一份,它是這個類所以的實例對象所共享的
-
一個類中的非靜態屬性,每次創建一個新的對象,在這個新的對象中就會有一份這個非靜態屬性。對象和對象之間的非靜態屬性是互不影響的。
-
package com.zzb.day22; public class Student{ private static int count; private int age; public Student(){ count++; age++; } public static void main(String[] args){ Student s1 = new Student(); Student s2 = new Student(); Student s3 = new Student(); Student s4 = new Student(); System.out.println(s1.age); System.out.println(s2.age); System.out.println(s3.age); System.out.println(s4.age); System.out.println("------------------------"); System.out.println(s1.count); System.out.println(s2.count); System.out.println(s3.count); System.out.println(s4.count); System.out.println("------------------------"); System.out.println(Student.count); } }
-
注意,靜態變量是屬於類的,是這個類的所有對象共享的,非靜態變量是屬於對象的,是每個對象獨有的。在類中,使用static修飾符修飾的方法就是靜態方法,反之爲非靜態方法
-
靜態方法是屬於類的,[可以] 使用類名直接訪問.
-
非靜態方法是屬於對象綁定,[必須] 使用對象名來訪問
-
靜態方法中[不可以]直接訪問類中的非靜態屬性和非靜態方法,但是反過來,類中的非靜態方法中[可以]直接訪問類中的靜態方法和靜態屬性。
-
this和super都屬於非靜態的變量,靜態方法中無法使用這兩個關鍵字
-
package com.zzb.day22; public class Student{ private static int count; private int age; public void run(){} public static void go(){} public static void test(){ //編譯報錯 //System.out.println(this); //System.out.println(age); //System.out.println(this.age); //編譯通過,直接訪問類中的靜態屬性 //和靜態方法 System.out.println(count); go(); } }
-
-
思考,爲什麼靜態方法中不可以訪問非靜態的屬性和訪問,非靜態的方法中卻可以訪問靜態的屬性和方法?
- 類中的屬性和方法,都必須分配內存空間,在其中進行初始化操作之後,才能被訪問和調用。靜態的屬性和方法,在類被加載到內存之後,已經在一-個叫靜態代碼區的內存區域中,專門的做好了初始化相關的操作,這些屬性和方法隨便可以被類進行調用
- 非靜態屬性和方法,是在使用new關鍵字創建對象之後,在對象所佔據的內存空間中,完成了對這些非靜態屬性和方法的初始化相關工作,在這之後,我們纔可以使用對象來訪問這些非靜態的屬性和方法。
- 從初始化的時間點來看,可以知道靜態的屬性和方法在初始化完成可以被調用的時候,那些非靜態的屬性和方法還沒有完成對應的初始化工作,不能被調用。所以靜態方法中無法直接訪問非靜態的屬性和方法。但是非靜態屬性和方法完成初始化工作,可以被調用的時候,類中的那些靜態屬性和方法,早就完成了初始化工作,所以非靜態方法中可以直接調用類中的靜態屬性和方法。
-
父類中的靜態方法可以被子類繼承,但是不能被子類重寫
-
public class Person{ public static void say(){} } public class Student extends Person{ //編譯報錯 //靜態方法可以繼承不能重寫 //public void say(){} //編譯通過,但不是重寫 public static void say(){} }
-
-
代碼塊和靜態代碼塊
-
public class Person{ { //代碼塊(匿名代碼塊) } static{ //靜態代碼塊 } }
-
匿名代碼塊和靜態代碼塊的調用
- 因爲都沒有名字,代碼中並不能直接調用這兩種代碼塊
- 匿名代碼塊是在創建對象的時候自動調用,並且是在類的構造器執行之前。如果我們連續多次創建對象,每次創建對象都會調用這個匿名代碼塊。
- 靜態代碼塊,會在類加載到內存的時候,自動執行一次,並且只會執行這一次。因爲這個類加載到內存之後,就不會再加載這個類了。
-
匿名代碼塊和靜態代碼塊的作用
-
匿名代碼塊的作用,是給對象裏面的非靜態屬性進行初始化賦值的。
-
構造器的作用有兩個,一個是配合new關鍵字創建對象,另一個就是給對象中的屬性做初始化。所以我們平
時見到的匿名代碼塊並不多,因爲它的工作是可以被構造器代替的。並且構造器是有名字的,可以使用this()的語法來調用,但是匿名代碼塊沒有名字,一般不會主動去調用 -
靜態代碼塊的作用,是給類中的靜態屬性做初始化,也可以在類加載的時候就給這個類本身做一些其他的初始化工作,因爲靜態代碼塊執行的時間點比較早,所以我們在靜態代碼塊中編寫的代碼就可以很早的得到執行,提前得到一些初始化操作。例如可以在靜態代碼塊中,早早對靜態屬性進行初始化賦值工作。
-
public class Student{ public static String name; public Student(){ name = "Tom"; } public static void main(String[] args){ //輸出null,繞過構造器直接拿值 //沒有創建對象構造器沒有執行,初始化沒有完成 //訪問的是默認值null System.out.println(Student.name); } }
-
如何解決? 使用靜態代碼塊
-
public class Student{ public static String name; static{ name = "Tom"; } public static void main(String[] args){ //訪問的是默認值Tom System.out.println(Student.name); } }
-
-
-
創建和初始化的過程
-
Student s = new Student();
-
假設Student類之前沒有被加載過
-
類加載,同時初始化靜態屬性的默認值
-
0 false null
-
-
執行靜態代碼塊
-
分配內存空間,同時初始化非靜態屬性的默認值 0 false null
-
調用父類構造器 super( )
-
對Student對象中的非靜態屬性做顯示賦值
-
private static name = "Tom";
-
-
執行匿名代碼塊
-
執行Student類中的構造器
-
把創建好的對象內存地址值,賦值給變量s(=)
-
-
-
創建對象的時候需要做初始化
-
靜態屬性
-
非靜態屬性
-
子類的非靜態屬性
-
父類的非靜態屬性
-
-
第一梯隊:靜態屬性 優先初始化
- 類加載(把編譯好的class文件加載到內存) 靜態代碼塊
-
第二梯隊:父類中的非靜態屬性
- super()這種特殊語法
-
第三梯隊:子類中的非靜態屬性
- 匿名代碼庫 構造器
-
-
經典案例