JAVA面向对象编程(1)
繼承-------對共性抽取,對代碼進(jìn)行重用
定義:是面向?qū)ο蟮倪^程中是代碼可以進(jìn)行復(fù)用的最重要的手段,它允許程序員在保持原有類特性的基礎(chǔ)上進(jìn)行擴(kuò)展,增加新功能,這樣產(chǎn)生的新的類,叫做派生類/子類
1)繼承我們是使用extends關(guān)鍵字我們的子類會將父類除構(gòu)造方法之外的全部繼承,private修飾的字段是可以繼承于子類的,但是不可以訪問;
2)當(dāng)我們的子類繼承父類之后,必須要添加自己特有的成員,體現(xiàn)出與基類的不同,否則就沒有必要進(jìn)行繼承了
在這里面我們還是需要注意一些問題:(沒有涉及到向上轉(zhuǎn)型或者向下轉(zhuǎn)型)
1)在我們的子類方法中通過this關(guān)鍵字或者通過子類對象來進(jìn)行訪問成員的時候,我們會優(yōu)先訪問自己的成員變量
2)如果我們的訪問的成員變量子類中沒有,那么我們就進(jìn)行訪問父類中所繼承下來的,如果說我們的父類中也沒有定義,那么我們就直接編譯報錯
3)如果說我們的訪問的成員變量與我們的父類的成員變量同名,那么我們就直接優(yōu)先訪問自己的
4)我們?nèi)绻f我們的子類對象訪問父類和子類的不同名的方法的時候,我們優(yōu)先在子類里面找,找到就訪問,找不到就去父類里面找,如果說我們的父類也沒有那么就直接報錯
5)通過子類對象訪問父類和子類同名的方法的時候,如果父類和子類同名方法的參數(shù)列表不同,構(gòu)成重載,那么我們直接根據(jù)調(diào)用方法選擇進(jìn)行傳遞的參數(shù)選擇不同的方法,如果沒有就進(jìn)行直接報錯
6)我們通過子類對象進(jìn)行訪問父類和子類的同名方法的時候,如果父類和子類的同名方法的參數(shù)列表,返回值都相同,那么我們直接遵循就近原則,直接訪問子類中的方法,不會訪問父類中的方法
7)在Java中是單繼承,不支持多繼承的,不能繼承兩個類以上的類
class Father{public String name;public int age;public Father(String name,int age){this.name=name;this.age=age;} } class Child extends Father{public Child(){super("李佳偉",90);//調(diào)用父類帶有兩個參數(shù)的構(gòu)造方法} } super()在子類幫助父類進(jìn)行構(gòu)造的時候只能放在構(gòu)造方法里面,況且只能放在構(gòu)造方法的第一行,不能出現(xiàn)在static代碼塊里面主要是我們在設(shè)計不好的時候,或者我們因場景需要,父類和子類中可能存在相同的名字的成員,我們要想在子類方法中訪問父類的同名成員的時候,我們該怎么操作呢?我們直接訪問是訪問不到的,因為局部有限的原則,我們會優(yōu)先訪問子類中的成員
1)所以我們在Java中提供了super關(guān)鍵字,該關(guān)鍵字的主要作用是,在我們的子類方法中訪問我們的父類的實例屬性和方法的
2)在子類中,如果沒有顯式指定super()方法,那么子類會隱藏生成一個super()方法,用來調(diào)用父類無參的構(gòu)造方法,這就是咱們每一個類在實例化的時候之所以可以調(diào)用到Object類的原因,就是默認(rèn)是super方法起作用了
3)為什么要把super()方法放到首行呢?因為只要將super()方法放到首行,那么在實例化子類的時候才可以保證父類已經(jīng)被初始化過了
1)super(),調(diào)用父類的構(gòu)造方法,幫助父類進(jìn)行構(gòu)造,必須放到第一行
2)super.data;訪問父類的屬性
3)super.func(),訪問父類的方法
this表示當(dāng)前對象的引用
1)this()調(diào)用自己的構(gòu)造方法
2)this.data調(diào)用自己的屬性
3)this.func(),調(diào)用當(dāng)前對象的方法
protected關(guān)鍵字
子類繼承了出構(gòu)造方法的所有方法,但是如果父類的字段中出現(xiàn)了有private修飾的字段,此時子類就無法訪問了,那么我們?nèi)绾渭仍谧宇愔锌梢栽L問父類用private修飾的字段,又可以還不改變它封裝的本質(zhì)呢?這是就要用到protected關(guān)鍵字
package PACKAGE; class father{public int id=90;public String name;public int age;public father(String name,int age){this.name=name;this.age=age;}public void run(){System.out.println("我是父親的run方法");} } class child extends father{public child(String name,int age){super(name,age);super.run();System.out.println(super.id);} }public class Servlet {public static void main(String[] args) {child t1=new child("李佳偉",23);} } 打印結(jié)果: 1)我是父類的構(gòu)造方法 2)90this和super有什么區(qū)別?
相同點:都是我們Java中的關(guān)鍵字,都是只能在類的非靜態(tài)方法中使用,用來訪問非靜態(tài)成員方法和字段,在我們的構(gòu)造方法進(jìn)行調(diào)用的時候,我們必須是構(gòu)造方法中的第一條語句,并且不能同時存在
不同點:
1)指代對象不同:this是表示當(dāng)前對象的引用,當(dāng)前對象是指調(diào)用實例方法的對象,super相當(dāng)于是子類對象從父類中繼承下來的部分成員的引用(注意在這里面并不是父類的引用,子類繼承父類并沒有創(chuàng)建父類對象)
2)查找范圍不同:在非靜態(tài)成員方法中,this是用來訪問本類的方法和屬性,子類對象中如果沒有重名現(xiàn)象的發(fā)生,this也是可以訪問父類繼承下來的方法和屬性,重名的話優(yōu)先訪問子類屬性,子類沒有再去父類中尋找,但是super只能訪問父類繼承下來的方法和屬性,甚至this還可以訪問父類的方法,this會先從本類中進(jìn)行查找,查找不到再去訪問父類的方法
3)在我們的構(gòu)造方法中,this()用于調(diào)用本類構(gòu)造方法,super()用于調(diào)用父類構(gòu)造方法,兩者調(diào)用不能同時在構(gòu)造方法中出現(xiàn)
4)本類屬性賦值不同:this可以為本類的實例屬性賦值,那么super不能使用此功能
5)this可用于synchronized使用,表示給該對象加鎖
方法重寫的注意事項:
1)方法重寫是一種語言特性,他是多態(tài)的具體表現(xiàn),它允許子類重新定義父類中已有的方法,其子類中的方法名,參數(shù)類型和個數(shù),都必須和父類保持一致
2)子類權(quán)限控制符不能變小,public>protected>default>private,子類的訪問修飾限定符必須要大于等于父類
3)子類返回值類型只能變小,Number類是Long的父類,和父類的類型返回保持一致也是可以的,如果將子類的返回類型變大就會出現(xiàn)報錯了,比如說父類返回了Number類型,但是子類反回了Object類型
package Demo;class Father{public Number run(){System.out.println(1);return 8;} } class Child extends Father{public Integer run(){return 1;} }4)在方法名后面的拋出異常的類型只能變小,如果子類拋出的異常類型比父類大,那么程序會出現(xiàn)報錯,也就是說子類方法拋出的異常類型比父類方法拋出的異常類型大,那么程序就會出現(xiàn)報錯,所以說要保持父類和子類拋出的異常類型相同
package Demo;class Father{public Number run() throws NumberFormatException{System.out.println(1);return 8;} } class Child extends Father{public Integer run()throws Exception{return 1;}}5)方法名,參數(shù)類型和個數(shù)必須和父類方法保持一致
int 的默認(rèn)值是0
String的默認(rèn)值是空
char 類型的默認(rèn)值是?'/uoooo’
double和float的默認(rèn)值是0.0
boolean的默認(rèn)值是false?
方法重寫和方法重載有什么區(qū)別??
1)概念不同:
1.1)方法重寫是多態(tài)的具體表現(xiàn),是允許子類重新定義父類已有的方法,況且子類的方法名,參數(shù)類型和個數(shù)都要和父類保持一致,比較經(jīng)典的是Object類中的equals方法,需要重寫的方法,是不可以被final修飾的,被final修飾之后,他是密封方法,不可以進(jìn)行修改,非靜態(tài),非private,非final,非構(gòu)造方法,非static修飾的方法
1.2)方法重載指的是在同一個類中,定義了多個同名方法,但是同名方法的參數(shù)類型和參數(shù)個數(shù)不同就是方法重載,返回值不做要求,比較經(jīng)典的使用就是String中的ValueOf方法,里面參數(shù)可以是Object,boolean,一共九種,他可以將數(shù)組對象和基本數(shù)據(jù)類型轉(zhuǎn)化成字符串,沒有訪問權(quán)限的要求
多態(tài):通過一個引用,調(diào)用同一個方法展現(xiàn)出不同的形態(tài),因為這個引用引用不同的對象,所以說表現(xiàn)出哪一種行為,完全取決于這個引用引用那一個對象;
package Demo; class Teacher{public void run(){}; } class Teacher1 extends Teacher{public void run(){System.out.println("Teacher1在教數(shù)學(xué)");} } class Teacher2 extends Teacher{public void run(){System.out.println("Teacher2在教語文");} } public class DemoKail{public static void ShowRun(Teacher teacher){teacher.run();}public static void main(String[] args) {Teacher1 t1=new Teacher1();Teacher2 t2=new Teacher2();ShowRun(t1);ShowRun(t2);} }發(fā)生多態(tài)的條件
1)通過父類引用引用子類對象,必須在繼承體系下面
2)父類與子類有同名的覆蓋方法
3)通過父類引用調(diào)用重寫的重名方法之后
一:向上轉(zhuǎn)型:
通過父類引用來指定子類對象,進(jìn)行向上轉(zhuǎn)型之后,通過父類的引用,只能訪問父類自己的成員,方法和字段屬性,只能訪問自己特有的;不能訪問到子類特有的方法和屬性
時機(jī):
1)把子類對象給父類的引用
2)實參是子類引用,形參是父類引用:只關(guān)注父類的代碼,同時可以進(jìn)行兼容各種子類的一個情況
package Demo;class Father{public String name;public int age; } class Child extends Father{public String username;public String password; } public class TestDemo{public static void GetAll(Father father){}public static void main(String[] args) {Child child=new Child();GetAll(child);} }二:動態(tài)綁定:是多態(tài)的基礎(chǔ),JAVA中的多態(tài)包括運行時多態(tài)和編譯時期多態(tài)
發(fā)生條件:
1)父類引用引用子類的對象
2)通過這個父類引用地用用父類和子類同名的覆蓋方法,重寫(方法名稱相同,參數(shù)列表相同,參數(shù)個數(shù)相同,在父類和子類的基礎(chǔ)),在編譯的時候還不能確定我此時到底是調(diào)用父類的方法還是子類的方法,在運行的時候,我才知道了我要進(jìn)行調(diào)用誰的方法,這也叫做運行時綁定動態(tài)綁定,甚至就是說在父類的構(gòu)造方法里面,調(diào)用父類和子類的同名的覆蓋方法,也會發(fā)生運行時綁定
3)重寫方法訪問修是限定符不能是static,final,private
???????常見用法:1)使用java中的集合類,例如說List<String> list=new ArrayList(); 2)多線程情況下,繼承Thread,重寫runnable,都必須提供run方法,JVM內(nèi)部調(diào)用父類的run方法,從而執(zhí)行到用戶自己定義的run方法 3)DataSource dataSource=new mysqlDataSource(); 4)再嘗試進(jìn)行數(shù)據(jù)庫鏈接的時候,會用到向下轉(zhuǎn)型,MysqlDataSource是DataSource的子類 ((MysqlDataSource) datasource).setURL(url); ((MysqlDataSource) datasource).setUser(username); ((MysqlDataSource) datasource).setPassword(password);咱們此時在PowerShell窗口反編譯一下javap -c查看JAVA的反匯編代碼,看到生成的.class文件,此時看到的還是調(diào)用的是父類引用.eat()相當(dāng)于此時還是調(diào)用父類的eat,也就是說編譯的時候,我此時還不知道調(diào)用的是誰的方法,運行的時候,我才知道調(diào)用的是誰的方法,在運行的時候,發(fā)現(xiàn)重寫了,就調(diào)用子類的方法
靜態(tài)綁定:根據(jù)你給的參數(shù)類型和個數(shù)來進(jìn)行決定推導(dǎo)你調(diào)用哪一種重載的函數(shù)
4)編譯時綁定,編譯時多態(tài),我們利用重載來進(jìn)行實現(xiàn)多態(tài),即在一個類中定義多個同名的不同方法來實現(xiàn)多態(tài),會根據(jù)你給的參數(shù)的個數(shù)和類型,在編譯時期確定你要進(jìn)行調(diào)用的一個方法
通過父類引用只能訪問我們父類自己的成員,找到匯編,編譯的時候就知道調(diào)用哪一個具體的方法
三.向下轉(zhuǎn)型:子類引用引用父類對象
class Father{public String name;public int age; } class Child1 extends Father{public String username;public String password;public void run(){System.out.println("生命在于運動");} } class Child2 extends Father{public String name;public String word;public void start(){System.out.println("陽光");} } public class TestDemo{public static void main(String[] args) {Father father=new Child1();Child2 child2= (Child2) father;child2.start();} } //上面的程序會報錯,會出現(xiàn)類型轉(zhuǎn)換異常,應(yīng)該改成這樣 public static void main(String[] args) {Father father=new Child1();if(father instanceof Child2){Child2 child2= (Child2) father;child2.start();}else{Child1 child1=(Child1) father;child1.run();}}使用多態(tài)有什么好處呢?
一:類的調(diào)用者對類的使用成本進(jìn)一步降低
一:封裝是讓類的調(diào)用者不需要知道類的實現(xiàn)細(xì)節(jié)
二:多態(tài)可以讓類的調(diào)用者連這個類的類型是什么都不知道,只需要知道他所指向?qū)ο笥羞@個方法即可
三:所以說多態(tài)就是封裝的更進(jìn)一步,讓調(diào)用者對類的使用成本進(jìn)一步降低
二:擴(kuò)展能力很強(qiáng)
總結(jié):
封裝是將這個類的實現(xiàn)細(xì)節(jié)隱藏起來,通過一些公用方法來進(jìn)行暴露該對象的功能,對象的狀態(tài)信息都被隱藏在內(nèi)部,外界無法進(jìn)行操作和修改,不允許訪問?,將方法暴露出來,讓方法控制這些成員變量進(jìn)行安全的訪問和操作
總結(jié)
以上是生活随笔為你收集整理的JAVA面向对象编程(1)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python怎么撤销_关于Python:
- 下一篇: 国内人才《上海市居住证》申领表