小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Java 繼承詳解 – 碼農(nóng)網(wǎng)

 Larryljx 2015-09-03

什么是繼承?

多個類中存在相同屬性和行為時,將這些內(nèi)容抽取到單獨一個類中,那么多個類無需再定義這些屬性和行為,只要繼承那個類即可。

多個類可以稱為子類,單獨這個類稱為父類、超類或者基類。

子類可以直接訪問父類中的非私有的屬性和行為。

通過 extends 關鍵字讓類與類之間產(chǎn)生繼承關系。

class SubDemo extends Demo{}	//SubDemo是子類,Demo是父類

繼承有什么好處?

  • 提高代碼的復用性。
  • 讓類與類之間產(chǎn)生了關系,是多態(tài)的前提。

繼承的特點

1.Java只支持單繼承,不支持多繼承。

//一個類只能有一個父類,不可以有多個父類。
class SubDemo extends Demo{} //ok
class SubDemo extends Demo1,Demo2...//error

2.Java支持多層(重)繼承(繼承體系)。

class A{}
class B extends A{}
class C extends B{}

使用繼承時的注意事項

  • 如果類之間存在著:is a 的關系,就可以考慮使用繼承。
  • 不要為了繼承部分功能,而去使用繼承。

super和this有什么區(qū)別?

super是一個關鍵字,代表父類的存儲空間標識。(可以理解為父親的引用)

super和this的用法相似。

this代表對象的引用(誰調(diào)用就代表誰);
super代表當前子類父類的引用。

使用場景

  • 當子父類出現(xiàn)同名成員時,可以用super進行區(qū)分;
  • 子類要調(diào)用父類構造函數(shù)時,可以使用super語句。

區(qū)別

1.成員變量

this.變量    --    本類的
super.變量    --    父類的

2.構造方法

this(...)    --    本類的
super(...)    --    父類的

3.成員方法

this.方法名()    --    本類的    
super.方法名()    --    父類的

super();和this();都是在構造函數(shù)的第一行,不能同時出現(xiàn)。

方法的重寫(覆蓋)

子類中出現(xiàn)與父類一模一樣的方法時(除了權限修飾符,權限修飾符大于等于不包括private,返回值類型,方法名和參數(shù)列表相同),會出現(xiàn)覆蓋操作,也稱為重寫或者復寫。

父類私有方法,子類看不到,因此父類私有方法的重寫也就無從談起。

覆蓋注意事項

  • 覆蓋時,子類方法權限一定要大于等于父類方法權限;
  • 靜態(tài)只能覆蓋靜態(tài)。

覆蓋的使用場景

當子類需要父類的功能,而功能主體子類有自己特有內(nèi)容時,可以復寫父類中的方法,這樣,既沿襲了父類的功能,又定義了子類特有的內(nèi)容。

方法重寫和重載有什么區(qū)別?

方法的重寫用在子類方法與父類方法一模一樣時,除權限修飾符,返回值類型,方法名和參數(shù)列表都是相同的。
重載用在同一個類中各方法方法名相同,參數(shù)列表不同(與返回值類型沒有關系)的情況。

子父類中構造方法的用法

  1. 子類的初始化過程中,首先回去執(zhí)行父類的初始化動作。因為子類的構造方法中默認有一個super()。子類要使用父類的成員變量,這個初始化,必須在子類初始化之前完成。所以,子類的初始化過程中,會先執(zhí)行父類的初始化。
  2. 如果父類沒有無參構造方法
  • 使用super調(diào)用父類的帶參構造。推薦方式。
  • 使用this調(diào)用本身的其他構造。

靜態(tài)代碼塊、構造代碼塊,構造方法的執(zhí)行順序

父類靜態(tài)代碼塊→子類靜態(tài)代碼塊→父類構造代碼塊→父類構造方法→子類構造代碼塊→子類構造方法

final關鍵字

final是一個關鍵字,可以用于修飾類,成員變量,成員方法。

特點

  1. 它修飾的類不能被繼承。
  2. 它修飾的成員變量是一個常量。
  3. 它修飾的成員方法是不能被子類重寫的。

final修飾的常量定義一般都有書寫規(guī)范,被final修飾的常量名稱,所有字母都大寫。

final修飾成員變量,必須初始化,初始化有兩種

  • 顯示初始化;
  • 構造方法初始化。
    但是不能兩個一起初始化

final和private的區(qū)別

  1. final修飾的類可以訪問;
    private不可以修飾外部類,但可以修飾內(nèi)部類(其實把外部類私有化是沒有意義的)。
  2. final修飾的方法不可以被子類重寫;
    private修飾的方法表面上看是可以被子類重寫的,其實不可以,子類是看不到父類的私有方法的。
  3. final修飾的變量只能在顯示初始化或者構造函數(shù)初始化的時候賦值一次,以后不允許更改;
    private修飾的變量,也不允許直接被子類或一個包中的其它類訪問或修改,但是他可以通過set和get方法對其改值和取值。

多態(tài)

概念

對象在不同時刻表現(xiàn)出來的不同狀態(tài)。

多態(tài)的前提

  • 要有繼承或者實現(xiàn)關系。
  • 要有方法的重寫。
  • 要有父類引用指向子類對象。

程序中的體現(xiàn)
父類或者接口的引用指向或者接收自己的子類對象。

好處和作用
多態(tài)的存在提高了程序的擴展性和后期可維護性

弊端:
父類調(diào)用的時候只能調(diào)用父類里的方法,不能調(diào)用子類的特有方法,因為你并不清楚將來會有什么樣的子類繼承你。

多態(tài)的成員特點

  • 成員變量:編譯時期:看引用型變量所屬的類中是否有所調(diào)用的變量;
    運行時期:也是看引用型變量所屬的類是否有調(diào)用的變量。
    成員變量無論編譯還是運行都看引用型變量所屬的類,簡單記成員變量,編譯和運行都看等號左邊。
  • 成員方法:編譯時期:要查看引用變量所屬的類中是否有所調(diào)用的成員;
    運行時期:要查看對象所屬的類中是否有所調(diào)用的成員。如果父子出現(xiàn)同名的方法,會運行子類中的方法,因為方法有覆蓋的特性。
    編譯看左邊運行看右邊。
  • 靜態(tài)方法:編譯時期:看的引用型變量所屬的類中是否有所調(diào)用的變量;
    運行時期:也是看引用型變量所屬的類是否有調(diào)用的變量。
    編譯和運行都看等號左邊

一定不能夠?qū)⒏割惖膶ο筠D換成子類類型!

父類的引用指向子類對象,該引用可以被提升,也可以被強制轉換。

多態(tài)自始至終都是子類對象在變化!

//多態(tài)向下轉型和向上轉型的例子,多態(tài)轉型解決了多態(tài)中父類引用不能使用子類特有成員的弊端。
class PolymorphicTest2 {
    public static void main(String[] args) {
        Phone p1 = new Nokia();        //向上轉型,類型提升
        Nokia no = (Nokia)p1;          //向下轉型,強制將父類的引用轉換成子類類型,不能將Nokia類型轉成Moto或Nexus類型
        no.print();                      //輸出結果為Phone---null---0,因為繼承了父類的方法

        Phone p2 = new Moto();
        Moto m = (Moto)p2;
        m.print();                    //輸出結果為Moto---yellow---1599,方法重寫,子類方法覆蓋父類方法

        Phone p3 = new Nexus();
        Nexus ne = (Nexus)p3;
        ne.print();
    }
}

class Phone{    
    String color;
    int price;

    public void print(){
        System.out.println("Phone---" + color + "---" + price );
    }    
}

class Nokia extends Phone{
    String color = "red";
    int price = 1009;

    //public void print(){
    //    System.out.println("Nokia---" + color + "---" + price);
    //}
}

class Moto extends Phone{
    String color = "yellow";
    int price = 1599;

    public void print(){
        System.out.println("Moto---" + color + "---" + price);
    }
}

class Nexus extends Phone{
    String color = "black";
    int price = 1999;

    public void print(){
        System.out.println("Nexus---" + color + "---" + price);
    }
}
}

抽象(abstract)

抽象就是從多個事物中將共性的,本質(zhì)的內(nèi)容抽象出來。

抽象類

Java中可以定義沒有方法體的方法,該方法的具體實現(xiàn)由子類完成,該方法稱為抽象方法,包含抽象方法的類就是抽象類。

由來

多個對象都具備相同的功能,但是功能具體內(nèi)容有所不同,那么在抽取過程中,只抽取了功能定義,并未抽取功能主體,那么只有功能聲明,沒有功能主體的方法稱為抽象方法。

抽象類特點

  1. 抽象方法一定在抽象類中;
  2. 抽象方法和抽象類都必須被abstract關鍵字修飾;
  3. 抽象類不可以用new創(chuàng)建對象,因為調(diào)用抽象方法沒意義;
  4. 抽象類中的抽象方法要被使用,必須由子類復寫其所有的抽象方法后,建立子類對象調(diào)用; 如果子類只覆蓋了部分的抽象方法,那么該子類還是一個抽象類;
  5. 抽象類中可以有抽象方法,也可以有非抽象方法,抽象方法用于子類實例化;
  6. 如果一個類是抽象類,那么,繼承它的子類,要么是抽象類,要么重寫所有抽象方法。
    特殊:抽象類中可以不定義抽象方法,這樣做僅僅是不讓該類建立對象。

抽象類的成員特點

  • 成員變量:可以是變量,也可以是常量;
  • 構造方法:有構造方法;
  • 成員方法:可以是抽象方法,也可以是非抽象方法。
abstract class 葵花寶典 {
    public abstract void 自宮();
}

class 岳不群 extends 葵花寶典 {
    public void 自宮(){
        System.out.println("剪刀");
    }
}

class 林平之 extends 葵花寶典{
    public void 自宮(){
        System.out.println("指甲刀");
    }
}
class AbstractTest  {
    public static void main(String[] args) {
        岳不群 岳 = new 岳不群();
        岳.自宮();

        林平之 林 = new 林平之();
        林.自宮();
    }
}

抽象類注意事項

抽象類不能被實例化,為什么還有構造函數(shù)?

只要是class定義的類里面就肯定有構造函數(shù)。抽象類中的函數(shù)是給子類實例化的。

一個類沒有抽象方法,為什么定義為抽象類?

不想被繼承,還不想被實例化。

抽象關鍵字abstract不可以和哪些關鍵字共存

  • final:如果方法被抽象,就需要被覆蓋,而final是不可以被覆蓋,所以沖突。
  • private:如果函數(shù)被私有了,子類無法直接訪問,怎么覆蓋呢?
  • static:不需要對象,類名就可以調(diào)用抽象方法。而調(diào)用抽象方法沒有意義。

接口(interface)

接口抽象方法常量值的集合。從本質(zhì)上講,接口是一種特殊的抽象類,這種抽象類只包含常量和方法的定義,而沒有變量和方法的實現(xiàn)。

格式:interface 接口名{}

接口的出現(xiàn)將”多繼承“通過另一種形式體現(xiàn)出來,即”多實現(xiàn)“。

實現(xiàn)(implements)

格式:class 類名 implements 接口名 {}

特點

  • 接口不能被實例化。
  • 一個類如果實現(xiàn)了接口,要么是抽象類,要么實現(xiàn)接口中的所有方法。

接口的成員特點

接口中的成員修飾符是固定的!

  • 成員常量:public static final,接口里定義的變量是全局常量,而且修飾符只能是這三個關鍵字,都可以省略,常量名要大寫。
  • 成員方法:public abstract,接口里定義的方法都是抽象的,兩個修飾符關鍵字可省略。
  • 推薦:永遠手動給出修飾符。

繼承與實現(xiàn)的區(qū)別

  • 類與類之間稱為繼承關系:因為該類無論是抽象的還是非抽象的,它的內(nèi)部都可以定義非抽象方法,這個方法可以直接被子類使用,子類繼承即可。只能單繼承,可以多層繼承。((class)
  • 類與接口之間是實現(xiàn)關系:因為接口中的方法都是抽象的,必須由子類實現(xiàn)才可以實例化??梢詥螌崿F(xiàn),也可以多實現(xiàn);還可以在繼承一個類的同時實現(xiàn)多個接口。((class) extends (class) implements (interface1,interface2…)
  • 接口與接口之間是繼承關系:一個接口可以繼承另一個接口,并添加新的屬性和抽象方法,并且接口可以多繼承。((interface) extends (interface1,interface2…)

抽象類和接口的區(qū)別

成員變量

  • 抽象類能有變量也可以有常量
  • 接口只能有常量

成員方法

  • 抽象類可以有非抽象的方法,也可以有抽象的方法
  • 接口只能有抽象的方法

構造方法

-抽象類有構造方法
-接口沒有構造方法

類與抽象類和接口的關系

  • 類與抽象類的關系是繼承 extends
  • 類與接口的關系是實現(xiàn) implements

接口的思想特點

  1. 接口是對外暴露的規(guī)則;
  2. 接口是程序的功能擴展;
  3. 接口的出現(xiàn)降低耦合性;(實現(xiàn)了模塊化開發(fā),定義好規(guī)則,每個人實現(xiàn)自己的模塊,大大提高了開發(fā)效率)
  4. 接口可以用來多實現(xiàn);
  5. 多個無關的類可以實現(xiàn)同一個接口;
  6. 一個類可以實現(xiàn)多個相互直接沒有關系的接口;
  7. 與繼承關系類似,接口與實現(xiàn)類之間存在多態(tài)性
//運動員和教練的案例(下圖是思路分析)

/*
    籃球運動員和教練
    乒乓球運動員和教練
    現(xiàn)在籃球運動員和教練要出國訪問,需要學習英語
    請根據(jù)你所學的知識,分析出來哪些是類,哪些是抽象類,哪些是接口
*/
interface SpeakEnglish {
    public abstract void speak();
}

interface GoAboard{
    public abstract void aboard();
}

abstract class Person {
    private String name;
    private int age;

    public Person(){}

    public Person(String name,int age){
        this.name = name;
        this.age = age;
    }

    public void setName(String name){
        this.name = name;
    }
    public String getName(){
        return name;
    }

    public void setAge(int age){
        this.age = age;
    }
    public int getAge(){
        return age;
    }

    //吃飯
    public abstract void eat();
    //睡覺
    public void sleep(){
        System.out.println("Zzz...");
    }
}
//運動員
abstract class Player extends Person {
    public abstract void study();
}
//教練
abstract class Coach extends Person {
    public abstract void teach();
}

//籃球運動員
class BasketballPlayer extends Player implements SpeakEnglish,GoAboard{
    public void eat(){
        System.out.println(getAge() + "歲的" + getName() + "吃雞腿");
    }

    public void study(){
        System.out.println(getAge() + "歲的" + getName() + "學扣籃");
    }

    public void speak(){
        System.out.println(getAge() + "歲的" + getName() + " Say Hello World");
    }

    public void aboard(){
        System.out.println(getAge() + "歲的" + getName() + " Go Aboard");
    }
}
//乒乓運動員
class PingPangPlayer extends Player{
    public void eat(){
        System.out.println(getAge() + "歲的" + getName() + "吃雞蛋");
    }

    public void study(){
        System.out.println(getAge() + "歲的" + getName() + "學扣球");
    }
}
//籃球教練
class BasketballCoach extends Coach implements SpeakEnglish {
    public void eat(){
        System.out.println(getAge() + "歲的" + getName() + "啃雞爪");
    }

    public void teach(){
        System.out.println(getAge() + "歲的" + getName() + "教扣籃");
    }

    public void speak(){
        System.out.println(getAge() + "歲的" + getName() + " Say Hello Java");
    }

    public void aboard(){
        System.out.println(getAge() + "歲的" + getName() + " Go Aboard");
    }
}
//乒乓球教練
class PingPangCoach extends Coach{
    public void eat(){
        System.out.println(getAge() + "歲的" + getName() + "吃雞蛋皮");
    }

    public void teach(){
        System.out.println(getAge() + "歲的" + getName() + "教扣球");
    }
}
class PlayerAndCoach {
    public static void main(String[] args) {
        //籃球運動員
        BasketballPlayer bp = new BasketballPlayer();
        bp.setName("郭艾倫");
        bp.setAge(33);
        bp.eat();
        bp.sleep();
        bp.study();
        bp.speak();
        bp.aboard();
        System.out.println("***********************");
        //籃球教練
        BasketballCoach bc = new BasketballCoach();
        bc.setName("波波維奇");
        bc.setAge(65);
        bc.eat();
        bc.sleep();
        bc.teach();
        bc.speak();
        bc.aboard();
        System.out.println("***********************");
        //多態(tài)
        Person p = new BasketballPlayer();
        p.setName("Kobe Bryant");
        p.setAge(33);
        p.eat();
        p.sleep();
        //p.study();
        //p.speak();

        BasketballPlayer bp2 = (BasketballPlayer)p;
        bp2.study();
        bp2.speak();
        bp2.aboard();
        System.out.println("***********************");
    }
}

內(nèi)部類

將一個類定義在另一個類里面,里面的那個類就稱為內(nèi)部類。內(nèi)部類的出現(xiàn),再次打破了Java單繼承的局限性。

訪問特點

  • 內(nèi)部類可以直接訪問外部類的成員,包括私有成員。
  • 外部類要訪問內(nèi)部類的成員,必須要建立內(nèi)部類的對象。
    內(nèi)部類分類及共性

共性

  • 內(nèi)部類仍然是一個獨立的類,在編譯之后會內(nèi)部類會被編譯成獨立的.class文件,但是前面冠以外部類的類名和$符號。
  • 內(nèi)部類不能用普通的方式訪問。內(nèi)部類是外部類的一個成員,因此內(nèi)部類可以自由地訪問外部類的成員變量,無論是否是private的。

成員內(nèi)部類

在外部類中有成員變量和成員方法,成員內(nèi)部類就是把整個一個類作為了外部類的成員;
成員內(nèi)部類是定義在類中方法外的類;
創(chuàng)建對象的格式為:外部類名.內(nèi)部類名 對象名 = 外部類對象.內(nèi)部類對象;
成員內(nèi)部類之所以可以直接訪問外部類的成員,那是因為內(nèi)部類中都持有一個外部類對象的引用:外部類名.this;
成員內(nèi)部類可以用的修飾符有final,abstract,public,private,protected,static.

靜態(tài)內(nèi)部類

靜態(tài)內(nèi)部類就是成員內(nèi)部類加上靜態(tài)修飾符static,定義在類中方法外。

在外部類中訪問靜態(tài)內(nèi)部類有兩種場景:

  • 在外部類中訪問靜態(tài)內(nèi)部類中非靜態(tài)成員:*外部類名.內(nèi)部類名 對象名 = 外部類名.內(nèi)部對象*,需要通過創(chuàng)建對象訪問;
  • 在外部類中訪問靜態(tài)內(nèi)部類中的靜態(tài)成員:同樣可以使用上面的格式進行訪問,也可以直接使用外部類名.內(nèi)部類名.成員。

局部內(nèi)部類

局部內(nèi)部類是定義在方法中的類。

  • 方法內(nèi)部類只能在定義該內(nèi)部類的方法內(nèi)實例化,不可以在此方法外對其實例化。
  • 方法內(nèi)部類對象不能使用該內(nèi)部類所在方法的非final局部變量。

可以用于方法內(nèi)部類的修飾符有final,abstract;

靜態(tài)方法中的方法內(nèi)部類只能訪問外部的靜態(tài)成員。

匿名內(nèi)部類

匿名內(nèi)部類是內(nèi)部類的簡化寫法,是建立一個帶內(nèi)容的外部類或者接口的子類匿名對象。
前提:
內(nèi)部類可以繼承或?qū)崿F(xiàn)一個外部類或者接口。
格式:
new 外部類名或者接口名(){重寫方法};
通常在方法的形式參數(shù)是接口或者抽象類,并且該接口中的方法不超過三個時,可以將匿名內(nèi)部類作為參數(shù)傳遞。

不同修飾符修飾的內(nèi)容(和內(nèi)部類無關)

成員變量 成員方法 構造方法
private Y Y Y
默認 Y Y Y Y
protected Y Y Y
public Y Y Y Y
abstract Y Y
static Y Y Y
final Y Y Y

注意,常見規(guī)則如下:

  • 以后,所有的類都用public修飾。并且,在一個java文件中,只寫一個類。
  • 以后,所有的成員變量用private修飾。
  • 以后,所有的成員方法用public修飾。
    如果是抽象類或者接口:public abstract + …
  • 以后,所有的構造方法用public修飾。
    如果類是工具類或者單例類:構造用private修飾

四種權限修飾符

本類 同包(無關類或子類) 不同包(子類) 不同包(無關類)
private Y
默認 Y Y
protected Y Y Y
public Y Y Y Y

推薦:

  • 成員變量 private
  • 構造方法 public
  • 成員方法 public

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多