2016-03-03 21 views
5

Hier ist ein vereinfachtes Beispiel mein Problem zeigt:Muss Standard-Interface-Methode implementieren?

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

In SingleTask I bieten Implementierungen für die Methoden get und size, die die einzigen abstrakten Methoden von AbstractList sind. Allerdings, wenn ich kompilieren MyTask, bekomme ich immer noch Fehler wie:

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

oder

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

(je nach Compiler). Ich bin natürlich, java 8.

Also ich habe zwei Fragen:

  1. Warum erhalte ich diese Fehler zu bekommen? Ich habe erwartet, dass es die Standardimplementierungen erkennt.
  2. Wenn es nicht so funktionieren soll, was ist der einfachste Weg, diese beiden Methoden in MyTask zu verwenden, ohne den gesamten Code zu kopieren?
+1

Lassen Sie Ihre Aufgaben nicht erweitern 'List ' (was bedeutet das eigentlich semantisch?), Sondern erstellen Sie eine Schnittstelle 'Task' mit einer' public List getRunnables(); 'Methode. Wenn Sie das nicht machen, machen Sie 'SingleTask' einfach eine abstrakte Klasse anstelle einer Schnittstelle. – biziclop

+1

Bemerkenswert ist, dass Eclipse auf der 'size()' erstickt ist nicht implementiert: Dies ist wahrscheinlich ein Eclipse-Fehler. 'javac' 1.8.0_51 erstickt an' get (int) 'wird nicht implementiert und es ist richtig: es ist nicht implementiert. – Tunaki

+0

@biziclop es sollte eine Liste von Aufgaben sein; SingleTask ist eine Singleton-Implementierung – aditsu

Antwort

6

Erzwingen SingleTask Implementierer auch alle Methoden der List zu implementieren ist nicht sehr elegant, und Standard-Methoden nicht bestimmt sind, verwendet werden Charakterzug ähnlichen Einheiten zu definieren, die Ihre SingleTask Schnittstelle aussieht.

Es gibt mehrere Gründe, warum Standardmethoden-wie-Eigenschaften eine schlechte Idee ist, die offensichtlichste ist, dass jeder Implementierer einfach Ihre Standardmethode überschreiben kann, ruinieren Sie Ihre Eigenschaft.

Und das ist genau das, was hier geschieht: Da AbstractList ausdrücklich get() und size() als abstract erklärt, es bedeutet SingleTask wird sie erben, anstatt die Standardimplementierungen Sie in einem Superschnitt gehabt haben können.

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.

alles, was die einfachste Lösung Bedenkt man wohl diese:

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

Sein Nachteil ist, dass Sie Ihre Aufgaben SingleTask und damit nichts anderes verlängern verlängern müssen, auf der Plusseite, obwohl sie nicht mit der Aufgabe beschäftigen müssen auch ein List, sie müssen nur implementieren run().

Auf lange Sicht würde ich jedoch Komposition über Vererbung bevorzugen, und Aufgaben einfach eine Liste von Runnables zurückgeben, anstatt sie selbst zu sein.

+0

Ich war nicht gezwungen, SingleTask-Implementierungen zu erweitern, auch abstraktList, aber es sieht so aus als ob Sie sind. Außerdem haben Sie SingleTask zu einer Klasse gemacht, was bedeutet, dass ich keine andere Klasse erweitern kann, wenn ich diese verwenden möchte. Und du hast nicht einmal versucht, meine erste Frage zu beantworten. – aditsu

+1

@aditsu 'Ich zwang die SingleTask-Implementierer nicht dazu, auch AbstractList zu erweitern. Ja, das tust du, und genau das verursacht die Probleme. Ich werde meine Antwort bearbeiten, um auch das zu erfassen. – biziclop

+0

Falsch, mit meinem Code müssen SingleTask-Implementierer nur die Methoden von List implementieren. Es gibt nichts in SingleTask über AbstractList! – aditsu

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

Ich denke, @biziclop korrekt abgedeckt in his answer. Kurz gesagt, da AbstractList die Methoden get(int) und size() als abstrakt deklariert, haben diese Vorrang vor Ihren Standardimplementierungen in 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?

Die einfachste get(int) und size() Methoden in MyTask, außer Kraft zu setzen wäre, so dass sie in SingleTask Schnittstelle zu Ihren Standard-Methoden delegieren:

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

Mit diesem Ansatz würden Sie Art von delegierenden seine zu Ihren Standardmethoden in SingleTask. Ich denke nicht, dass dies eine schlechte Sache ist (zumindest müssen Sie kein Attribut verwenden). Außerdem ist es sinnvoll, diese Methoden zu schreiben, damit Sie auswählen können, welche Schnittstelle die Standardimplementierungen bereitstellt.

Verwandte Themen