溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java抽象類和接口怎么用

發(fā)布時間:2022-02-14 14:33:47 來源:億速云 閱讀:146 作者:小新 欄目:開發(fā)技術(shù)

這篇文章將為大家詳細(xì)講解有關(guān)Java抽象類和接口怎么用,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

    抽象類

    什么是抽象類呢?在現(xiàn)實生活中,我們說“人類”,我們無法對應(yīng)到具體某個人,同樣的,“動物類”、“圖形類”這些無法映射到具體的對象的類就是抽象類。

    抽象類是普通類的超集,意思就是普通類有的抽象類也有,只是它比普通類多了一些抽象方法而已。這些抽象方法可以有一個,也可以有多個。

    它存在的意義就是讓子類來覆寫它的抽象方法,抽象類和抽象方法的實現(xiàn)使用 abstract 關(guān)鍵字實現(xiàn): 

    Java抽象類和接口怎么用

    此時Sharp類就是抽象類,可以看到它的圖標(biāo)和普通類都有所不同。

    抽象方法

    示例:

    public abstract void print();

    抽象方法所在的類一定是抽象類,抽象方法只有方法聲明,沒有方法體{}

    注意區(qū)分沒有方法體和方法體為空的情況

    public abstract void print();//這是沒有方法體

    public abstract void print(){  } //這是方法體為空,它是普通方法

    抽象類三大原則

    1.抽象類無法直接實例化對象。例如上面的 Sharp 類,Sharp  sharp  = new Sharp();//這是錯誤的

    2.子類繼承抽象類,必須覆寫抽象類中的所有抽象方法(前提是子類是普通類)

    Java抽象類和接口怎么用

    Triangle是一個普通類,此時沒覆寫方法就報錯了,這時我們使用alt + enter 快捷鍵,點擊第一行,再點擊ok,就覆寫了父類的抽象方法

    Java抽象類和接口怎么用

    Java抽象類和接口怎么用

    但是當(dāng)子類依然是抽象類時,可以選擇不覆寫抽象方法

    Java抽象類和接口怎么用

    3.final 和 abstract 不能同時使用、private 和 abstract 不能同時使用

    Java抽象類和接口怎么用

    抽象類存在的最大意義就是被繼承,而且它仍然滿足繼承關(guān)系的 is a 原則

    abstract class Person

    class Chinese extends Person  √  

    class Dog extends Person × //因為Dog not is a Person

    同時抽象類任然受到單繼承的局限,此時我們就引出了接口來打破這兩個局限

    接口

    Java使用 interface 關(guān)鍵字定義接口,接口中只有全局常量和抽象方法(JDK之前)JDK8擴(kuò)展了default方法。子類使用 implements 實現(xiàn)接口

    一般接口的命名使用大寫 ' I ' 字母開頭,子類命名以 Impl 結(jié)尾

    全局常量:

    public static final int NUM = 10;

    抽象方法:

    public abstract String msg( );

    接口使用原則

    1.接口中只有 public 權(quán)限,且只有全局常量和抽象方法,所以 abstract、static、final、public這些關(guān)鍵字在接口內(nèi)部都可以省略

    public interface IMassage {
        int NUM = 10;//全局常量
         String msg();//抽象方法
    }

    2.接口沒有單繼承限制,子類可以同時實現(xiàn)多個父接口,多個接口之間使用逗號分隔。此時子類必須實現(xiàn)父類接口中所有的抽象方法

    public interface IMassage {
        int NUM = 10;//全局常量
        String msg();//抽象方法
    }
     interface INews{
        void getNews();
    }
     
    //子類
    public class MessageImpl implements IMassage,INews{
     
        public String msg() {
            return null;
        }
        public void getNews() {
     
        }
    }

    接口可以使用 extends 繼承多個父接口,下面的示例若類要實現(xiàn)接口 C ,就必須覆寫 A、B、C中所有的抽象方法

        interface A{
            void testA();
        }
        interface B{
            void testB();
        }
        interface C extends A,B{
            
        }

    3.接口依然不能直接實例化對象,需要通過向上轉(zhuǎn)型實現(xiàn)

    public class MessageImpl implements IMassage,INews{
     
        public String msg() {
            return "hello JAVA";
        }
     
        public void getNews() {
          System.out.println("hello n~");
     
        }
     
        public static void main(String[] args) {
            IMassage m = new MessageImpl();
            System.out.println(m.msg());
     
        }
    }

    //輸出:hello JAVA

    m只能調(diào)用msg方法,不能調(diào)用INews接口類定義的方法,需要用父類間的相互轉(zhuǎn)換實現(xiàn)調(diào)用

            INews n = (INews)m;
            n.getNews();

    //輸出:hello n~

    4.子類若既要繼承類又要實現(xiàn)接口,就先繼承,后實現(xiàn)接口

    public class D  extends A  implements X,Y{  } 

    JDK兩大內(nèi)置接口

    java.lang.Comparable 比較接口

    引入示例:使用排序方法比較Student類中的對象

    public class Student {
        private String name;
        private int age;
        public Student(String name,int age){
            this.name = name;
            this.age = age;
        }
        public String toString(){
            return "Student{" +
        "name=" + name+'\''+ ",age="+ age + '}';
        }
     
        public static void main(String[] args) {
            Student s1 = new Student("張三",18);
            Student s2 = new Student("李四",20);
            Student s3 = new Student("王五",30);
            Student[] students = {s3,s1,s2};
            Arrays.sort(students);
            System.out.println(Arrays.toString(students));
        }
    }

    運行結(jié)果:

    Java抽象類和接口怎么用

    程序報錯,因為Student類是自定義類型,當(dāng)使用Arrays.sort方法對自定義類型進(jìn)行排序時,自定義類型需要實現(xiàn) Comparable 才具有可比較的能力

    因此我們將上述示例做如下改動:

    public class Student implements Comparable<Student>{
        private String name;
        private int age;
        public Student(String name,int age){
            this.name = name;
            this.age = age;
        }
        public String toString(){
            return "Student{" +
        "name=" + name+'\''+ ",age="+ age + '}';
        }
        @Override
        public int compareTo(Student o) {
            if (this.age == o.age){
                return 0;
            }else if (this.age < o.age){
                return -1;
            }
            return 1;
        }
     
        public static void main(String[] args) {
            Student s1 = new Student("張三",18);
            Student s2 = new Student("李四",20);
            Student s3 = new Student("王五",30);
            Student[] students = {s3,s1,s2};//亂序放入數(shù)組
            Arrays.sort(students);
            System.out.println(Arrays.toString(students));
        }
     
    }

    //輸出結(jié)果:
    [Student{name=張三',age=18}, Student{name=李四',age=20}, Student{name=王五',age=30}]

    可以看到數(shù)組按照年齡的升序排序,達(dá)到了預(yù)期效果。如果想要按照年齡降序排列,只需要修改 compareTo 方法中的一和負(fù)一

    Java抽象類和接口怎么用

    實現(xiàn)Comparable接口,必須覆寫它的compareTo方法,該方法返回的數(shù)字:

    • =0 表示當(dāng)前對象等于目標(biāo)對象 o

    • >0 表示當(dāng)前對象等于目標(biāo)對象 o

    • <0 表示當(dāng)前對象等于目標(biāo)對象 o

    java.lang.Cloneable 克隆接口

    在程序中,克隆是指復(fù)制一個新的對象,而這個新對象的屬性值是從舊對象中拷貝過來的

    Cloneable 接口是一個標(biāo)記接口,本身沒有任何抽象方法,當(dāng)一個類實現(xiàn)了 Cloneable 接口,就表示該類具備了克隆的能力,這個能力是JVM賦予的,要知道在堆上開辟空間和對象創(chuàng)建都由JVM實現(xiàn)。

    我們需要覆寫 Object 類的 clone 方法,點擊向上轉(zhuǎn)型的圖標(biāo)我們就能看到 Object 提供的該方法

    Java抽象類和接口怎么用

    Java抽象類和接口怎么用

    可以看到,clone 方法沒有方法體,用 native 關(guān)鍵字修飾,叫做本地方法,clone方法不是Java語言實現(xiàn)的,而是C++實現(xiàn)的,要知道JVM就是由C++實現(xiàn)的。所以本地方法就表示Java調(diào)用了C++的同名方法,此處只是方法聲明,具體的方法實現(xiàn)是在C++中。所以雖然它沒有方法體,但它并不是抽象方法。

    Java抽象類和接口怎么用

    這里我們就能知道一個小知識點:沒有方法體的方法不一定就是抽象方法

    代碼示例:

    public class Cat implements Cloneable{
        private String name;
     
        @Override
        protected Cat clone() throws CloneNotSupportedException {
            return (Cat) super.clone();
        }
     
        public static void main(String[] args) throws CloneNotSupportedException {
            Cat c1 = new Cat();
            c1.name = "喵喵";
            Cat c2 = c1.clone();
            System.out.println(c1 == c2);
            System.out.println(c2.name);
        }
    }

    輸出結(jié)果:

    Java抽象類和接口怎么用

    可以看到,輸出 false表示c1和c2不是同一個地址,也就是說在堆上為c2開辟了一個新空間,將c1的值拷貝給了c2

    對象的深淺拷貝

    我們先看一個示例:

    class A{
        int num;
    }
    public class B implements Cloneable{
        A a = new A();
     
        @Override
        protected B clone() throws CloneNotSupportedException {
            return (B)super.clone();
        }
     
        public static void main(String[] args) throws CloneNotSupportedException {
            B b1 = new B();
            B b2 = b1.clone();
            System.out.println(b1 == b2);
            System.out.println(b2.a.num);
            b1.a.num = 100;
            System.out.println(b2.a.num);
        }
    }

    輸出:false
    0
    100

    根據(jù)結(jié)果我們看到,將b1.a的值改為100后,b2.a也隨之變化,就是說b1.a 和 b2.a 指向了相同的對象

    Java抽象類和接口怎么用

    這就是淺拷貝,拷貝出的 b1 對象只是拷貝了 b1 自身, 而沒有拷貝內(nèi)部包含的 a 對象. 此時 b1 和 b2 中包含的 a 引用仍然是指向同一個對象. 此時修改一邊, 另一邊也會發(fā)生改變.

    我們將代碼做如下修改:

    class A implements Cloneable{
        int num;
     
        @Override
        protected A clone() throws CloneNotSupportedException {
            return (A)super.clone();
        }
    }
    public class B implements Cloneable{
        A a = new A();
     
        @Override
        protected B clone() throws CloneNotSupportedException {
            B b = new B();
            b.a = a.clone();
            return b;
        }
     
        public static void main(String[] args) throws CloneNotSupportedException {
            B b1 = new B();
            B b2 = b1.clone();
            System.out.println(b1 == b2);
            System.out.println(b2.a.num);
            b1.a.num = 100;
            System.out.println(b2.a.num);
        }
    }

    結(jié)果:false
    0
    0

    我們讓A類也實現(xiàn)克隆接口,可以看到b1.a的修改沒有影響b2.a,說明此時b1和b2內(nèi)部包含的a對象也是不同的,這種拷貝就叫做深拷貝

    在Java中,實現(xiàn)深拷貝的方式有兩種:一種是遞歸實現(xiàn)Cloneable,上述的例子就是遞歸實現(xiàn)的;另外一種就是通過序列化(Serializable 接口)來進(jìn)行拷貝。這兩種方法現(xiàn)在已經(jīng)不常用了,現(xiàn)在實現(xiàn)深拷貝是將對象轉(zhuǎn)為json字符串

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

    Java抽象類和接口怎么用

    關(guān)于“Java抽象類和接口怎么用”這篇文章就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,使各位可以學(xué)到更多知識,如果覺得文章不錯,請把它分享出去讓更多的人看到。

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI