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

Java超詳細(xì)分析抽象類和接口的使用

 更新時間:2022年04月25日 15:30:20   作者:厚積薄發(fā)?  
在類中沒有包含足夠的信息來描繪一個具體的對象,這樣的類稱為抽象類,接口是Java中最重要的概念之一,它可以被理解為一種特殊的類,不同的是接口的成員沒有執(zhí)行體,是由全局常量和公共的抽象方法所組成,本文給大家介紹Java抽象類和接口,感興趣的朋友一起看看吧

什么是抽象類

什么是抽象類呢?抽象類顧名思義就是很抽象,就是當(dāng)我們沒有足夠的信息去描述這個類的時候我們就可以先不用描述,這樣的類就是抽象類。

用代碼舉個例子:

class Shape {
    public void draw() {
        System.out.println("我要畫圖形??!");
    }
}
class circle extends Shape {
    @Override
    public void draw() {
        System.out.println("我要畫圓形!??!");
    }
}
class rect extends Shape {
    @Override
    public void draw() {
        System.out.println("我要畫矩形?。?!");
    }
}
public class TestDemo3 {
    public static void drawShape(Shape shape) {
        shape.draw();
    }
    public static void main(String[] args) {
        drawShape(new circle());
        drawShape(new rect());
    }
}

正好也通過這個小小的案例來復(fù)習(xí)一下多態(tài),我們創(chuàng)建一個Shape父類,然后又創(chuàng)建兩個子類分別為 rect類和circle類 然后利用這兩個類使用同一個方法,產(chǎn)生的形態(tài)是不一樣的這就是多態(tài),但是

我們可以發(fā)現(xiàn)我只用了這兩個子類來畫圖形分別是圓形和矩形,我并沒有調(diào)用父類來實現(xiàn)這個方法,為啥呢???就是因為這個父類并不能畫出圖形,那這個父類的draw方法的實現(xiàn)豈不是沒有用,我只需要它父類要有這方法,通過子類重寫就可以了,不需要父類的方法有具體的實現(xiàn)。

沒錯,這就引入到我們今天的主題抽象類

上面父類的draw方法由于它的具體實現(xiàn)根本沒有用處,所以我們就可以不寫,這也正符合抽象類的定義,當(dāng)不能有足夠的信息去描述它,那我們就把它叫做抽象類。

抽象類語法

上面父類的draw方法沒有具體的實現(xiàn)我們就可以把它叫做抽象方法。利用abstract來修飾

public abstract void draw();

但是這樣為啥會報錯呢??

原因是被abstract修飾的方法叫做抽象方法,如果一個類里面有抽象方法,那這個類一定是抽象類,所以類也要被abstract來修飾。

但是相反,抽象類里面一定有抽象方法么???

編譯器并不會報錯,所以答案是不一定,抽象類里面可以有抽象方法也可以沒有抽象方法。

抽象類能否被實例化呢???

所以,抽象類是不能實例化的。 

抽象類能否像普通類一樣定義成員變量和方法,構(gòu)造方法呢???

抽象類與普通類的區(qū)別就是在與抽象類不能實例化,其他定義成員變量,成員方法,構(gòu)造方法等等都是一樣的。

 既然抽象類不能實例化,那他存在的意義是什么呢???

老鐵思考的有道理,其實抽象類最大的意義就是被繼承,因為抽象類不能實例化對象,只能依靠子類來重寫父類(就是抽象類)的方法來完成業(yè)務(wù)需求。

怎么繼承抽象類呢???有哪些注意的點(diǎn)呢???

 這樣繼承為啥會出錯呢??原因是在子類繼承抽象類的時候,子類需要重寫父類的所有方法或者子類需要用abstract修飾(抽象類被抽象類繼承或者子類重寫抽象類(父類)的所有方法)。

這樣就正確了。

這里還要注意當(dāng)我們沒有重寫父類的方法時而是用abstract來修飾,這時當(dāng)你在次繼承這個子類的時候也就是這個子類變成了父類,下一個子類還是要繼續(xù)重寫這個父類的方法和這個父類的父類的方法。 

抽象方法能否別static和final修飾呢???

 抽象方法不能被static  和final 修飾,因為子類要重寫父類的方法,同時可以省略訪問修飾限定符,默認(rèn)是public。

總結(jié)抽象類:

  • 我們把不能足夠描述清楚一個對象的類叫做抽象類。
  • 被abstract修飾的方法稱為抽象方法,被abstract修飾的類稱為抽象類
  • 抽象方法必須在抽象類里面,也就是說,只要有抽象方法,類名也必須利用abstract來修飾,相反,抽象類里面可以沒有抽象方法,也可以有抽象方法。
  • 抽象類不能實例化,除了不能實例化之外其他與普通類一樣可以定義成員變量,成員方法,構(gòu)造方法等。同時構(gòu)造方法和類方法(被static修飾的方法)不能被abstract來修飾
  • 抽象方法的訪問修飾限定符不能是private,如果省略默認(rèn)是public,同時抽象方法不能被final修飾。
  • 子類繼承抽象類的時候,子類必須重寫抽象類的所有方法并且要有方法的具體實現(xiàn),如果重寫那子類還是抽象類,必須用abstract來修飾。
  • 抽象類中的方法沒有具體實現(xiàn),要通過子類重寫在子類中實現(xiàn)。
  • 一個類只能繼承一個抽象類

接口

說到接口我們會想到什么呢???我一開始想到的就是充電接口插排等等,比如充電接口,只要符合那個插口的標(biāo)準(zhǔn),我們都可以使用那個接口來進(jìn)行充電。這就是把標(biāo)準(zhǔn)進(jìn)行統(tǒng)一起來,然后大家就可以根據(jù)不同的標(biāo)準(zhǔn)來使用不同的接口,比如蘋果手機(jī)與安卓手機(jī)的手機(jī)接口就是不一樣的,他們就是兩種不同的標(biāo)準(zhǔn),安卓手機(jī)用安卓的接口,蘋果用蘋果的接口這就將標(biāo)準(zhǔn)統(tǒng)一起來。

而在Java中也是一樣的,我們把這個標(biāo)準(zhǔn)或者可以說是一種公共的規(guī)范叫做接口,只要符合這一接口的標(biāo)準(zhǔn)我們就可以使用它。

聽著這抽象的概念你可能現(xiàn)在還是不太明白這到底是什么,我在來拿代碼舉個例子:

class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println(this.name+"吃飯***!");
    }
}

這里我定義了一個動物類,這個動物有名字,年齡,還有吃飯的行為。

class Animal {
    public String name;
    public int age;
    public void eat() {
        System.out.println(this.name+"吃飯***!");
    }
    public void swim() {
        System.out.println("我要游泳~~~~");
    }
}
class Fish extends Animal {
}

接著我又定義了一個魚類(子類)繼承這個動物類(父類),我想讓這個魚有這個游泳的行為,但是這就會有一個問題,在父類定義了一個swim方法,接著我還要定義很多類,難道所有的類都要有這個游泳的行為么???答案是不可以的。所以我們就不能把這個swim方法定義在父類里面,那我們就可以把這個方法定義在子類(魚類)里面,這樣就符合了,但是如果我還要定義1000個動物都會游泳難道都要在自己類中寫這個游泳的方法么??這樣做顯然是不可行的。那我們該怎么做呢??

我們可以就提供一個公共的接口,這也是一種標(biāo)準(zhǔn),只要符合這一標(biāo)準(zhǔn)都可以使用這個接口或者可以說可以實現(xiàn)這一功能。

看了上面的引例我們應(yīng)該接口是干什么的了,接下來我們來學(xué)一下接口的語法。

怎么定義接口

定義接口要使用interface關(guān)鍵字:

//創(chuàng)建一個接口
//創(chuàng)建接口要是用interface關(guān)鍵字  接口的命名最好是形容詞其他的也可以
interface IFlying{
    //這就是一個flying接口
}

接口中的成員變量:

這樣會報錯,接口中的成員變量都是常量,所以必須初始化,接口中的成員變量會被隱式指定為public static final 修飾的。

interface IFlying{
    //接口中的成員變量默認(rèn)都是被public static final修飾的常量
    //這里的成員變量不可改變
   public static final int a =10;
}

接口中的成員方法:

interface IFlying{
    //接口中的成員方法都是抽象方法,默認(rèn)是public abstract 
    //其中public abstract 可以被省略
    //接口中的成員方法不能有具體的實現(xiàn)
    public abstract void eat();
    //一般就寫成:
    //void eat();
    default void sleep(){
        //接口中的方法想要具體實現(xiàn),要加上default修飾
    }
    //接口中可以有靜態(tài)方法的具體實現(xiàn)
    public static void method() {
        System.out.println("我是靜態(tài)的方法!!");
    }
}

接口能否實例化???

接口是不能被實例化的。

怎么使用接口???

實現(xiàn)的接口如下:

interface IFlying{
    void eat();
}
interface IRunning{
    void run();
}
interface ISwimming{
    void swim();
}
interface IClimbing{
    void climb();
}
//創(chuàng)建一個Ant類 
//利用implements關(guān)鍵字來實現(xiàn)接口
//一個類可以實現(xiàn)多個接口,接口之間利用逗號連接
//實現(xiàn)了接口必須要在接口中重寫接口中的方法
//重寫方法快捷鍵:鼠標(biāo)移動到implements關(guān)鍵字上然后 alt+enter
class Ant implements IClimbing,IRunning{
    public String name;
    @Override
    public void run() {
        System.out.println(this.name+"要跑步");
    }
    @Override
    public void climb() {
        System.out.println(this.name+"爬山");
    }
}
  • 接口的使用時利用implements關(guān)鍵字與類連接,類與接口之間使用implements連接的。
  • 一個類可以實現(xiàn)多個接口,多個接口之間利用逗號連接。
  • class Ant implements IClimbing,IRunning.的意思是類Ant可以實現(xiàn)兩個功能,既可以爬又可以跑。
  • 類實現(xiàn)接口時,必須要重寫接口中的方法。如果不重寫該類還是抽象類,要用abstract來修飾。
  • 接口能否有靜態(tài)方法和代碼塊呢???

  • 接口中是不能有靜態(tài)代碼塊和構(gòu)造方法的。 

接口間的繼承

我們這里總結(jié)一下類與接口之間的聯(lián)系

  • 類與類之間是繼承關(guān)系利用extends來連接   代表子類繼承了父類
  • 類與接口之間是利用implements來連接, 代表類能實現(xiàn)某個功能
  • 接口與接口之間也可以進(jìn)行聯(lián)系,利用extends 接口A和接口B  interface A enxtends B 代表接口A拓展了接口B的功能。

這里來講一下接口與接口之間的繼承

我們利用extends關(guān)鍵字將兩個接口連接起來,這樣就實現(xiàn)了接口之間的繼承。

例如:

interface IRunning extends IFlying{
    //類IRunning拓展了IFlying的功能
    void run();
    //接口與接口之間繼承后IRunning拓展了IFlying功能
    //有了IRunning的功能的類也要重寫IFlying這個方法
}
  • 類IRunning拓展了IFlying的功能
  • 接口與接口之間繼承后IRunning拓展了IFlying功能
  • 有了IRunning的功能的類也要重寫IFlying這個方法

幾個重要的接口

接口comparable

我們這里舉一個例子:

比如我們要進(jìn)行給一個學(xué)生進(jìn)行排序,我們之前學(xué)過Arrays的sort方法,好我們來嘗試一下這個方法對學(xué)生進(jìn)排序。

class Student{
    public String name;
    public int age;
    public double score;
    public Student(String name, int age, double score) {
        this.name = name;
        this.age = age;
        this.score = score;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                '}';
    }
}
public class TestDemo {
    public static void main(String[] args) {
        Student[] student = new Student[4];
        student[0] = new Student("張三",18,88);
        student[1] = new Student("李四",98,98);
        student[2] = new Student("王二麻子",8,18);
        student[3] = new Student("趙老八",58,38);
        System.out.println(Arrays.toString(student));
        Arrays.sort(student);
        System.out.println(Arrays.toString(student));
    }
}

從這里發(fā)現(xiàn)Arrays.sort方法是比較具體的數(shù)字大小的,而我們這里比較學(xué)生這個對象并沒有指定,我們究竟依靠什么來比較這個學(xué)生對象,目前這個學(xué)生有名字,分?jǐn)?shù),年齡,我們到底依靠什么比較是根據(jù)我們的需求來定,那我們要具體的比較學(xué)生對象的某一個學(xué)生怎么比較呢·???看報錯信息也就是這個異常,我們需要提供這個comparable這個接口然后重寫這個comparable方法。

怎樣提供接口????

 我們根據(jù)類要實現(xiàn)一個接口是利用關(guān)鍵字implements來連接的。

 然后使用comparable這個接口,尖括號里面寫上你要排序的類。

好這樣我們就實現(xiàn)了這個接口,當(dāng)然看前面那個紅線就知道會有報錯,這也就是當(dāng)我們實現(xiàn)一個接口我們必須重寫這個接口中的方法,然后Alt+enter重寫這個接口中的方法。

好,我們就重寫了這樣的一個方法,比如我們要比較年齡按照升序排列:

然后調(diào)用Arrays.sort方法就可以進(jìn)行排序了。

 同樣我們還可以根據(jù)名字排序:

由于,名字是String類型也就是引用類型所以我們要調(diào)用compareTo方法來進(jìn)行比較。

同樣的我們還可以根據(jù)分?jǐn)?shù)來排序這個學(xué)生對象。

comparator接口-比較器

我們剛才使用comparable這個接口會有一個缺陷,就比如當(dāng)我們已經(jīng)實現(xiàn)按照年齡排序好了,但是有個人突然把他改成了名字比較,如果是未來做項目開發(fā)的時候,那就會給程序猿造成很大的困擾,就怕有一天別人修改了那段代碼,所以我們就有了這個comparator這個比較器,我們還是把他封裝起來,不用在去學(xué)生這個類中去修改。

對學(xué)生年齡排序:

class AgeComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.age - o2.age;
    }
}

對學(xué)生分?jǐn)?shù)排序:

class ScoreComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return (int)(o1.score - o2.score);
    }
}

對學(xué)生名字排序:

class NameComparator implements Comparator<Student>{
    @Override
    public int compare(Student o1, Student o2) {
        return o1.name.compareTo(o2.name);
    }
}

我們還是利用Arrays.sort方法里面再加一個比較器的這個參數(shù)就可以比較了。

 public static void main(String[] args) {
        Student[] student = new Student[4];
        student[0] = new Student("張三",18,88);
        student[1] = new Student("李四",98,98);
        student[2] = new Student("王二麻子",8,18);
        student[3] = new Student("趙老八",58,38);
        System.out.println(Arrays.toString(student));
        AgeComparator ageComparator = new AgeComparator();
        Arrays.sort(student,ageComparator);
        System.out.println(Arrays.toString(student));
    }

這樣我們將根據(jù)什么排序,實例化對應(yīng)的對象,通過對象調(diào)用重寫comparator的方法就可以進(jìn)行比較,不需要擔(dān)心類中被修改。

cloneable接口深入理解深拷貝與淺拷貝

我們之前學(xué)過數(shù)組中的克隆方法,就是把一個數(shù)組中的內(nèi)容全部拷貝到另外一個數(shù)組中去。

今天我們學(xué)的cloneable接口可以將一個對象的屬性拷貝到另外一個對象里面去。

怎么使用cloneable接口

我們創(chuàng)建一個人這個類,人這個類中有兩個屬性,一個是分?jǐn)?shù),一個是smartphone這個對象(引用類型)。

class SmartPhone{
    public int money = 9999;
}
class Person{
    public int score = 96;
    SmartPhone smartPhone = new SmartPhone();
}
public class TestDemo {
    public static void main(String[] args){
        Person person1 = new Person();
    }
}

我們現(xiàn)在要將這個person這個類實現(xiàn)cloneable接口,利用implements連接,同樣的我們要重寫這個cloneable這個接口中的方法。

這里我們要注意·重寫cloneable這個方法,它的返回類型是object,object是Java中所有類的父類。

好,完成了接口的操作,我們接下來完成克隆的工作,我們怎么使用clone這個方法來進(jìn)行克隆呢???

淺拷貝:

//淺拷貝
class SmartPhone{
    public int money = 9999;
}
class Person implements  Cloneable{
    public int score = 96;
    SmartPhone smartPhone = new SmartPhone();
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        return "Person{" +
                "score=" + score +
                ", smartPhone=" + smartPhone +
                '}';
    }
}
public class TestDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person();
        Person person2 = (Person)person1.clone();
        System.out.println(person1.smartPhone.money);
        System.out.println(person2.smartPhone.money);
        person1.smartPhone.money=9;
        System.out.println("===============拷貝之后=================");
        System.out.println(person1.smartPhone.money);
        System.out.println(person2.smartPhone.money);
    }
}

 原因是什么呢??畫一下圖理解一下

 這就是淺拷貝,對基本數(shù)據(jù)類型進(jìn)行值傳遞,對引用數(shù)據(jù)類型進(jìn)行引用傳遞般的拷貝,此

為淺拷貝。只要將money值進(jìn)行修改兩個對象的money的值都改變,沒有徹底的拷貝。

深拷貝

//深拷貝
class SmartPhone implements  Cloneable{
    public int money = 9999;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
    @Override
    public String toString() {
        return "SmartPhone{" +
                "money=" + money +
                '}';
    }
}
class Person implements  Cloneable{
    public int score = 96;
    SmartPhone smartPhone = new SmartPhone();
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Person tmp = (Person)super.clone();
        tmp.smartPhone= (SmartPhone) this.smartPhone.clone();
        return tmp;
    }
    @Override
    public String toString() {
        return "Person{" +
                "score=" + score +
                ", smartPhone=" + smartPhone +
                '}';
    }
}
public class TestDemo {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person person1 = new Person();
        Person person2 = (Person)person1.clone();
        System.out.println(person1.smartPhone.money);
        System.out.println(person2.smartPhone.money);
        person1.smartPhone.money=9;
        System.out.println("===============拷貝之后=================");
        System.out.println(person1.smartPhone.money);
        System.out.println(person2.smartPhone.money);
    }
}

 此時為深拷貝,進(jìn)行了徹底的拷貝。對基本數(shù)據(jù)類型進(jìn)行值傳遞,對引用數(shù)據(jù)類型,創(chuàng)建一個新的對象,并復(fù)制其內(nèi)容,此為深拷貝。

到此這篇關(guān)于Java超詳細(xì)分析抽象類和接口的使用的文章就介紹到這了,更多相關(guān)Java抽象類與接口內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評論