封裝(Encapsulation)是面向對象的三大特徵之一(另外兩個是繼承和多態),它指的是將對象的狀態信息隱藏在對象內部,不容許外部程序直接訪問對象內部信息,而是經過該類所提供的方法來實現對內部信息的操做和訪問。java
Java 提供了 3 個訪問控制符:private、 protected 和 public ,表明 3 種不一樣的訪問級別,再加上一個默認的訪問控制級別(不使用任何訪問控制符),共有 4 個訪問控制級別。ide
private(當前類訪問權限):類中的一個的成員被 private 修飾,它只能在當前類的內部被訪問;函數
default(包訪問權限):類中的一個成員或者一個外部類不使用任何訪問控制符修飾,它能被當前包下其餘類訪問;this
protected(子類訪問權限):類中的一個的成員被 protected 修飾,它既能夠被當前包下的其餘類訪問,又能夠被不一樣包的子類訪問;code
public(公共訪問權限):類中的一個成員或者一個外部類使用 public 修飾,它能被全部類訪問。對象
private | default | protected | public | |
---|---|---|---|---|
同一個類中 | ✔ | ✔ | ✔ | ✔ |
同一個包中 | ✔ | ✔ | ✔ | |
子類中 | ✔ | ✔ | ||
全局範圍內 | ✔ |
java.lang.Object
,所以 java.lang.Object
是全部類的直接或間接父類。重寫父類方法應遵循 「兩同兩小一大「 規則:blog
class B { public void show() { System.out.println("B"); } } public class A extends B{ @Override public void show() { System.out.println("A"); //重寫父類方法 } }
重載(Overload)和重寫(Override)區別:繼承
class B { private int x; public B(int x) { this.x = x; } public void show() { System.out.println("x:" + x); } } public class A extends B{ private int x; public A(int x, int x1) { super(x1); this.x = x; } @Override public void show() { super.show(); //調用被覆蓋的父類方法 } public static void main(String[] args) { A a = new A(1, 2); a.show(); //x:2 } }
子類繼承了父類的所有變量和方法,因此實例化子類時,必須先將其父類實例化。調用父類構造器的方式是 super(),參數爲父類構造器所需參數。使用 super 調用父類構造器必須出現放在子類構造器的第一行,而 this 調用同一個類中重載的構造器也要放在第一行,因此 super() 和 this() 不能同時出現。get
無論是否使用 super 顯式調用父類構造器,子類構造器總會調用父類構造器一次,總共會出現三種狀況:io
多態:相同類型的變量調用同一個方法時呈現出多種不一樣的行爲特徵。
產生緣由:Java 容許把一個子類對象直接賦給一個父類引用變量,無須任何類型轉換。當把一個子類對象賦給父類引用變量時,會出現編譯類型和運行類型不一致的狀況,此時調用子類和父類的同名方法時(這裏的同名指的是子類重寫了父類方法),老是表現出子類方法的行爲特徵。例如:B b = new A()
編譯類型看左邊,運行類型看右邊,所以編譯類型爲 B,運行類型爲 A,當 b 調用 A 和 B 的同名的方法時,運行的老是 A 中的方法。
class B { public String book = "B"; public void base() { System.out.println("父類普通方法"); } public void test() { System.out.println("父類被覆蓋的方法"); } public String getBook() { return book; } } public class A extends B{ public String book = "A"; @Override public void test() { System.out.println("子類覆蓋父類方法"); } public void sub() { System.out.println("子類普通方法"); } @Override public String getBook() { return book; } public static void main(String[] args) { B b = new B(); System.out.println(b.book); //B b.base(); //父類普通方法 b.test(); //父類被覆蓋的方法 System.out.println(b.getBook()); //B A a = new A(); System.out.println(a.book); //A a.base(); //父類普通方法 a.test(); //子類覆蓋父類方法 System.out.println(a.getBook()); //A //編譯看左邊,運行看右邊,編譯和運行不一致 B b1 = new A(); //訪問的是父類的屬性,與方法不一樣,實例變量不具備多態性 System.out.println(b1.book); //B //訪問父類繼承的方法 b1.base(); //父類普通方法 //訪問的是子類的同名方法 b1.test(); //子類覆蓋父類方法 //B沒有提供sub()方法,就算A有,也沒法經過編譯 //b1.sub(); //錯誤 System.out.println(a.getBook()); //A } }
當代碼運行 B b1 = new A()
時,編譯類型爲 B,運行類型爲 A。
當調用 b1.test()
方法時(B 中有 test() 方法,A 中將其覆蓋了),實際運行的是 A 的 test() 方法,方法行爲老是表現出子類方法的行爲特徵,而不是父類方法的行爲特徵,這就是多態。
當執行 b1.base()
方法時,由於子類繼承了父類的該方法,而且沒有重寫,因此運行一致。
當執行 b1.sub()
方法時,因爲父類沒有 sub() 方法,而編譯時類型爲父類,因此沒法經過編譯。
當執行 b1.book
獲取同名實例變量時,返回的是父類的實例變量,與方法不一樣,對象的實例變量則不具有多態性,返回的數據看編譯時的類型。
當執行 b1.getBook()
方法時,實際運行的是 A 的 getBook() 方法 ,內部訪問的實例變量是 A 的,方法是表現出多態特性。
注意:只有調用子類重寫父類的方法才表現出多態性,直接訪問公開的同名實例變量時不表現多態性,返回的數據看左邊類型(編譯類型)。