面向物件中的一些概念的理解
阿新 • • 發佈:2021-12-12
今天回顧的內容,可能相對於前面的內容來說在理解上需要花費一點功夫,但面向物件也是屬於打基礎的部分,學好雖然不能夠加分,但是沒有掌握到這方面的知識,在後續的基礎學習中,會有一些問題。那,我們開始回顧今天的內容吧!!
1. 構造方法 特點:與類同名而沒有返回值型別 作用:建立物件package cn.tedu.object; public class PersonDemo { public static void main(String[] args) { //構造方法 --- 建立物件的 //呼叫構造方法建立 Person 物件 Person p = new Person("翠花"); p.name = "如花";//物件點出來的是一個成員變數 p.eat(); Person p2 = new Person(); p2.eat(); } } class Person{ String name; int age; char gender; String no; //身份證號,數字,還很多有的人的後面是 x //在類中沒有手動指定構造方法的時候,那麼在編譯的時候會自動新增一個無參的構造方法 //沒有返回值型別,與當前類同名 //構造方法中可以寫 return,用於規避一些不合常理的資料 public Person(){ } //在程式碼中手動指定了含參構造,那麼就不會再預設新增無參構造 public Person(String name){//開發了網站,用的人都要註冊,寫一個 user 類,使用者的基本資訊建立的時候就要寫進來 //遵循就近原則 this.name = name; // Warning --- 警告 --- 智慧工具編譯到這兒的時候認為這個地方可能存在問題, //但是不影響程式的正常執行 } //Person p = new Person("珠子",-18); public Person(String name,int age){ this.name = name; if(age < 0){ return; } this.age = age; } public void eat(){ System.out.println("吃飯"); } }
package cn.tedu.object; public class ThisDemo { public static void main(String[] args) { Student s1 = new Student("Amy"); System.out.println("s1:" + s1); Student s2 = new Student("Sma"); System.out.println("s2:" + s2); s1.name = "Amyy"; } } class Student{ String name; int age; String no;//學號 //用 this 代替一個具體的物件 //this 代表當前在活動的物件 //this 在本類中呼叫本類中的屬性和方法 public Student(String name){ this.name = name; System.out.println("this:"+this); } public Student(String name, int age){ } public Student(String name, int age, String no){ //this 呼叫的普通方法而不是構造方法 //this.Student(name,age); //this(引數列表) --- this 語句 //表示呼叫本類中對應形式的構造方法 //必須放在構造方法的首行 this(name,age); this.no = no; } }
package cn.tedu.object; public class CodeDemo { public static void main(String[] args) { Baby b1 = new Baby(); Baby b2 = new Baby("鐵蛋"); } } //定義一個代表嬰兒的類 class Baby{ String name; //構造程式碼塊/初始化程式碼塊 //無論利用哪個構造方法建立物件,構造程式碼塊都會先於構造方法執行 //如果每一個構造方法都有一些要初始化的操作,可以將它們提取到構造程式碼塊中執行 { this.cry(); this.eat(); } public Baby(){ System.out.println("running~~~"); } public Baby(String name){ // this(); this.name = name; //this.cry(); //this.eat(); } public void cry(){ System.out.println("這個嬰兒在哇哇的哭"); } public void eat(){ System.out.println("這個小孩在吃奶"); } }
本類中 | 子類中 | 同包內中 | 其他類中 | |
public | 可以 | 可以() | 可以(你的室友) | 可以 |
protected(你自己的一些東西,你們寢室的掃帚) | 可以 | 可以 | 可以 | 不可以(其他寢室的,來搶劫啊) |
預設(沒有給定的形式)(你們家的門,或者窗) | 可以 | 同包子類可以,不同包子類不行 | 可以 | 不可以(你來弄,入室搶劫啊) |
private(相當於自己的小祕密,私房錢,青春回憶) | 可以 | 不可以 | 不可以 | 不可以(走在路上一人說給我點錢花唄,不行) |
package cn.tedu.extendsx.b; import cn.tedu.extendsx.a.A; public class E extends A{ public static void main(String[] args) { D d = new D(); //物件的宣告類是 D類,所以d物件所對應的子類是 D類 //因此d物件使用 m方法需要在對應的子類 D類中使用 //子類物件使用的時候必須在對應的子類中使用 //d.m(); } } //public class E{ // public static void main(String[] args) { // D d = new D(); // //雖然D通過繼承A可以使用A類中m方法,但是m方法最終定義在A類中 // //m方法的許可權是protected:本類中、子類中、同包類中 // //m方法的本類是A類,E和A是本類中? --- 不是 // //m方法是在E類中,E是A的子類嗎? --- 不是 // //E類所在的包是b包,A類所在的包是a包,所以E和A是同包類嗎1?---不是 // //d.m(); // } //}練習:定義一個類表示矩形(長方形),提供獲取周長和麵積的方法
package cn.tedu.fengzhuang; public class Rectangle { public static void main(String[] args) { GetRectangle rec = new GetRectangle(2, 4); System.out.println("周長:"+rec.getLong()+" 釐米,面積:"+rec.getSqure()+" 平方釐米"); } } class GetRectangle{ private double width; private double height; public double getWidth() { return width; } public double getHeight() { return height; } public GetRectangle(double width, double heigth){ if(width <= 0 || heigth == 0) return; this.width = width; this.height = heigth; } public double getLong(){ return 2 * (width + height); } public double getSqure(){ return width * height; } }4.2 繼承 如果一些類中含有相同的程式碼,那麼可以將這些相同的程式碼提取到一個新的類中,然後通過 extends 關鍵字讓原來的類和新的類產生關係 --- 繼承。 通過繼承,原來的類就稱之為了子類(派生類),新的類就成了父類(超類/基類)。 子類通過繼承父類可以使用父類中的一部分方法和屬性 注意:子類繼承了父類的全部的資料域(方法 + 屬性),但是繼承之後只有一部分資料域對子類可見。 在 Java 中,支援的是類和類之間的單繼承 -> 一個子類只能繼承一個父類,但是一個父類可以有多個子類 單繼承一定優於多繼承嗎? --- 不對,C++ 中採用的是多繼承,但是現在幾十年的時間了,C++ 仍然採用多繼承。 ---比如,一個人要到一個醫院上班(這個 Person 繼承這個 Doctor 類(有一個treat() 方法)),要到醫院去上課(這個 Person 繼承 Teacher 類(有一個 teach() 方法)),如果是單繼承,選擇繼承了 Doctor 了,Teacher 類中的程式碼就要在 Person 中再寫一遍。 ---多繼承比單繼承能夠更好的提高程式碼的複用性 ---再比如,如果是多繼承,無論是 Doctor 還是 Teacher 都有一個相同名字 salary() 方法(這兩個類的計算方法不一樣),但是我想知道工資(p.salary() 並不確定是哪一個) ---多繼承導致在呼叫方法的時候可能產生歧義 優勢:提高程式碼的複用性,避免方法的呼叫產生歧義 4.2.1 Super 關鍵字 在子類中用於表示父類物件的引用,可以在子類中呼叫父類中的方法的屬性。 super 語句--- 子類在繼承父類之後,子類的構造方法中會含有一個 super 語句。如果沒有沒有手動指定 super 語句,那麼預設使用super()呼叫父類無參的構造;如果父類只提供了含參構造,那麼父類就必須手動提供對應形式的 super 語句---super 語句必須在子類構造方法的首行 4.2.2 方法的重寫/覆蓋 在父子類中存在了方法簽名相同的非靜態方法。遵循“兩等兩小一大 ”原則: 1.方法簽名相同 2.如果父類中的方法的返回值型別是基本型別/void,那麼子類重寫的方法的返回值型別與父類一致 3.如果父類中的方法的返回值型別是引用型別,那麼子類在重寫方法的時候,返回值型別要麼與父類一致,要麼是父類方法返回值型別的子類 class A{} class B extends A{} class C{ public A m(){return null;} } class D extends C{ public B m() { return null;} } 4.子類重寫的方法的許可權修飾符的範圍要大於等於父類中對應方法的許可權修飾符的範圍 class A{ public void m(){ } } class B extends A{ public int m(){ return 0;} } 注意:如果父類中的方法用 private 修飾,那麼這個方法對子類不可見,所以此時與子類中的方法構不成重寫
package cn.tedu.extendsx; public class ExtendsDemo { public static void main(String[] args) { Cat c = new Cat(); //通過繼承,子類可以使用父類中的屬性和方法 c.eat(); } } //父類 class Pet{ String name; String color; public Pet(String name){ } public Pet(String name, String color){ } public void eat(){ System.out.println("在吃東西"); } } //利用extends關鍵字讓原來的類與提取出來的新的類產生了聯絡 --- 繼承 //子類 class Cat extends Pet{ public Cat(){ //在子類構造方法中,如果沒有手動指定,那麼預設新增super() //super 語句 --- 表示呼叫父類中對應的形式的構造方法 //super() --- Pet() //如果父類中只提供含參構造,那麼子類中就必須手動提供對應形式的構造方法 super("波斯貓"); } public void drink(){ //通過super代表父類物件,通過父類物件呼叫父類中的屬性和方法 super.eat(); System.out.println("吃完東西喝點水"); } public void catches(){ System.out.println("這隻貓在撓沙發"); } } //子類 class Dog extends Pet{ public Dog(){ //super("金毛","綠色"); super("二哈");//this();這兩個不能夠同時出現 super.color = "綠色"; } public void bark(){ System.out.println("這隻狗在叫"); } }4.3 多型 (在未來的基礎階段你感覺不到用處,但在後面的大資料中,解耦會涉及到)一個介面建了之後,實現的具體方式就由其他分別體現(使用子類都統一用一個父類接收,在父類中判斷接收的具體物件),兩個介面,一個加分,一個加密,子類造型成父類,在父類中判斷是不是這個子類,是就加分。編譯時,不管子類是什麼,後面交給程式設計師就具體實現相應的類。只有在執行時,便於維護。 4.3.1編譯時多型:方法的過載 add(2,4) -> add(int, int); add(3,1,7) ->add(int, int, int) //編譯時期就知道這個方法有沒有 4.3.2執行時多型:向上造型和方法的重寫 --- 基於繼承的 注意:如果使用向上造型來建立物件,那麼這個物件所能呼叫的方法看的是父類中的宣告,方法如何執行看的是子類中的實現過程
package cn.tedu.duotai; public class DuotaiDemo { public static void main(String[] args) { //父類宣告物件,用子類建立物件,利用向上造型來建立的這個物件 //物件在編譯過程中並不會檢查到底使用的是哪個子類,在編譯期間只會檢查宣告類和實現類之間是否有繼承關係, //直到執行的時候才會檢查具體的子類然後根據子類來分配空間 Pet p = new Cat(); //p.catches(); //當使用向上造型來建立物件的時候,只能使用父類中宣告的方法,而不能使用子類中單獨定義的方法 p.eat(); } } class Pet{ public void eat(){ System.out.println("在吃東西~~~"); } } class Cat extends Pet{ @Override public void eat(){ System.out.println("這隻貓在吃草~~~"); } public void catches(){ System.out.println("這隻貓在抓老鼠"); } } class Dog extends Pet{ @Override public void eat(){ System.out.println("這隻狗在吃貓~~~"); } public void bark(){ System.out.println("這隻狗在叫"); } }重寫的理解 1.子類重寫的方法的許可權修飾符的範圍要大於等於父類中對應方法的許可權修飾符 2.如果父類中的方法的返回值型別是引用型別,那麼子類在重寫方法的時候,返回值型別要麼與父類一致,要麼是父類方法返回值型別的子類 注意:Java 中所有的基本型別之間沒有繼承關係,之所以能夠自動提升,是因為所表示的範圍是否能夠包含
package cn.tedu.extendsx; public class OverrideDemo { private void mian() { // TODO Auto-generated method stub Teacher t = new Teacher(); //子類物件是呼叫重寫之後的方法 t.work(); } } //表示職業的類 class Profession{ public void work(){ System.out.println("在工作~~~"); } } class Teacher extends Profession{ //父類中的方法寫的比較簡單,子類需要對父類中的方法進行擴充套件 @Override //@ 註解 //@Override 這個註解是用於校驗當前方法是否構成了重寫 public void work(){ System.out.println("這個老師在誨人不倦"); } }