[英]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
}
當interface
或abstract 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.