2010-06-10 16 views
9

Ho un'interfaccia e voglio che chiunque implementa questa interfaccia implementi un metodo "uguale" sovrascritto.Applicare "uguale" in un'interfaccia

C'è un modo per assicurarsi che ciò accada?

Il modo in cui penso che questo accadrà è che la classe che implementa la mia interfaccia otterrà automaticamente gli uguali da Object, rendendo l'interfaccia felice.

+1

Qual è il tuo fondamento logico per questo? –

+0

Il caso specifico in cui mi sono imbattuto quando è sorto questo problema; Ho un'interfaccia che implementa diverse classi. Queste classi sono identificate da un identificatore univoco. Quindi se due identificatori erano uguali, gli oggetti dovrebbero essere considerati uguali. A un certo punto avevo una lista di una di quelle classi e volevo sapere se un nuovo oggetto esisteva già nella lista. Ho pensato che sarebbe stato elegante usare List.contains (..) per questo controllo. Ma ciò richiederebbe che potessi essere certo che l'uguaglianza fosse superata. Facile da risolvere in altri modi però. Anche una classe astratta avrebbe funzionato bene. – Fredrik

risposta

10

No, è solo possibile creare una classe astratta invece di un'interfaccia come questa:

public abstract class MyApi { 

    public final boolean equals(Object other) { 
    if (other == this) { 
     return true; 
    } 
    if (other instanceof MyApi) { 
     return equals((MyApi)other); 
    } 
    return false; 
    } 

    protected abstract boolean equals(MyApi other); 

} 

o una versione più semplice:

public abstract class MyApi { 

    public boolean equals(Object other) { 
    throw new UnsupportedOperationException("equals() not overridden: " + getClass()); 
    } 

} 

EDIT (dato una prova dopo il commento da @CodeConfident, grazie! Mai supposto che avrebbe funzionato):

Si può anche semplicemente dichiarare equals() in un Classe stract (! non in un'interfaccia) e quindi nascondere l'attuazione Object e applicare una nuova implementazione in ogni sottoclasse:

public abstract class MyApi { 

    public abstract boolean equals(Object obj); 

    public abstract int hashCode(); 

} 

In ogni caso si dovrebbe sempre implementare equals() e hashCode() insieme per adempiere al contratto.

+0

Se si sta sostenendo l'uso di una classe astratta, perché non dichiarare uguale (oggetto) come astratto? – ILMTitan

+2

@ilmtitan: non è possibile dichiarare un metodo astratto che è ereditato! –

+0

@ArneBurmeister - Questo non è vero (almeno adesso). È assolutamente possibile sovrascrivere un metodo ereditato con un metodo astratto all'interno di una classe astratta. Vedi questa risposta: https://stackoverflow.com/questions/1718112/tostring-equals-and-hashcode-in-an-interface#answer-1718170 – AjahnCharles

3

No. È possibile aggiungerlo all'interfaccia (e quindi ai javadoc), ma se Object.equals ha la stessa firma, non è possibile fare in modo che il compilatore li sovrascriva.

1

Modifica: Probabilmente non è una buona idea (vedere il commento di FarmBoy). Lasciando qui per i posteri.

Invece di utilizzare equals(Object obj) dalla classe Object, falli confrontare con un'implementazione dell'interfaccia.

public interface MyInterface { 
    public boolean equals(MyInterface mi); 
} 

Pertanto,

public class MyImplementation implements MyInterface { 
    public boolean equals(MyInterface mi) 
    { 
    if(this == mi) 
     return true; 
    // for example, let's say that each implementation 
    // is like a snowflake...(or something) 
    return false; 
    } 
} 

E poi:

public class Main { 

    public static void main(String[] args) 
    { 
    Object o = new MyImplementation(); 
    MyImplementation mi1 = new MyImplementation(); 
    MyImplementation mi2 = new MyImplementation(); 

    // uses Object.equals(Object) 
    o.equals(mi1); 
    // uses MyImplementation.equals(MyInterface) 
    mi1.equals(mi2); 
    // uses Object.equals(Object) 
    mi2.equals(o); 
    } 
} 
+2

Questa non è una buona idea. Qualsiasi cosa che chiami equivale (come mettere un oggetto in un 'Set' non chiamerà questo uguale, ma quello 'reale'. Quindi dovresti forzare la classe di implementazione ad implementare questo metodo, e qualsiasi buon programmatore implementerebbe quello 'reale' –

+0

Un buon punto: non ci avevo pensato, mi piacerebbe avere maggiori dettagli da chi ci chiede e dalla motivazione alla base di questa domanda. – Catchwa

0

Credo che ci possono essere due motivi per cui tale carattere di uguale metodo potrebbe essere necessario

  1. Volete per garantire che tutte le classi in la tua app (o un suo sottoinsieme) "avrà" il metodo di uguaglianza. Qualcosa come l'applicazione degli standard, o assicurarti che alcune delle API che utilizzi funzionino come dovrebbero (e si aspettano che i tuoi pari siano implementati correttamente. Supponiamo che tu utilizzi Maps parecchio e vuoi essere assolutamente sicuro che un sottoinsieme di classi sia sicuramente possibile chiavi) Se questo è il caso, questa non è la strada da percorrere. In questo caso non sarai in grado di farlo, ma anche se lo sei, non sarebbe corretto. Dovresti usare gli strumenti di copertura del codice e testare meglio le unità.

  2. Non si desidera il metodo equals, ma si desidera un metodo simile. In questo caso è possibile creare un altro metodo con un nome simile nell'interfaccia.

3

No. Un'interfaccia è un contratto che garantisca metodi esiste.

Non esiste alcun meccanismo per applicare i metodi che devono essere sovrascritti in un'interfaccia.

0

Ho sperimentato con la scrittura del contratto richiesto per equals nel JavaDoc. Tuttavia, il requisito che hashCode sia coerente con equals genera un contratto molto complesso per hashCode. Quindi ho rinunciato e ho creato una classe base astratta con un'implementazione final dei due metodi.