這篇博客將會涉及到:
- 繼承的概念和實現
- super關鍵字
- 方法重寫—Override
- Object常見方法
繼承的概念:
生活中,繼承的概念隨處可見,繼承需要符合的關系:is-a;父類更通用、子類更特殊更具體。就比如說:動物是一個類,那么它的子類可以是:食草動物、食肉動物。
- 對于java語言來說,繼承背后的思想就是基于已存在的類來構建新類,當從已存在類繼承時,就重用了它的方法和屬性,還可以添加新的方法和屬性來定制新類以應付需求。約定: 從其他類導出的類叫做子類,被導出的類叫做父類。在java中,除了Object類之外,所有類都是子類,都只有唯一父類。就是在創建類的時候,如果不寫類繼承自哪一個類,系統會默認的認為是Object的子類,通過下圖方法可查看,一個類繼承的父類:
- 繼承在OOP中不可或缺(不寫繼承自哪一個類會默認繼承Object類),創建一個類時總是在繼承,繼承的意義: 代碼重用、體現不同的抽象層次。父子類關系: 父類更抽象,更一般、子類更具體,更特殊。
- 在java語言中,用extends 關鍵字來表示一個類繼承了另外一個類,如下:
public class Teacher extends Person{
}
- extends使用示例:
package fhn.demo.java;
class Person{String name;String address;public void eat(){System.out.println("人吃飯");}public void drink(){System.out.println("人喝水");}
}
class Student extends Person{String address;float score;void goToSchool(){System.out.println("去上學");}
}
public class Test {public static void main(String[] args) {Person p=new Person();Student s=new Student();p.name="人";p.eat();p.drink();s.name="學生";s.eat();s.drink();s.goToSchool();}
}
super關鍵字:
super關鍵字的特點:
- super和this關鍵字的特點類似;super代表的是父類對象的引用
- 當子父類的成員出現同名時,可以通過super來區分
- 子類構造方法中,通過super關鍵字調用父類的構造方法
- 在子類構造方法中默認都是調用了父類的構造方法
super()
這個是無參數的,當想調用父類的構造方法是有參數的時候就要自己在子類的第一行輸入super(參數)
來調用父類的構造方法。 - 強調: 當構造一個子類對象的時候一定會先調用父類的構造方法來初始化父類的字段。調用父類構造方法的語句必須是子類構造方法中的第一條指令。
- 注意: 子類只能調用父類的構造方法來初始化參數,當然也可以在自己的構造方法中添加一些父類構造方法沒有的語句
- java繼承之私有權限:父類的私有屬性和私有方法不會被子類繼承,但是可以通過父類的公有方法來間接訪問父類的私有屬性
class Person{String name;String address;//public Person(){};//無參構造方法,當不寫帶參數的構造方法,系統會默認的添加無參構造方法public Person(String name,String adress) {//父類的構造方法this.name=name;this.address=adress;System.out.println("父類構造方法被調用");}public void eat(){System.out.println("父類的人吃飯");}public void drink(){System.out.println("父類的人喝水");}
}
class Student extends Person{float score;public Student(String name,String adress) {//子類的構造方法super(name,adress);//在子類的構造方法里面通過super調用父類的構造方法//調用父類構造方法的語句必須是子類構造方法中的第一條指令。/** this.name=name;* this.adress=adress;//這種寫法不可以,當父類里面存在無參構造方法時* //子類需要通過super關鍵字來調用父類的構造方法在自己的構造方法里面進行參數的初始化* */System.out.println("子類構造方法被調用");//當然也可以在自己的構造方法中添加一些父類構造方法沒有的語句}void goToSchool(){System.out.println("去上學");}public void eat(){super.eat();//當子父類的成員出現同名時,可以通過super來區分System.out.println("子類的人吃飯");}
}
public class Main {public static void main(String[] args) {Person p=new Person("你們","北京");Student s=new Student("我們","河北");//當構造一個子類對象的時候一定會先調用父類的構造方法來初始化父類的字段p.eat();p.drink();s.eat();s.drink();s.goToSchool();}
}
Object常見方法:
- java中,所有的類都可以直接或間接繼承自
java.lang.Object
類,可以說Object是java中所有類的祖先即根類。 - java任何類中都繼承了Object類中的方法,主要有:
toString()
、equals()
、hashcode()
、clone()
、getClass()
、finalize()
- String toString(): 返回該對象的字符串描述信息。默認輸出格式是:類名[字段值,字段值…]。只要對象與一個字符串通過“+”連接,系統就會自動調用toString獲得對象的字符串描述符。常被改寫:可以根據用戶的需求對其進行重寫。
- Boolean equals(): OBject類原始功能是實現判斷兩個對象是否具有相同的引用,要求判斷兩個對象狀態的相等性。
class Person{String name;String address;//public Person(){};//無參構造方法,當不寫帶參數的構造方法,系統會默認的添加無參構造方法public Person(String name,String adress) {//父類的構造方法this.name=name;this.address=adress;System.out.println("父類構造方法被調用");}public String toString() {//在子類里面對Object類父類toString方法進行重寫//默認返回父親的toString,return super.toString();return "person message:"+name+address;}public boolean equals(Object arg0) {//對equals進行重寫,判斷兩個類里面的內容知否一致// TODO Auto-generated method stub//return super.equals(arg0);Person p=(Person) arg0;if(this.name==p.name&&this.address==p.address)//java中可用==表示兩個字符串是否相等,在C語言中用strcmpreturn true;elsereturn false;}
}
public class Main {public static void main(String[] args) {Person p=new Person("你們","北京");/*不對toString方法進行重寫* System.out.println(p.toString());//輸出:Person@659e0bfd----Person類名、@659e0bfd是類的內存地址//若果有包名,還會將包名打印出來//默認打印這個對象的地址和相關信息,返回值是字符串類型*///對toSting方法進行重寫System.out.println(p.toString());//輸出--你們北京Person p2=new Person("你們","北京");/** 不對equals進行重寫System.out.println(p2.equals(p));返回的是Boolean類型的值,比較的是兩個對象的地址值不是比較兩個類的內容是否一致*///方法重寫后輸出:System.out.println(p2.equals(p));//重寫方法后,比較的是兩個對象的內容是否一致}
}
繼承學習綜合練習:
class Wapon
{String name;void WaponAttack(){System.out.println("武器攻擊"); }}
class K98 extends Wapon
{void WaponAttack()//重寫父類方法{System.out.println("98K攻擊");System.out.println("一擊斃命");}
}
class Dao extends Wapon
{void WaponAttack()//重寫父類方法{System.out.println("砍刀攻擊");System.out.println("刀刀見血");}
}
class Play
{String name;String level;Wapon wapon;int id;void attack(){System.out.println("玩家攻擊");wapon.WaponAttack();}
}
public class Main {public static void main(String[] args) {Play p1=new Play();p1.name="玩家一";p1.level="青銅";//p1.wapon =new Wapon();p1.wapon =new Dao();//多態p1.attack();//如果直接寫這句話,會出現空指針異常,要先給wapon賦值再使用System.out.println();p1.wapon =new K98();//多態p1.attack();//如果直接寫這句話,會出現空指針異常,要先給wapon賦值再使用}
}
java繼承的簡單工廠模式:
- 工廠模式之前在寫智能家居的代碼的時候用C語言加鏈表實現過,在用C語言實現時,就是構建了連個鏈表分別代表指令工廠和控制工廠,然后將設備通過添加節點的方式插入到對應的鏈表,在使用的時候,通過設備或者指令名稱進行查找然后調用相關的函數,實現起來比較繁瑣。
- 而在java中有了繼承的概念,就可以將那些結點看作是繼承自一個父類的子類,然后構建一個查找的類對所需要的內容進行查找即可,查找到返回查找的對象的引用,然后就可以調用相關的方法。實現起來比較簡單。
class Fruit //相當于之前用C語言寫的鏈表的頭部
{String name;void grow(){System.out.println("野蠻生長的水果"); }public Fruit(String name){this.name=name; }
}
class Apple extends Fruit
{public Apple(String name){super(name);}void grow()//對父類方法進行重寫{System.out.println("野蠻生長的"+name);}
}
class Peach extends Fruit
{public Peach(String name){//構造方法調用父類的構造方法super(name);}void grow()//對父類方法進行重寫{System.out.println("野蠻生長的"+name);}
}
class Factory //在這個類里面進行對水果的查找
{public static Fruit getFruit(String name){if(name=="蘋果")return new Apple(name);//這里有用到多態else if(name=="桃")return new Peach(name);else{return null;}}
}
public class Main {public static void main(String[] args) {if(Factory.getFruit("蘋果")!=null){System.out.println("找到了蘋果");Factory.getFruit("蘋果").grow();}if(Factory.getFruit("桃")!=null){System.out.println("找到了桃");Factory.getFruit("桃").grow();}if(Factory.getFruit("葡萄")==null){System.out.println("沒有該水果");}}
}
抽象類:
Java中可以定義沒有方法體的方法,該方法由子類來具體實現。該沒有方法體的方法我們稱之為抽象方法,含有抽象方法的類我們稱之為抽象類。
- 抽象方法的特點:① 只有方法頭沒有方法體的方法稱為抽象方法。② 抽象方法用
abstract
來修飾。③ 抽象方法代表一種不確定的操作或者行為。④ 抽象方法不能被調用。⑤ 抽象類代表一種抽象的對象類型。 ⑥ 抽象類不能實例化 ⑦ 抽象類中可以有具體方法,可以沒有抽象方法。
abstract class Demo1
{abstract public void method();//抽象方法只能放在抽象類里面,在這里聲明抽象方法就要將類聲明為抽象類
}
class Demo2 extends Demo1 //抽象類使用的時候一般是使用新的類繼承抽象類,然后重寫里面的抽象方法
{public void method(){System.out.println("Demo2重寫的Demo1的方法");}
}
public class Main {public static void main(String[] args) {/** 抽象類在使用的時候不能實例化* 添加函數體則如下所示,對里面的抽象方法進行補充,這種方式算不上實例化,是做的一個匿名的內部類* Demo1 d=new Demo1(){public void method() {}};*/Demo2 d=new Demo2();d.method();}
}
模板方法模式(也是抽象類的一種使用方法):
定義: 一個模板方法用一些抽象的操作定義一個算法,而子類將重定義這些操作以提供具體行為。
意圖: 定義了一個操作中的一個算法框架,把一些步驟推遲到子類去實現,模板方法讓子類不需要改變算法結構。
具體的代碼示例:
abstract class Contrl //這個控制類只是做一個模板放到這里,因為每一個抽象方法實現不一樣
{abstract void initUsart();abstract void getComand();abstract void openCure();abstract void openLight();abstract void OpenTv();public void work() //這個方法里面是一系列的控制流程里面是抽象方法{initUsart();getComand();openCure();openLight();OpenTv();}
}
class STM32contrl extends Contrl //繼承自contrl這個類然后會讓我們實現父類這個抽象類的所有抽象方法
{void OpenTv() {// TODO Auto-generated method stubSystem.out.println("STM32 OpenTv");}void getComand() {// TODO Auto-generated method stubSystem.out.println("STM32 getComand");}void initUsart() {// TODO Auto-generated method stubSystem.out.println("STM32 initUsart");}void openCure() {// TODO Auto-generated method stubSystem.out.println("STM32 openCure");}void openLight() {// TODO Auto-generated method stubSystem.out.println("STM32 openLight");}
}
class C51contrl extends Contrl //繼承自contrl這個類然后會讓我們實現父類這個抽象類的所有抽象方法
{void OpenTv() {// TODO Auto-generated method stubSystem.out.println("C51 OpenTv");}void getComand() {// TODO Auto-generated method stubSystem.out.println("C51 getComand");}void initUsart() {// TODO Auto-generated method stubSystem.out.println("C51 initUsart");}void openCure() {// TODO Auto-generated method stubSystem.out.println("C51 openCure");}void openLight() {// TODO Auto-generated method stubSystem.out.println("C51 openLight");}
}
public class Main {public static void main(String[] args) {STM32contrl stm32=new STM32contrl();stm32.work();//STM32contrl這個類也繼承了Contrl的work方法,該方法是總的控制流程C51contrl c51=new C51contrl();c51.work();}
}
接口的概念和作用:
接口語法:interface 接口{ //公有靜態方法、抽象方法 }
接口的特點: ① 接口中只能存放靜態常量和抽象方法 ② java接口是對功能的拓展 ③ 通過實現接口,java類可以實現多實現 ④ 一個類可以同時繼承(extends)
一個父類并且實現(implement)
多個接口 ⑤ 接口與接口之間可以使用extends
實現繼承。
接口與抽象類的區別:
- 抽象類和具體實現之間是一個繼承關系,也就是如果采用抽象類的方式,則父類和子類在概念上應該是相同的。
- 接口和實現類在概念上不要求相同,接口只是抽取相互之間沒有關系的類的共同特征,而不去關注類之間的關系,它可以使沒有層次關系的類具有相同的行為。
- 抽象類是對一組具有相同屬性和行為的邏輯上上有關系的事物的一種抽象,而接口則是對一組具有相同屬性和行為的邏輯上不相關的事物的一種抽象。
interface Move
{abstract void eat();abstract void drink();
}
class man implements Move
{public void eat() {System.out.println("人類吃"); }public void drink() {System.out.println("人類喝"); }
}
class animal implements Move
{public void eat() {System.out.println("動物吃"); }public void drink() {System.out.println("動物喝"); }
}
public class Main {public static void main(String[] args) {new man().drink();new animal().eat(); }
}
內部類:
- 概念: 所謂的內部類(Inner Class),顧名思義,就是將一個類定義在另一個類的內部,內部的類稱之為內部類。
- 特點: ① 內部類可以很好的實現隱藏,可以使用
protected、private
修飾符。② 內部類可以直接訪問外部類所有成員包括私有成員。③ 外部類不能直接訪問內部類的成員,必須首先建立內部類對象才能訪問。 - 成員內部類及應用: ① 成員內部類屬于外部類的實例成員,成員內部類可以有
public、private、default、protected
權限修飾符。在成員內部類中訪問外部類的成員方法和屬性,要使用“外部類名.this.成員方法
”和“外部類名.this.成員屬性
”的形式 。② 創建成員內部類的實例使用“外部類名.內部類名 實例=外部類實例名.new 內部類 構造方法(參數)
”的形式。 - 成員內部類有以下限制: ① 成員內部類不能與外部類重名 ② 不能在成員內部類中定義static屬性,方法和類(static、final形式的常量定義除外),因為一個成員內部類實例必然與一個外部類實例關聯,static成員完全可以移到其外部類中去。
- 在一個java文件中只能有一個public類,如果有多個就要放在其他文件中
class Outer
{int data;public Outer(int data) {this.data=data;}void printfData(){System.out.println("外部類打印外部類data:"+data);}class Inner{int data;public Inner(int data) {this.data=data;}void printfData(){System.out.println("內部類打印外部類的data:"+Outer.this.data);System.out.println("內部類打印內部類的data:"+data);}void printouter(){System.out.println("內部類調用外部類方法打印data如下:");Outer.this.printfData();}}
}
public class Main {public static void main(String[] args) {// 創建成員內部類的實例使用 外部類名.內部類名 實例=外部類實例名.new 內部類 構造方法(參數)的形式。Outer Out1=new Outer(10);//創建成員內部類的實例得先創建外部類的實例Outer.Inner In1=Out1.new Inner(20);Out1.printfData();In1.printfData();In1.printouter();}
}
匿名內部類及應用:
- 內部匿名類: 一個帶具體實現的父類或者父接口的匿名的子類對象。
- 匿名內部類的特點: ① 匿名內部類是沒有名稱的內部類,沒辦法引用他們。必須在創建時,作為new語句的一部分來聲明并創建他們的實例。② 匿名內部類必須繼承一個類(抽象的、非抽象的都可以)或者實現一個接口,所有的父類(或者父接口)是抽象類,則匿名內部類必須實現其所有抽象的方法。
- 語法: 實例一個匿名內部類---->
new interface/superclass(){類體}
這形式的new語句聲明一個新的匿名類,它對一個給定的類進行擴展,或者實現一個給定的接口,并同時創建該匿名類的一個新實例。
abstract class Demo
{abstract void printfInfo();abstract void interPrintf();//在接口中默認是抽象方法
}
interface Demo2
{void interPrintf();//在接口中默認是抽象方法
}
public class Main {public static void main(String[] args) {new Demo(){void printfInfo() {System.out.println("這不是demo類的實例化,而是匿名內部類的方法");}void interPrintf() {System.out.println("所有的父類(或者父接口)是抽象類,則匿名內部類必須實現其所有抽象的方法");}}.printfInfo();// Demo d=new Demo(){這種形式是以多態的形式創建匿名內部類,new Demo()是Demo 的子類的對象,在這里用父類引用來接收的
// void printfInfo() {
// System.out.println("這不是demo類的實例化,而是匿名內部類的方法");
// }
// void interPrintf() {
// System.out.println("所有的父類(或者父接口)是抽象類,則匿名內部類必須實現其所有抽象的方法");
// }
// };
// d.interPrintf();
// d.printfInfo();new Demo2(){public void interPrintf() {System.out.println("這不是接口的實例,而是匿名內部類的方法"); }}.interPrintf();}
}