Java 面向對象
類:
是構造對象的模板或藍圖;
類構造對象的過程稱為創建對象的實例;
用Java編寫的所有代碼都位於某個類的內部;
封裝:
將實例域(屬性)和方法包在一起;
對對象的使用者隱藏了數據的實現方式;
關鍵在於:絕對不能讓類中的方法直接地訪問其它類的實例域,程序僅通過對象的方法與對象數據進行交互;即使用方法將類的數據隱藏起來,控制其他類對該類的修改和訪問數據的程度;就是說,一般獲取、修改對象的屬性都是通過方法來操作;
對於每個特定的實例(對象)都有一組特定的實例域值,這些值的集合就是這個對象的當前狀態;
優點:針對域
避免域被其他類的方法直接訪問;(所以一般都定義為私有的,只通過本類中的方法進行調用和修改)
可以改變內部實現,除了該類的方法之外,不會影響其他代碼;
更改器方法可以執行錯誤檢查;
註意:
不要編寫返回引用可變對象的訪問器方法;如果需要返回一個可變對象的引用,應該首先對它進行克隆;
繼承:
子類會繼承父類所有的內容(包括所有屬性和方法,但不包括構造方法),但不一定能直接使用;
java只支持單繼承,extends後面只能跟一個類;
舉例:
類B繼承類A;
類B創建的實例,可以調用和類A中相同的公有的方法和公有的實例域;但不能調用或設置類和A中相同的私有實例域和私有方法;
一個類的所有對象,每個對象都有自己的一份實例域,但所有對象共用那些方法;
繼承的特性:
1.當一個類繼承自另一個類,子類中沒有顯式定義和父類相同的方法(方法名、參數、返回值都一樣)時。用子類的對象調用方法時,會首先在子類中查找,如果子類中沒有該方法,再到父類中查找。
實例(1):
1 public class Demo1 2 { 3 // 父類定義的 print()方法 4 public void print() 5 { 6 System.out.println(123); 7 } 8 } 9 10 11 public class Demo2 extends Demo1 12 { 13 //子類沒有顯式定義和父類相同的方法(方法名、參數、返回值類型都一樣) 14 } 15 16 17 public class Test 18 { 19 public static void main(String[] args) 20 { 21 Demo2 demo = new Demo2(); 22 // 最後打印出的結果是 123 23 demo.print(); 24 } 25 }
實例(2):
public class Demo1 { // 父類定義的 print()方法 public void print() { System.out.println(123); } } public class Demo2 extends Demo1 { // 子類顯式定義和父類相同的方法(重寫) public void print() { System.out.println(456); } } public class Test { public static void main(String[] args) { Demo2 demo = new Demo2(); // 最後打印出的結果是 456 demo.print(); } }
2.子類與父類之間構造函數的使用規則:
(1).Java中每個類都有一個構造函數;如果類中沒有顯式定義構造函數,則編譯器會默認提供一個無參構造函數;
(2).子類繼承父類時,必須在構造函數中調用父類的構造函數;
(3).父類沒有顯式定義構造函數,只有一個默認的無參構造函數,那麽子類繼承父類時,也是通過在默認的無參構造函數調用父類的構造函數;
public class Demo1 { /** * 這是編譯器默認提供的無參構造函數 * 這個構造函數是隱藏的,看不到,現在讓它顯式出來只是為了看到無參構造函數的樣子 * 這裏的super()調用的是 Object 類的構造方法 * 父類並沒有顯式定義構造函數 */ public Demo1() { super(); } } public class Demo2 extends Demo1 { /** * 子類繼承父類,通過編譯器提供的默認構造方法調用父類的構造方法 * 這裏構造方法也是隱藏的 * 這裏的 super() 調用的是 Demo1 類的構造方法 */ public Demo2() { super(); } }
(4). 父類顯示定義了帶參(必須是帶參)構造函數,那麽子類繼承父類時,也必須顯示定義一個帶參構造函數,在這個構造函數中調用父類的構造函數;
public class Demo1 { /** * 父類顯示定義了一個帶參構造函數 */ public Demo1(String s) { super(); System.out.println(s); } } public class Demo2 extends Demo1 { /** * 子類必須顯示定義一個帶參構造函數來調用父類的構造函數 * 這裏的 super(s) 就是調用父類的帶參構造函數,s是實參 */ public Demo2(String s) { super(s); } }
3.當一個方法只在父類中定義時,調用該方法時使用到的屬性是父類的屬性;如果該方法中又調用了其他方法,那麽還是按照之前的順序,先在子類中查找,再在父類中查找。
public class Demo1 { int x = 6; private int y = 2; public Demo1(int a) { x = a; } int getz() { int z; z = x / y; return z; } void show() { System.out.println("x=" + x); System.out.println("y=" + y); // 方法中調用了其它方法 System.out.println("z=" + getz()); } } public class Demo2 extends Demo1 { // 重新定義了 x,y 變量 int x = 3, y = 5, z; public Demo2(int a) { super(a); } // 重寫了 getz() 方法 int getz() { z = x + y; return z; } // 定義獨有的方法 public void print() { System.out.println("x = " + x); System.out.println("y = " + y); System.out.println("z = " + z); } } public class Test { public static void main(String[] args) { Demo1 demo1 = new Demo1(10); Demo2 demo2 = new Demo2(9); demo1.show(); /** * 打印出的結果: * x=9:子類 Demo2 通過構造方法將父類 Demo1 中的 x 屬性值設為9,子類對象調用的 * show() 方法在子類中沒有重新定義(重寫),調用的是繼承自父類的 show()方法, * 則在父類中的 show() 方法中調用的 x 屬性就是父類中的屬性,值為 9; * y=2:同樣的道理,子類調用的 show() 方法在子類中沒有重新定義,所以 show() 方法 * 中調用的 y 屬性是父類中的 y 屬性,值為 3; * z=8:show() 方法中的 getz() 方法在子類和父類中都有,則優先調用子類中的 getz() * 方法,那麽子類中的getz()放用到的 x,y,z 屬性就是子類中定義的 x,y,z 屬性,x,y 的 * 值分別為 3和5,所以 y 計算出來的值是 8; */ demo2.show(); /** * 調用子類特有的方法,那方法裏面用的屬性都是子類重新定義好的屬性 */ demo2.print(); } } // 最後打印出的結果: // x=10 // y=2 // z=5 // x=9 // y=2 // z=8 // x = 3 // y = 5 // z = 8
Java 面向對象