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

Java抽象類和接口使用梳理

 更新時(shí)間:2022年02月14日 11:29:36   作者:Word碼鴨  
對(duì)于面向?qū)ο缶幊虂碚f,抽象是它的一大特征之一,在?Java?中可以通過兩種形式來體現(xiàn)OOP的抽象:接口和抽象類,下面這篇文章主要給大家介紹了關(guān)于Java入門基礎(chǔ)之抽象類與接口的相關(guān)資料,需要的朋友可以參考下

抽象類

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

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

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

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

抽象方法

示例:

public abstract void print();

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

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

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

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

抽象類三大原則

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

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

Triangle是一個(gè)普通類,此時(shí)沒覆寫方法就報(bào)錯(cuò)了,這時(shí)我們使用alt + enter 快捷鍵,點(diǎn)擊第一行,再點(diǎn)擊ok,就覆寫了父類的抽象方法

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

3.final 和 abstract 不能同時(shí)使用、private 和 abstract 不能同時(shí)使用

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

abstract class Person

class Chinese extends Person  √  

class Dog extends Person × //因?yàn)镈og not is a Person

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

接口

Java使用 interface 關(guān)鍵字定義接口,接口中只有全局常量和抽象方法(JDK之前)JDK8擴(kuò)展了default方法。子類使用 implements 實(shí)現(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.接口沒有單繼承限制,子類可以同時(shí)實(shí)現(xiàn)多個(gè)父接口,多個(gè)接口之間使用逗號(hào)分隔。此時(shí)子類必須實(shí)現(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 繼承多個(gè)父接口,下面的示例若類要實(shí)現(xiàn)接口 C ,就必須覆寫 A、B、C中所有的抽象方法

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

3.接口依然不能直接實(shí)例化對(duì)象,需要通過向上轉(zhuǎn)型實(shí)現(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)換實(shí)現(xiàn)調(diào)用

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

//輸出:hello n~

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

public class D  extends A  implements X,Y{  } 

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

java.lang.Comparable 比較接口

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

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));
    }
}

運(yùn)行結(jié)果:

程序報(bào)錯(cuò),因?yàn)镾tudent類是自定義類型,當(dāng)使用Arrays.sort方法對(duì)自定義類型進(jìn)行排序時(shí),自定義類型需要實(shí)現(xiàn) Comparable 才具有可比較的能力

因此我們將上述示例做如下改動(dòng):

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ù)一

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

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

java.lang.Cloneable 克隆接口

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

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

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

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

這里我們就能知道一個(gè)小知識(shí)點(diǎn):沒有方法體的方法不一定就是抽象方法

代碼示例:

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é)果:

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

對(duì)象的深淺拷貝

我們先看一個(gè)示例:

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 指向了相同的對(duì)象

這就是淺拷貝,拷貝出的 b1 對(duì)象只是拷貝了 b1 自身, 而沒有拷貝內(nèi)部包含的 a 對(duì)象. 此時(shí) b1 和 b2 中包含的 a 引用仍然是指向同一個(gè)對(duì)象. 此時(shí)修改一邊, 另一邊也會(huì)發(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類也實(shí)現(xiàn)克隆接口,可以看到b1.a的修改沒有影響b2.a,說明此時(shí)b1和b2內(nèi)部包含的a對(duì)象也是不同的,這種拷貝就叫做深拷貝

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

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

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

相關(guān)文章

最新評(píng)論