2016-07-20 49 views
6

我只是好奇,如果他們對待任何不同。正常的接口類和只有抽象方法的抽象類是否有區別?

例如,如果我們有:

接口:

public interface Test { 
    public void method(); 
} 

與抽象類:

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

請問JVM對待這些類有什麼不同?哪兩個在存儲期間佔用更多的磁盤空間,哪一個將耗盡最多的運行時間內存哪一個執行更多的操作(執行更好的)。

這個問題不是關於何時使用接口或抽象類。

+0

這個問題只是問關於類的內存表示還是更廣泛的問題關於抽象類和接口之間的區別? –

+0

@AlexanderPetrov我知道這兩個類之間的區別。顯然,如果你需要使用上面列出的兩個之一,你將使用第一個。我只是問,如果我需要更多的存儲空間,會稍微快一點或者在運行時使用更少的內存等。 –

+0

@VinceEmigh謝謝我忘記了一些事情,如果我不使用IDE。 –

回答

5

是的,它們是不同的。

有了一個接口,客戶端可以實現它藏漢作爲擴展類:

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的語義強制實施。

至於資源使用方面的差異,不要擔心,除非它導致您的軟件問題使用內存管理語言的想法是不擔心這種事情,除非你有問題。不要預先優化,我敢肯定,差異是可以忽略的。即使存在差異,只要它可能導致您的軟件出現問題就應該重要。

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

+1

我的想法,但我不認爲這必然回答他問的問題。他問JVM如何看待這兩個。 – Vucko

+0

@Vucko他實際上是在問「*** JVM會不會對這些類有不同的看法?***」而不是「***虛擬機如何在引擎蓋下對待它們?***」。他可能沒有字節碼的經驗,只是想知道它們是否可以互換。我回答「他們是不同的」,並提到他們工作方式的不同(需要不同的語義)。他應該在他的回答中澄清他是否想知道* VM如何處理它,因爲目前這個問題沒有表達這個問題。 –

+0

@Vucko這是一個我不知道的區別。我以爲在java中你只能實現一個類。 –

6

JVM內部結構和內存表示 它對於JVM幾乎是一樣的。我的聲明基於第4章 - 類文件格式。從附加文檔可以看出,JVM正在使類和接口之間的差異爲,由access_flags。如果你有一個簡單的接口只是一種方法和一個簡單的抽象類只是一種方法。這種格式的大多數字段將是相同的(空),主要區別是access_flags。

默認構造代抽象類 作爲@Holger指出的那樣,接口和抽象類之間的另一個小的區別是,普通類需要一個構造。 Java編譯器將爲抽象類生成默認構造函數,該類將爲其每個子類調用。從這個意義上講,抽象類的定義會比接口略大。

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只有一個方法抽象類是不是一個功能接口

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

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

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

抽象類不能實現。

接口 - 缺乏「擴展的開放性」。 高達Java 8接口因缺乏可擴展性而受到批評。如果您更改界面合同,則需要重構界面的所有客戶端。浮現在腦海

一個例子是Hadoop的,這 在0.20.0版本改變了 接口青睞抽象類,因爲它們更容易演變的Java的MapReduce API。這意味着,可以將新方法 添加到抽象類(使用默認實現),而不使用 則破壞類的舊實現。

通過引入的Java 8接口的缺省方法 這種缺乏可擴展性已得到解決的。

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

+0

我不確定以前的Java版本(和Java 8的改進)中的「*接口可擴展性*缺乏」與題。你對我的回答非常嚴厲,偏離了這個觀點(事實並非如此,你只是清楚地表明你對這個問題的解釋是最重要的),但是你會包括一些不相關的信息,儘管這些信息與界面,與手頭的問題有*無關。先生,你用虛僞的虛僞讓我心生疑慮。 –

1

如果你談論性能,那麼前一段時間有人認爲接口比抽象類慢。但是現在JIT在它們之間沒有區別。

請參閱this answer瞭解更多詳情。