簡體   English   中英

普通接口類和只有抽象方法的抽象類之間有什么區別嗎?

[英]Are there any differences between a normal interface class and an abstract class that only has abstract methods?

我只是好奇他們是否受到任何不同的對待。

例如,如果我們有:

界面:

public interface Test {
    public void method();
}

和抽象類:

public abstract class Test {
    public abstract void method();
}

JVM會以不同的方式對待這些類嗎? 兩者中哪一個在存儲過程中占用更多的磁盤空間,哪一個會占用最多的運行時內存,哪個執行更多的操作(性能更好)。

這個問題與何時使用接口或抽象類無關。

是的,它們是不同的。

使用接口,客戶端可以實現它以及擴展一個類:

class ClientType implements YourInterface, SomeOtherInterface { //can still extend other types

}

使用類,客戶端將能夠擴展它,但不能擴展任何其他類型:

class ClientType extends YourClass { //can no longer extend other types

}

interfaceabstract class只有一個抽象方法聲明時,就會出現另一個區別,它與匿名函數(lambdas)有關。

正如@AlexanderPetrov 所說,具有一種方法的接口可以用作功能接口,允許我們在指定功能接口類型的地方“即時”創建函數:

//the interface
interface Runnable {
    void run()
}

//where it's specified
void execute(Runnable runnable) {
    runnable.run();
}

//specifying argument using lambda
execute(() -> /* code here */);

這不能用abstract class來完成。 所以你不能互換使用它們。 區別在於客戶端如何使用它的限制,這是由 JVM 的語義強制執行的。

至於資源使用的差異,除非它導致您的軟件問題,否則無需擔心。 使用內存管理語言的想法是不要擔心這些事情,除非您遇到問題。 不要預先優化,我確定差異可以忽略不計。 即使存在差異,也只有它是否可能導致您的軟件出現問題才重要。

如果您的軟件存在資源問題,請分析您的應用程序。 如果它確實導致內存問題,您將能夠看到它,以及每個人消耗了多少資源。 在此之前,您不必擔心。 您應該更喜歡使代碼更易於管理的功能,而不是消耗最少資源的功能。

JVM 內部結構和內存表示 JVM幾乎相同。 我的陳述基於第 4 章 - 類文件格式 從附帶的文檔中可以看出, JVM通過access_flags區分了類和接口。 如果你一個方法只有一個方法的簡單抽象類的簡單接口。 此格式中的大多數字段將相同(空),主要區別在於 access_flags。

默認構造函數生成抽象類正如@Holger 所指出的,Interface 和 Abstract 類之間的另一個小區別是普通類需要一個構造函數。 Java 編譯器將為Abstract 類生成一個默認構造函數,該構造函數將為它的每個子類調用。 從這個意義上說,與接口相比,抽象類定義會稍微大一些。

https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    u2             access_flags;
    u2             this_class;
    u2             super_class;
    u2             interfaces_count;
    u2             interfaces[interfaces_count];
    u2             fields_count;
    field_info     fields[fields_count];
    u2             methods_count;
    method_info    methods[methods_count];
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

除了接口的多重繼承,還有一個不同點就是Java8中只有一個方法的抽象類不是Functional interface

 @FunctionalInterface
 public interface SimpleFuncInterface {
      public void doWork();
 }

 execute(SimpleFuncInterface function) {
      function.doWork();
 }

 execute(()->System.out.printline("Did work"));

同樣不能用抽象類來實現。

接口 - 缺乏“對擴展的開放性”。 高達 Java 8 的接口因其缺乏可擴展性而受到批評。 如果更改接口契約,則需要重構接口的所有客戶端。

想到的一個例子是用於 Hadoop 的 Java MapReduce API,它在 0.20.0 版本中進行了更改,以支持抽象類而不是接口,因為它們更容易發展。 這意味着,可以將新方法添加到抽象類(具有默認實現),而不會破壞類的舊實現。

隨着Java 8 Interface Default 方法的引入,這種缺乏可擴展性的問題已經得到解決。

public interface MyInterface {
 int method1();
 // default method, providing default implementation
 default String displayGreeting(){
  return "Hello from MyInterface";
 }
}

使用 Java 8 可以將新方法添加到接口和抽象類中,而不會破壞客戶端類的約定。 http://netjs.blogspot.bg/2015/05/interface-default-methods-in-java-8.html

它們在實現上是不同的

  • 你只能擴展一個抽象類
  • 另一方面,您可以同時實現多個接口
  • 您需要實現接口中存在的所有方法
  • 對於抽象,它可能會提供一些默認實現,因此您是想再次實現它還是只使用默認實現是獨立的

如果您談論性能,那么前一段時間有人認為接口比抽象類慢。 但是現在 JIT 對它們沒有任何區別。

請參閱此答案以獲取更多詳細信息。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM