2016-03-03 68 views
5

在這裏是表示我的問題的簡化示例:必須實現默認的接口方法嗎?

import java.util.List; 

public interface SingleTask extends List<Runnable>, Runnable { 
    default Runnable get(final int x) { 
     if (x != 0) { 
      throw new IndexOutOfBoundsException(); 
     } 
     return this; 
    } 

    default int size() { 
     return 1; 
    } 
} 

import java.util.AbstractList; 

public class MyTask extends AbstractList<Runnable> implements SingleTask { 
    @Override 
    public void run() { 
     System.out.println("hello"); 
    } 
} 

SingleTask我的方法getsize,它們是從AbstractList唯一抽象方法的實現。然而,當我編譯MyTask,我還是得到這樣的錯誤:

The type MyTask must implement the inherited abstract method AbstractCollection.size()

MyTask.java:3: error: MyTask is not abstract and does not override abstract method get(int) in AbstractList

(取決於編譯器)。我,當然,用java 8

所以我有兩個問題:

  1. 爲什麼會出現這些錯誤?我期待它識別默認實現。
  2. 如果不應該這樣工作,那麼在不復制整個代碼的情況下在MyTask中使用這兩種方法的最簡單方法是什麼?
+1

不要讓你的任務擴展'List '(這意味着什麼意思,語義無論如何?),而是創建一個接口'任務'與'公共列表 getRunnables();'方法。否則,只需將SingleTask作爲抽象類而不是接口即可。 – biziclop

+1

值得注意的是Eclipse沒有實現'size()',這可能是Eclipse的一個bug。 'javac' 1.8.0_51扼殺了'get(int)'沒有被執行,它是正確的:它沒有被實現。 – Tunaki

+0

@biziclop它應該是一個任務清單; SingleTask是一個單例實現 – aditsu

回答

6

強制SingleTask實現者,也能實現的List所有方法是不是很優雅,但並不意味着默認方法可以用來定義特質樣的實體,你的SingleTask界面的樣子。

爲什麼默認方法作爲特性是一個壞主意有幾個原因,最明顯的是任何實現者都可以簡單地覆蓋默認方法,破壞你的特質。

而這正是這裏發生了什麼:因爲AbstractList顯式聲明get()size()abstract,這意味着SingleTask將繼承他們,而不是你可能有一個超接口的默認實現。

JLS 8.4.8

A class C inherits from its direct superclass and direct superinterfaces all abstract and default (§9.4) methods m for which all of the following are true:

...

  • No concrete method inherited by C from its direct superclass has a signature that is a subsignature of the signature of m.

軸承都考慮到這一點最簡單的解決方案可能是這樣的:

public abstract class SingleTask extends AbstractList<Runnable> implements Runnable { 
    @Override 
    public final Runnable get(final int x) { 
     if (x != 0) { 
      throw new IndexOutOfBoundsException(); 
     } 
     return this; 
    } 

    @Override 
    public final int size() { 
     return 1; 
    } 

    @Override 
    public abstract void run(); 
} 

其缺點是,你的任務必須擴展SingleTask,因此不能延長別的什麼,在正面,儘管他們不需要處理也是List的任務,但他們只需要實現run()

但是從長遠來看,我寧願將構造視爲繼承,而只是簡單地返回可運行列表的列表,而不是其自身。

+0

我並不強迫SingleTask實現者也擴展AbstractList,但它看起來像你。此外,你讓SingleTask成爲一個類,這意味着如果我想使用它,我不能擴展一個不同的類。而且你甚至沒有試圖回答我的第一個問題。 – aditsu

+1

@aditsu'我並沒有強迫SingleTask實現者擴展AbstractList'是的,你確實是這樣,這就是導致問題的原因。我會編輯我的答案以涵蓋這一點。 – biziclop

+0

錯誤,用我的代碼,SingleTask實現者只需要實現List的方法。 SingleTask中沒有關於AbstractList的內容! – aditsu

2
  1. Why am I getting these errors? I was expecting it to recognize the default implementations.

我認爲@biziclop正確覆蓋了his answer。總之,由於AbstractListget(int)size()方法聲明爲抽象方法,因此這些方法優先於SingleTask中的默認實現。

  1. If it's not supposed to work like that, then what's the simplest way to use those two methods in MyTask without copying the whole code?

最簡單的將是覆蓋MyTaskget(int)size()方法,讓他們委託給您的默認方法SingleTask接口:

public class MyTask extends AbstractList<Runnable> implements SingleTask { 

    @Override 
    public void run() { 
     System.out.println("hello"); 
    } 

    @Override 
    public Runnable get(int index) { 
     return SingleTask.super.get(index); 
    } 

    @Override 
    public int size() { 
     return SingleTask.super.size(); 
    } 
} 

通過這種方法,你會是怎樣委託的SingleTask的默認方法。我不認爲這是一件壞事(至少,你不需要使用屬性)。此外,編寫這些方法是有意義的,以便您可以選擇提供默認實現的接口。

相關問題