欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

新手初學(xué)Java繼承、封裝與多態(tài)

 更新時(shí)間:2021年07月07日 10:23:31   作者:有一個(gè)大佬夢(mèng)  
封裝、繼承、多態(tài)三大特征是java中比較常用的,務(wù)必要掌握,下面給大家介紹Java封裝、繼承、多態(tài)三大特征的理解,有不清楚的朋友可以一起學(xué)習(xí)下

面向?qū)ο蟮娜蠛诵奶匦?/h2>

面向?qū)ο箝_(kāi)發(fā)模式更有利于人們開(kāi)拓思維,在具體的開(kāi)發(fā)過(guò)程中便于程序的劃分,方便程序員分工合作,提高開(kāi)發(fā)效率。面向?qū)ο蟪绦蛟O(shè)計(jì)有以下優(yōu)點(diǎn)。

  • 可重用性:代碼重復(fù)使用,減少代碼量,提高開(kāi)發(fā)效率。下面介紹的面向?qū)ο蟮娜蠛诵奶匦裕ɡ^承、封裝和多態(tài))都圍繞這個(gè)核心。
  • 可擴(kuò)展性:指新的功能可以很容易地加入到系統(tǒng)中來(lái),便于軟件的修改。
  • 可管理性:能夠?qū)⒐δ芘c數(shù)據(jù)結(jié)合,方便管理。

該開(kāi)發(fā)模式之所以使程序設(shè)計(jì)更加完善和強(qiáng)大,主要是因?yàn)槊嫦驅(qū)ο缶哂欣^承、封裝和多態(tài) 3 個(gè)核心特性。

封裝

封裝將類的某些信息隱藏在類內(nèi)部,不允許外部程序直接訪問(wèn),只能通過(guò)該類提供的方法來(lái)實(shí)現(xiàn)對(duì)隱藏信息的操作和訪問(wèn)。例如:一臺(tái)計(jì)算機(jī)內(nèi)部極其復(fù)雜,有主板、CPU、硬盤和內(nèi)存, 而一般用戶不需要了解它的內(nèi)部細(xì)節(jié),不需要知道主板的型號(hào)、CPU 主頻、硬盤和內(nèi)存的大小,于是計(jì)算機(jī)制造商將用機(jī)箱把計(jì)算機(jī)封裝起來(lái),對(duì)外提供了一些接口,如鼠標(biāo)、鍵盤和顯示器等,這樣當(dāng)用戶使用計(jì)算機(jī)就非常方便。

封裝的特點(diǎn):

  • 只能通過(guò)規(guī)定的方法訪問(wèn)數(shù)據(jù)。
  • 隱藏類的實(shí)例細(xì)節(jié),方便修改和實(shí)現(xiàn)。

實(shí)現(xiàn)封裝的具體步驟如下:

  • 修改屬性的可見(jiàn)性來(lái)限制對(duì)屬性的訪問(wèn),一般設(shè)為 private
  • 為每個(gè)屬性創(chuàng)建一對(duì)賦值(setter)方法和取值(getter)方法,一般設(shè)為 public,用于屬性的讀寫。
  • 在賦值和取值方法中,加入屬性控制語(yǔ)句(對(duì)屬性值的合法性進(jìn)行判斷)。

下面以一個(gè)員工類的封裝為例介紹封裝過(guò)程。一個(gè)員工的主要屬性有姓名、年齡、聯(lián)系電話和家庭住址。假設(shè)員工類為 Employee,示例如下:

public class Employee {
    private String name; // 姓名
    private int age; // 年齡
    private String phone; // 聯(lián)系電話
    private String address; // 家庭住址
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        // 對(duì)年齡進(jìn)行限制
        if (age < 18 || age > 40) {
            System.out.println("年齡必須在18到40之間!");
            this.age = 20; // 默認(rèn)年齡
        } else {
            this.age = age;
        }
    }
    public String getPhone() {
        return phone;
    }
    public void setPhone(String phone) {
        this.phone = phone;
    }
    public String getAddress() {
        return address;
    }
    public void setAddress(String address) {
        this.address = address;
    }
}

繼承

繼承是面向?qū)ο蟮娜筇卣髦?。繼承和現(xiàn)實(shí)生活中的“繼承”的相似之處是保留一些父輩的特性,從而減少代碼冗余,提高程序運(yùn)行效率。

Java 中的繼承就是在已經(jīng)存在類的基礎(chǔ)上進(jìn)行擴(kuò)展,從而產(chǎn)生新的類。已經(jīng)存在的類稱為父類、基類或超類,而新產(chǎn)生的類稱為子類或派生類。在子類中,不僅包含父類的屬性和方法,還可以增加新的屬性和方法。

創(chuàng)建人類 People,并定義 name、age、sex、sn 屬性,代碼如下:

public class People {
    public String name; // 姓名
    public int age; // 年齡
    public String sex; // 性別
    public String sn; // 身份證號(hào)
    public People(String name, int age, String sex, String sn) {
        this.name = name;
        this.age = age;
        this.sex = sex;
        this.sn = sn;
    }
    public String toString() {
        return "姓名:" + name + "\n年齡:" + age + "\n性別:" + sex + "\n身份證號(hào):" + sn;
    }
}

創(chuàng)建 People 類的子類 Student 類,并定義 stuNo 和 department 屬性,代碼如下:

public class Student extends People {
    private String stuNo; // 學(xué)號(hào)
    private String department; // 所學(xué)專業(yè)
    public Student(String name, int age, String sex, String sn, String stuno, String department) {
        super(name, age, sex, sn); // 調(diào)用父類中的構(gòu)造方法
        this.stuNo = stuno;
        this.department = department;
    }
    public String toString() {
        return "姓名:" + name + "\n年齡:" + age + "\n性別:" + sex + "\n身份證號(hào):" + sn + "\n學(xué)號(hào):" + stuNo + "\n所學(xué)專業(yè):" + department;
    }
}

由于 Student 類繼承自 People 類,因此,在 Student 類中同樣具有 People 類的屬性和方法,這里重寫了父類中的 toString() 方法。

注意:如果在父類中存在有參的構(gòu)造方法而并沒(méi)有重載無(wú)參的構(gòu)造方法,那么在子類中必須含有有參的構(gòu)造方法,因?yàn)槿绻谧宇愔胁缓袠?gòu)造方法,默認(rèn)會(huì)調(diào)用父類中無(wú)參的構(gòu)造方法,而在父類中并沒(méi)有無(wú)參的構(gòu)造方法,因此會(huì)出錯(cuò)。

單繼承

Java 語(yǔ)言摒棄了 C++ 中難以理解的多繼承特征,即 Java 不支持多繼承,只允許一個(gè)類直接繼承另一個(gè)類,即子類只能有一個(gè)直接父類,extends 關(guān)鍵字后面只能有一個(gè)類名。

很多地方在介紹 Java 的單繼承時(shí),可能會(huì)說(shuō) Java 類只能有一個(gè)父類,嚴(yán)格來(lái)講,這種說(shuō)法是錯(cuò)誤的,應(yīng)該是一個(gè)類只能有一個(gè)直接父類,但是它可以有多個(gè)間接的父類。

繼承的優(yōu)缺點(diǎn)

在面向?qū)ο笳Z(yǔ)言中,繼承是必不可少的、非常優(yōu)秀的語(yǔ)言機(jī)制,它有如下優(yōu)點(diǎn):

  • 實(shí)現(xiàn)代碼共享,減少創(chuàng)建類的工作量,使子類可以擁有父類的方法和屬性。
  • 提高代碼維護(hù)性和可重用性。
  • 提高代碼的可擴(kuò)展性,更好的實(shí)現(xiàn)父類的方法。

自然界的所有事物都是優(yōu)點(diǎn)和缺點(diǎn)并存的,繼承的缺點(diǎn)如下:

  • 繼承是侵入性的。只要繼承,就必須擁有父類的屬性和方法。
  • 降低代碼靈活性。子類擁有父類的屬性和方法后多了些約束。
  • 增強(qiáng)代碼耦合性(開(kāi)發(fā)項(xiàng)目的原則為高內(nèi)聚低耦合)。當(dāng)父類的常量、變量和方法被修改時(shí),需要考慮子類的修改,有可能會(huì)導(dǎo)致大段的代碼需要重構(gòu)。

super關(guān)鍵字

由于子類不能繼承父類的構(gòu)造方法,因此,如果要調(diào)用父類的構(gòu)造方法,可以使用 super 關(guān)鍵字。super 可以用來(lái)訪問(wèn)父類的構(gòu)造方法、普通方法和屬性。

super 關(guān)鍵字的功能:

  • 在子類的構(gòu)造方法中顯式的調(diào)用父類構(gòu)造方法
  • 訪問(wèn)父類的成員方法和變量。

super調(diào)用父類構(gòu)造方法

super 關(guān)鍵字可以在子類的構(gòu)造方法中顯式地調(diào)用父類的構(gòu)造方法,基本格式如下:

super(parameter-list);

其中,parameter-list 指定了父類構(gòu)造方法中的所有參數(shù)。super( ) 必須是在子類構(gòu)造方法的方法體的第一行。

聲明父類 Person,類中定義兩個(gè)構(gòu)造方法。示例代碼如下:

public class Person {
    public Person(String name, int age) {
    }
    public Person(String name, int age, String sex) {
    }
}

子類 Student 繼承了 Person 類,使用 super 語(yǔ)句來(lái)定義 Student 類的構(gòu)造方法。示例代碼如下:

public class Student extends Person {
    public Student(String name, int age, String birth) {
        super(name, age); // 調(diào)用父類中含有2個(gè)參數(shù)的構(gòu)造方法
    }
    public Student(String name, int age, String sex, String birth) {
        super(name, age, sex); // 調(diào)用父類中含有3個(gè)參數(shù)的構(gòu)造方法
    }
}

從上述 Student 類構(gòu)造方法代碼可以看出,super 可以用來(lái)直接調(diào)用父類中的構(gòu)造方法,使編寫代碼也更加簡(jiǎn)潔方便。

編譯器會(huì)自動(dòng)在子類構(gòu)造方法的第一句加上super();來(lái)調(diào)用父類的無(wú)參構(gòu)造方法,必須寫在子類構(gòu)造方法的第一句,也可以省略不寫。通過(guò) super 來(lái)調(diào)用父類其它構(gòu)造方法時(shí),只需要把相應(yīng)的參數(shù)傳過(guò)去。

super訪問(wèn)父類成員

當(dāng)子類的成員變量或方法與父類同名時(shí),可以使用 super 關(guān)鍵字來(lái)訪問(wèn)。如果子類重寫了父類的某一個(gè)方法,即子類和父類有相同的方法定義,但是有不同的方法體,此時(shí),我們可以通過(guò) super 來(lái)調(diào)用父類里面的這個(gè)方法。

使用 super 訪問(wèn)父類中的成員與 this 關(guān)鍵字的使用相似,只不過(guò)它引用的是子類的父類,語(yǔ)法格式如下:

super.member

其中,member 是父類中的屬性或方法。使用 super 訪問(wèn)父類的屬性和方法時(shí)不用位于第一行。

  • super調(diào)用成員屬性

當(dāng)父類和子類具有相同的數(shù)據(jù)成員時(shí),JVM 可能會(huì)模糊不清。我們可以使用以下代碼片段更清楚地理解它。

class Person {
    int age = 12;
}
class Student extends Person {
    int age = 18;
    void display() {
        System.out.println("學(xué)生年齡:" + super.age);
    }
}
class Test {
    public static void main(String[] args) {
        Student stu = new Student();
        stu.display();
    }
}

輸出結(jié)果為:

學(xué)生年齡:12

在上面的例子中,父類和子類都有一個(gè)成員變量 age。我們可以使用 super 關(guān)鍵字訪問(wèn) Person 類中的 age 變量。

  • super調(diào)用成員方法

當(dāng)父類和子類都具有相同的方法名時(shí),可以使用 super 關(guān)鍵字訪問(wèn)父類的方法。具體如下代碼所示。

class Person {
    void message() {
        System.out.println("This is person class");
    }
}
class Student extends Person {
    void message() {
        System.out.println("This is student class");
    }
    void display() {
        message();
        super.message();
    }
}
class Test {
    public static void main(String args[]) {
        Student s = new Student();
        s.display();
    }
}

輸出結(jié)果為:

This is student class

This is person class

在上面的例子中,可以看到如果只調(diào)用方法 message( ),是當(dāng)前的類 message( ) 被調(diào)用,使用 super 關(guān)鍵字時(shí),是父類的 message( ) 被調(diào)用

super和this的區(qū)別

this 指的是當(dāng)前對(duì)象的引用,super 是當(dāng)前對(duì)象的父對(duì)象的引用。下面先簡(jiǎn)單介紹一下 super 和 this 關(guān)鍵字的用法。

super 關(guān)鍵字的用法:

  • super.父類屬性名:調(diào)用父類中的屬性
  • super.父類方法名:調(diào)用父類中的方法
  • super():調(diào)用父類的無(wú)參構(gòu)造方法
  • super(參數(shù)):調(diào)用父類的有參構(gòu)造方法

如果構(gòu)造方法的第一行代碼不是 this() 和 super(),則系統(tǒng)會(huì)默認(rèn)添加 super()。

this 關(guān)鍵字的用法:

  • this.屬性名:表示當(dāng)前對(duì)象的屬性
  • this.方法名(參數(shù)):表示調(diào)用當(dāng)前對(duì)象的方法

當(dāng)局部變量和成員變量發(fā)生沖突時(shí),使用this.進(jìn)行區(qū)分。

關(guān)于 Java super 和 this 關(guān)鍵字的異同,可簡(jiǎn)單總結(jié)為以下幾條。

  • 子類和父類中變量或方法名稱相同時(shí),用 super 關(guān)鍵字來(lái)訪問(wèn)??梢岳斫鉃?super 是指向自己父類對(duì)象的一個(gè)指針。在子類中調(diào)用父類的構(gòu)造方法。
  • this 是自身的一個(gè)對(duì)象,代表對(duì)象本身,可以理解為 this 是指向?qū)ο蟊旧淼囊粋€(gè)指針。在同一個(gè)類中調(diào)用其它方法。
  • this 和 super 不能同時(shí)出現(xiàn)在一個(gè)構(gòu)造方法里面,因?yàn)?this 必然會(huì)調(diào)用其它的構(gòu)造方法,其它的構(gòu)造方法中肯定會(huì)有 super 語(yǔ)句的存在,所以在同一個(gè)構(gòu)造方法里面有相同的語(yǔ)句,就失去了語(yǔ)句的意義,編譯器也不會(huì)通過(guò)。
  • this( ) 和 super( ) 都指的是對(duì)象,所以,均不可以在 static 環(huán)境中使用,包括 static 變量、static 方法和 static 語(yǔ)句塊。
  • 從本質(zhì)上講,this 是一個(gè)指向?qū)ο蟊旧淼闹羔? 然而 super 是一個(gè) Java 關(guān)鍵字。

多態(tài)

多態(tài)性是面向?qū)ο缶幊痰挠忠粋€(gè)重要特征,它是指在父類中定義的屬性和方法被子類繼承之后,可以具有不同的數(shù)據(jù)類型或表現(xiàn)出不同的行為,這使得同一個(gè)屬性或方法在父類及其各個(gè)子類中具有不同的含義。

對(duì)面向?qū)ο髞?lái)說(shuō),多態(tài)分為編譯時(shí)多態(tài)和運(yùn)行時(shí)多態(tài)。其中編譯時(shí)多態(tài)是靜態(tài)的,主要是指方法的重載,它是根據(jù)參數(shù)列表的不同來(lái)區(qū)分不同的方法。通過(guò)編譯之后會(huì)變成兩個(gè)不同的方法,在運(yùn)行時(shí)談不上多態(tài)。而運(yùn)行時(shí)多態(tài)是動(dòng)態(tài)的,它是通過(guò)動(dòng)態(tài)綁定來(lái)實(shí)現(xiàn)的,也就是大家通常所說(shuō)的多態(tài)性。

Java 實(shí)現(xiàn)多態(tài)有 3 個(gè)必要條件:繼承、重寫和向上轉(zhuǎn)型。只有滿足這 3 個(gè)條件,開(kāi)發(fā)人員才能夠在同一個(gè)繼承結(jié)構(gòu)中使用統(tǒng)一的邏輯實(shí)現(xiàn)代碼處理不同的對(duì)象,從而執(zhí)行不同的行為。

  • 繼承:在多態(tài)中必須存在有繼承關(guān)系的子類和父類。
  • 重寫:子類對(duì)父類中某些方法進(jìn)行重新定義,在調(diào)用這些方法時(shí)就會(huì)調(diào)用子類的方法。
  • 向上轉(zhuǎn)型:在多態(tài)中需要將子類的引用賦給父類對(duì)象,只有這樣該引用才既能可以調(diào)用父類的方法,又能調(diào)用子類的方法。

創(chuàng)建 Figure 類,在該類中首先定義存儲(chǔ)二維對(duì)象的尺寸,然后定義有兩個(gè)參數(shù)的構(gòu)造方法,最后添加 area() 方法,該方法計(jì)算對(duì)象的面積。代碼如下:

public class Figure {
    double dim1;
    double dim2;
    Figure(double d1, double d2) {
        // 有參的構(gòu)造方法
        this.dim1 = d1;
        this.dim2 = d2;
    }
    double area() {
        // 用于計(jì)算對(duì)象的面積
        System.out.println("父類中計(jì)算對(duì)象面積的方法,沒(méi)有實(shí)際意義,需要在子類中重寫。");
        return 0;
    }
}

創(chuàng)建繼承自 Figure 類的 Rectangle 子類,該類調(diào)用父類的構(gòu)造方法,并且重寫父類中的 area() 方法。代碼如下:

public class Rectangle extends Figure {
    Rectangle(double d1, double d2) {
        super(d1, d2);
    }
    double area() {
        System.out.println("長(zhǎng)方形的面積:");
        return super.dim1 * super.dim2;
    }
}

創(chuàng)建繼承自 Figure 類的 Triangle 子類,該類與 Rectangle 相似。代碼如下:

public class Triangle extends Figure {
    Triangle(double d1, double d2) {
        super(d1, d2);
    }
    double area() {
        System.out.println("三角形的面積:");
        return super.dim1 * super.dim2 / 2;
    }
}

創(chuàng)建 Test 測(cè)試類,在該類的 main() 方法中首先聲明 Figure 類的變量 figure,然后分別為 figure 變量指定不同的對(duì)象,并調(diào)用這些對(duì)象的 area() 方法。代碼如下:

public class Test {
    public static void main(String[] args) {
        Figure figure; // 聲明Figure類的變量
        figure = new Rectangle(9, 9);
        System.out.println(figure.area());
        System.out.println("===============================");
        figure = new Triangle(6, 8);
        System.out.println(figure.area());
        System.out.println("===============================");
        figure = new Figure(10, 10);
        System.out.println(figure.area());
    }
}

從上述代碼可以發(fā)現(xiàn),無(wú)論 figure 變量的對(duì)象是 Rectangle 還是 Triangle,它們都是 Figure 類的子類,因此可以向上轉(zhuǎn)型為該類,從而實(shí)現(xiàn)多態(tài)。

執(zhí)行上述代碼,輸出結(jié)果如下:

長(zhǎng)方形的面積:

81.0 ===============================

三角形的面積:

24.0 ===============================

父類中計(jì)算對(duì)象面積的方法,沒(méi)有實(shí)際意義,需要在子類中重寫。

0.0

instanceof關(guān)鍵字

嚴(yán)格來(lái)說(shuō) instanceof 是 Java 中的一個(gè)雙目運(yùn)算符,由于它是由字母組成的,所以也是 Java 的保留關(guān)鍵字。在 Java 中可以使用 instanceof 關(guān)鍵字判斷一個(gè)對(duì)象是否為一個(gè)類(或接口、抽象類、父類)的實(shí)例,語(yǔ)法格式如下所示。

boolean result = obj instanceof Class

其中,obj 是一個(gè)對(duì)象,Class 表示一個(gè)類或接口。obj 是 class 類(或接口)的實(shí)例或者子類實(shí)例時(shí),結(jié)果 result 返回 true,否則返回 false。

下面介紹 Java instanceof 關(guān)鍵字的幾種用法。

1)聲明一個(gè) class 類的對(duì)象,判斷 obj 是否為 class 類的實(shí)例對(duì)象(很普遍的一種用法),如以下代碼:

Integer integer = new Integer(1);
System.out.println(integer instanceof Integer);  // true

2)聲明一個(gè) class 接口實(shí)現(xiàn)類的對(duì)象 obj,判斷 obj 是否為 class 接口實(shí)現(xiàn)類的實(shí)例對(duì)象,如以下代碼:

Java 集合中的 List 接口有個(gè)典型實(shí)現(xiàn)類 ArrayList。

public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable

所以我們可以用 instanceof 運(yùn)算符判斷 ArrayList 類的對(duì)象是否屬于 List 接口的實(shí)例,如果是返回 true,否則返回 false。

ArrayList arrayList = new ArrayList();
System.out.println(arrayList instanceof List);  // true

或者反過(guò)來(lái)也是返回 true

List list = new ArrayList();
System.out.println(list instanceof ArrayList);  // true

3)obj 是 class 類的直接或間接子類

我們新建一個(gè)父類 Person.class,代碼如下:

public class Person {
}

創(chuàng)建 Person 的子類 Man,代碼如下:

public class Man extends Person {
}

測(cè)試代碼如下:

Person p1 = new Person();
Person p2 = new Man();
Man m1 = new Man();
System.out.println(p1 instanceof Man);    // false
System.out.println(p2 instanceof Man);    // true
System.out.println(m1 instanceof Man);    // true

第 4 行代碼中,Man 是 Person 的子類,Person 不是 Man 的子類,所以返回結(jié)果為 false。

值得注意的是 obj 必須為引用類型,不能是基本類型。例如以下代碼:

int i = 0;
System.out.println(i instanceof Integer);  // 編譯不通過(guò)
System.out.println(i instanceof Object);  // 編譯不通過(guò)

所以,instanceof 運(yùn)算符只能用作對(duì)象的判斷。

當(dāng) obj 為 null 時(shí),直接返回 false,因?yàn)?null 沒(méi)有引用任何對(duì)象。

Integer i = 1;
System.out.println(i instanceof null);  // false

所以,obj 的類型必須是引用類型或空類型,否則會(huì)編譯錯(cuò)誤。

當(dāng) class 為 null 時(shí),會(huì)發(fā)生編譯錯(cuò)誤,錯(cuò)誤信息如下:

Syntax error on token "null", invalid ReferenceType

所以 class 只能是類或者接口。

方法重載

Java 允許同一個(gè)類中定義多個(gè)同名方法,只要它們的形參列表不同即可。如果同一個(gè)類中包含了兩個(gè)或兩個(gè)以上方法名相同的方法,但形參列表不同,這種情況被稱為方法重載(overload)。

例如,在 JDK 的 java.io.PrintStream 中定義了十多個(gè)同名的 println() 方法。

public void println(int i){…}
public void println(double d){…}
public void println(String s){…}

這些方法完成的功能類似,都是格式化輸出。根據(jù)參數(shù)的不同來(lái)區(qū)分它們,以進(jìn)行不同的格式化處理和輸出。它們之間就構(gòu)成了方法的重載。實(shí)際調(diào)用時(shí),根據(jù)實(shí)參的類型來(lái)決定調(diào)用哪一個(gè)方法。例如:

System.out.println(102);    // 調(diào)用println(int i)方法
System.out.println(102.25);    // 調(diào)用println(double d)方法
System.out.println("價(jià)格為 102.25");    // 調(diào)用println(String s)方法

方法重載的要求是兩同一不同:同一個(gè)類中方法名相同,參數(shù)列表不同。至于方法的其他部分,如方法返回值類型、修飾符等,與方法重載沒(méi)有任何關(guān)系。

使用方法重載其實(shí)就是避免出現(xiàn)繁多的方法名,有些方法的功能是相似的,如果重新建立一個(gè)方法,重新取個(gè)方法名稱,會(huì)降低程序可讀性。

為什么方法重載不能用方法的返回值類型區(qū)分呢?

對(duì)于int f() { }void f() { }兩個(gè)方法,如果這樣調(diào)用int result = f();,系統(tǒng)可以識(shí)別是調(diào)用返回值類型為 int 的方法,但 Java 調(diào)用方法時(shí)可以忽略方法返回值,如果采用如下方法來(lái)調(diào)用f();,你能判斷是調(diào)用哪個(gè)方法嗎?如果你尚且不能判斷,那么 Java 系統(tǒng)也會(huì)糊涂。在編程過(guò)程中有一條重要規(guī)則就是不要讓系統(tǒng)糊涂,系統(tǒng)一糊涂,肯定就是你錯(cuò)了。因此,Java 里不能用方法返回值類型作為區(qū)分方法重載的依據(jù)。

方法重寫

在子類中如果創(chuàng)建了一個(gè)與父類中相同名稱、相同返回值類型、相同參數(shù)列表的方法,只是方法體中的實(shí)現(xiàn)不同,以實(shí)現(xiàn)不同于父類的功能,這種方式被稱為方法重寫(override),又稱為方法覆蓋。當(dāng)父類中的方法無(wú)法滿足子類需求或子類具有特有功能的時(shí)候,需要方法重寫。

子類可以根據(jù)需要,定義特定于自己的行為。既沿襲了父類的功能名稱,又根據(jù)子類的需要重新實(shí)現(xiàn)父類方法,從而進(jìn)行擴(kuò)展增強(qiáng)。

在重寫方法時(shí),需要遵循下面的規(guī)則:

  • 參數(shù)列表必須完全與被重寫的方法參數(shù)列表相同。
  • 返回的類型必須與被重寫的方法的返回類型相同(Java1.5 版本之前返回值類型必須一樣,之后的 Java 版本放寬了限制,返回值類型必須小于或者等于父類方法的返回值類型)。
  • 訪問(wèn)權(quán)限不能比父類中被重寫方法的訪問(wèn)權(quán)限更低(public>protected>default>private)。
  • 重寫方法一定不能拋出新的檢査異?;蛘弑缺恢貙懛椒暶鞲訉挿旱臋z査型異常。例如,父類的一個(gè)方法聲明了一個(gè)檢査異常 IOException,在重寫這個(gè)方法時(shí)就不能拋出 Exception,只能拋出 IOException 的子類異常,可以拋出非檢査異常。

另外還要注意以下幾條:

  • 重寫的方法可以使用 @Override 注解來(lái)標(biāo)識(shí)。
  • 父類的成員方法只能被它的子類重寫。
  • 聲明為 final 的方法不能被重寫。
  • 聲明為 static 的方法不能被重寫,但是能夠再次聲明。
  • 構(gòu)造方法不能被重寫。
  • 子類和父類在同一個(gè)包中時(shí),子類可以重寫父類的所有方法,除了聲明為 private 和 final 的方法。
  • 子類和父類不在同一個(gè)包中時(shí),子類只能重寫父類的聲明為 public 和 protected 的非 final 方法。
  • 如果不能繼承一個(gè)方法,則不能重寫這個(gè)方法。

抽象類

Java 語(yǔ)言提供了兩種類,分別為具體類和抽象類。

在面向?qū)ο蟮母拍钪?,所有的?duì)象都是通過(guò)類來(lái)描繪的,但是反過(guò)來(lái),并不是所有的類都是用來(lái)描繪對(duì)象的,如果一個(gè)類中沒(méi)有包含足夠的信息來(lái)描繪一個(gè)具體的對(duì)象,那么這樣的類稱為抽象類。

在 Java 中抽象類的語(yǔ)法格式如下:

<abstract>class<class_name> {
    <abstract><type><method_name>(parameter-iist);
}

其中,abstract 表示該類或該方法是抽象的;class_name 表示抽象類的名稱;method_name 表示抽象方法名稱,parameter-list 表示方法參數(shù)列表。

如果一個(gè)方法使用 abstract 來(lái)修飾,則說(shuō)明該方法是抽象方法,抽象方法只有聲明沒(méi)有實(shí)現(xiàn)。需要注意的是 abstract 關(guān)鍵字只能用于普通方法,不能用于 static 方法或者構(gòu)造方法中。

抽象方法的 3 個(gè)特征如下:

  • 抽象方法沒(méi)有方法體
  • 抽象方法必須存在于抽象類中
  • 子類重寫父類時(shí),必須重寫父類所有的抽象方法

注意:在使用 abstract 關(guān)鍵字修飾抽象方法時(shí)不能使用 private 修飾,因?yàn)槌橄蠓椒ū仨毐蛔宇愔貙?,而如果使用?private 聲明,則子類是無(wú)法重寫的。

抽象類的定義和使用規(guī)則如下:

  • 抽象類和抽象方法都要使用 abstract 關(guān)鍵字聲明。
  • 如果一個(gè)方法被聲明為抽象的,那么這個(gè)類也必須聲明為抽象的。而一個(gè)抽象類中,可以有 0~n 個(gè)抽象方法,以及 0~n 個(gè)具體方法。
  • 抽象類不能實(shí)例化,也就是不能使用 new 關(guān)鍵字創(chuàng)建對(duì)象。

接口

抽象類是從多個(gè)類中抽象出來(lái)的模板,如果將這種抽象進(jìn)行的更徹底,則可以提煉出一種更加特殊的“抽象類”——接口(Interface)。接口是 Java 中最重要的概念之一,它可以被理解為一種特殊的類,不同的是接口的成員沒(méi)有執(zhí)行體,是由全局常量和公共的抽象方法所組成。

注意:一個(gè)接口可以有多個(gè)直接父接口,但接口只能繼承接口,不能繼承類。

定義接口

接口對(duì)于其聲明、變量和方法都做了許多限制,這些限制作為接口的特征歸納如下:

  • 具有 public 訪問(wèn)控制符的接口,允許任何類使用;沒(méi)有指定 public 的接口,其訪問(wèn)將局限于所屬的包。
  • 方法的聲明不需要其他修飾符,在接口中聲明的方法,將隱式地聲明為公有的(public)和抽象的(abstract)。
  • 在 Java 接口中聲明的變量其實(shí)都是常量,接口中的變量聲明,將隱式地聲明為 public、static 和 final,即常量,所以接口中定義的變量必須初始化。
  • 接口沒(méi)有構(gòu)造方法,不能被實(shí)例化。

例如:

public interface A {
    publicA(){…}    // 編譯出錯(cuò),接口不允許定義構(gòu)造方法
}

一個(gè)接口不能夠?qū)崿F(xiàn)另一個(gè)接口,但它可以繼承多個(gè)其他接口。子接口可以對(duì)父接口的方法和常量進(jìn)行重寫。例如:

public interface StudentInterface extends PeopleInterface {
    // 接口 StudentInterface 繼承 PeopleInterface
    int age = 25;    // 常量age重寫父接口中的age常量
    void getInfo();    // 方法getInfo()重寫父接口中的getInfo()方法
}

例如,定義一個(gè)接口 MyInterface,并在該接口中聲明常量和方法,如下:

public interface MyInterface {    // 接口myInterface
    String name;    // 不合法,變量name必須初始化
    int age = 20;    // 合法,等同于 public static final int age = 20;
    void getInfo();    // 方法聲明,等同于 public abstract void getInfo();
}

實(shí)現(xiàn)接口

接口的主要用途就是被實(shí)現(xiàn)類實(shí)現(xiàn),一個(gè)類可以實(shí)現(xiàn)一個(gè)或多個(gè)接口,繼承使用 extends 關(guān)鍵字,實(shí)現(xiàn)則使用 implements 關(guān)鍵字。因?yàn)橐粋€(gè)類可以實(shí)現(xiàn)多個(gè)接口,這也是 Java 為單繼承靈活性不足所作的補(bǔ)充。類實(shí)現(xiàn)接口的語(yǔ)法格式如下:

<public> class <class_name> [extends superclass_name] [implements interface1_name[, interface2_name…]] {
    // 主體
}

對(duì)以上語(yǔ)法的說(shuō)明如下:

  • public:類的修飾符;
  • superclass_name:需要繼承的父類名稱;
  • interface1_name:要實(shí)現(xiàn)的接口名稱。

實(shí)現(xiàn)接口需要注意以下幾點(diǎn):

  • 實(shí)現(xiàn)接口與繼承父類相似,一樣可以獲得所實(shí)現(xiàn)接口里定義的常量和方法。如果一個(gè)類需要實(shí)現(xiàn)多個(gè)接口,則多個(gè)接口之間以逗號(hào)分隔。
  • 一個(gè)類可以繼承一個(gè)父類,并同時(shí)實(shí)現(xiàn)多個(gè)接口,implements 部分必須放在 extends 部分之后。
  • 一個(gè)類實(shí)現(xiàn)了一個(gè)或多個(gè)接口之后,這個(gè)類必須完全實(shí)現(xiàn)這些接口里所定義的全部抽象方法(也就是重寫這些抽象方法);否則,該類將保留從父接口那里繼承到的抽象方法,該類也必須定義成抽象類。

總結(jié)

本篇文章就到這里了,希望可以幫助到你,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • Springboot整合Mybatispuls的實(shí)例詳解

    Springboot整合Mybatispuls的實(shí)例詳解

    這篇文章主要介紹了Springboot整合Mybatispuls的相關(guān)資料,本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-11-11
  • SpringBoot + FFmpeg實(shí)現(xiàn)一個(gè)簡(jiǎn)單的M3U8切片轉(zhuǎn)碼系統(tǒng)

    SpringBoot + FFmpeg實(shí)現(xiàn)一個(gè)簡(jiǎn)單的M3U8切片轉(zhuǎn)碼系統(tǒng)

    使用大名鼎鼎的ffmpeg,把視頻文件切片成m3u8,并且通過(guò)springboot,可以實(shí)現(xiàn)在線的點(diǎn)播。
    2021-05-05
  • SpringBoot如何進(jìn)行參數(shù)校驗(yàn)實(shí)例詳解

    SpringBoot如何進(jìn)行參數(shù)校驗(yàn)實(shí)例詳解

    開(kāi)發(fā)過(guò)程中,后臺(tái)的參數(shù)校驗(yàn)是必不可少的,下面這篇文章主要給大家介紹了關(guān)于SpringBoot如何進(jìn)行參數(shù)校驗(yàn)的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-01-01
  • java開(kāi)發(fā)非公平鎖不可打斷源碼示例解析

    java開(kāi)發(fā)非公平鎖不可打斷源碼示例解析

    這篇文章主要為大家介紹了java開(kāi)發(fā)非公平鎖不可打斷源碼示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(41)

    Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(41)

    下面小編就為大家?guī)?lái)一篇Java基礎(chǔ)的幾道練習(xí)題(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧,希望可以幫到你
    2021-07-07
  • 詳解Java數(shù)組擴(kuò)容縮容與拷貝的實(shí)現(xiàn)和原理

    詳解Java數(shù)組擴(kuò)容縮容與拷貝的實(shí)現(xiàn)和原理

    這篇文章主要帶大家學(xué)習(xí)數(shù)組的擴(kuò)容、縮容及拷貝,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • Java動(dòng)態(tài)代理四種實(shí)現(xiàn)方式詳解

    Java動(dòng)態(tài)代理四種實(shí)現(xiàn)方式詳解

    這篇文章主要介紹了Java四種動(dòng)態(tài)代理實(shí)現(xiàn)方式,對(duì)于開(kāi)始學(xué)習(xí)java動(dòng)態(tài)代理或者要復(fù)習(xí)java動(dòng)態(tài)代理的朋友來(lái)講很有參考價(jià)值,有感興趣的朋友可以參考一下
    2021-04-04
  • 詳解JAVA中priorityqueue的具體使用

    詳解JAVA中priorityqueue的具體使用

    這篇文章主要介紹了詳解JAVA中priorityqueue的具體使用,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-01-01
  • Java實(shí)現(xiàn)常見(jiàn)排序算法的優(yōu)化

    Java實(shí)現(xiàn)常見(jiàn)排序算法的優(yōu)化

    今天給大家?guī)?lái)的是關(guān)于Java的相關(guān)知識(shí),文章圍繞著Java實(shí)現(xiàn)常見(jiàn)排序算法的優(yōu)化展開(kāi),文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-01-01
  • 詳解Spring Cloud負(fù)載均衡重要組件Ribbon中重要類的用法

    詳解Spring Cloud負(fù)載均衡重要組件Ribbon中重要類的用法

    本篇文章主要介紹了詳解Spring Cloud負(fù)載均衡重要組件Ribbon中重要類的用法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-03-03

最新評(píng)論