2011-09-05 15 views
47

Vorrei sapere se esiste un modo in cui posso rendere obbligatorio per la classe implementatore dichiarare gli handle handle/primitives come fanno con i metodi. per es .:Attributi/variabili membro nelle interfacce?

public interface Rectangle {  
    int height = 0; 
    int width = 0; 

    public int getHeight(); 
    public int getWidth(); 
    public void setHeight(int height); 
    public void setWidth(int width);     
} 


public class Tile implements Rectangle{ 
    @Override 
    public int getHeight() { 
     return 0; 
    } 

    @Override 
    public int getWidth() { 
     return 0; 
    } 

    @Override 
    public void setHeight(int height) { 
    } 

    @Override 
    public void setWidth(int width) { 
    } 

} 

Nel metodo di cui sopra come possiamo costringere classe Tile per dichiarare attributi altezza e larghezza mediante l'interfaccia? Per qualche ragione, desidero farlo solo con l'interfaccia!

Inizialmente ho pensato di usarlo con l'ereditarietà. Ma la cosa è che devo affrontare con 3 classi.!

  1. rettangolo
  2. Tile
  3. JLabel.!

 

class Tile extends JLabel implements Rectangle {} 

avrebbe funzionato.!

ma

class Tile extends JLabel extends Rectangle {} 

non woud.!

+4

L'interfaccia non è corretta. Non può contenere attributi. Forse vuoi usare una lezione astratta? – pvoosten

+5

@lbp Che [verrà effettivamente compilato] (http://www.coderanch.com/t/178630/java-SCJA/certification/Instance-variables-interface) ;-) È solo ... non il "previsto" comportamento. Il compilatore assume/applica un modificatore 'statico finale '. –

+0

Potrebbe essere utile usare Altezza invece di Hieght e Hight. Hight è il participio passato di highten, hihten, chiamare, essere chiamato.;) –

risposta

52

Il punto di un'interfaccia è specificare l'API pubblica. Un'interfaccia non ha stato. Qualsiasi variabile che crei è davvero una costante (quindi fai attenzione a creare oggetti mutabili nelle interfacce).

Fondamentalmente un'interfaccia dice qui sono tutti i metodi che una classe che lo implementa deve supportare. Probabilmente sarebbe stato meglio se i creatori di Java non avessero permesso le costanti nelle interfacce, ma troppo tardi per sbarazzarsene ora (e ci sono alcuni casi in cui le costanti sono sensibili nelle interfacce).

Poiché si specifica solo quali metodi devono essere implementati, non vi è alcuna idea di stato (nessuna variabile di istanza). Se vuoi richiedere che ogni classe abbia una certa variabile, devi usare una classe astratta.

Infine, in generale, non si dovrebbero utilizzare variabili pubbliche, quindi l'idea di inserire le variabili in un'interfaccia è una cattiva idea.

Risposta breve: non è possibile fare ciò che si desidera perché è "sbagliato" in Java.

Edit:

class Tile 
    implements Rectangle 
{ 
    private int height; 
    private int width; 

    @Override 
    public int getHeight() { 
     return height; 
    } 

    @Override 
    public int getWidth() { 
     return width; 
    } 

    @Override 
    public void setHeight(int h) { 
     height = h; 
    } 

    @Override 
    public void setWidth(int w) { 
     width = w; 
    } 
} 

una versione alternativa sarebbe:

abstract class AbstractRectangle 
    implements Rectangle 
{ 
    private int height; 
    private int width; 

    @Override 
    public int getHeight() { 
     return height; 
    } 

    @Override 
    public int getWidth() { 
     return width; 
    } 

    @Override 
    public void setHeight(int h) { 
     height = h; 
    } 

    @Override 
    public void setWidth(int w) { 
     width = w; 
    } 
} 

class Tile 
    extends AbstractRectangle 
{ 
} 
+0

kk! quindi come faccio a farlo? (Ho modificato la domanda, controllo di pls)! – Shrey

+0

Questo aiuterà a supporre ..! thnxx :) – Shrey

+0

Ma questo lascia il problema che non si può incasinare con l'altezza nell'implementazione concreta. Quindi sai che hai bisogno di un'altezza, sai che devi essere in grado di tornare all'altezza, ma non puoi lasciarla a ogni implementazione per calcolare l'altezza (che penso sconfigga lo scopo). Ovviamente puoi dichiarare "getHeight' abstract e non dichiarare affatto l'altezza, ma poi devi ripetere il codice di ritorno ogni volta, solo così puoi mantenere la variabile privata. –

6

Le interfacce non possono richiedono le variabili di istanza da definire: solo metodi.

(Variables can be defined in interfaces, ma non si comportano come ci si poteva aspettare:. Sono trattati come final static)

Felice di codifica.

7

È possibile farlo solo con una classe astratta, non con un'interfaccia.

dichiarare Rectangle come abstract class invece di un interface e dichiarare i metodi che devono essere implementati dalla sottoclasse come public abstract. Quindi la classe Tile estende la classe Rectangle e deve implementare i metodi astratti da Rectangle.

+0

Inizialmente pensavo di usarlo con l'ereditarietà. Ma la cosa è che devo affrontare con 3 classi.! 1. Rettangolo 2. Piastrella 3. JLabel.! classe Tile estende JLabel implementa Rectangle {} funzionerebbe.! ma classe Tile extends JLabel extends Rectangle {} woud not.! – Shrey

2

In Java non è possibile. L'interfaccia ha a che fare con i metodi e la firma, non ha a che fare con lo stato interno di un oggetto - questa è una domanda di implementazione. E anche questo ha senso - voglio dire, semplicemente perché alcuni attributi esistono, non significa che debbano essere usati dalla classe di implementazione. getHeight potrebbe effettivamente puntare alla variabile width (assumendo che l'implementatore sia un sadico).

(Come nota - questo non è vero per tutti i linguaggi, ActionScript consente di dichiarazione di attributi pseudo, e credo che C# non troppo)

+1

In C# * i getter/setter * (che sono in realtà solo chiamate di metodo speciali) possono essere nelle interfacce - le variabili di istanza non possono. –

+0

Questo è quello che ho pensato (ed è per questo che ho detto pseudo) ActionScript fa la stessa cosa. – cwallenpoole

+0

kk !! l'ereditarietà invece dell'implementazione aiuterebbe.! Ma questo mi creerebbe un nuovo problema ..! mi puoi suggerire come procedere? (vedi la domanda modificata) thnx !! – Shrey

0

campi nelle interfacce sono implicitamente public static final. (Anche i metodi sono implicitamente pubblici, quindi è possibile eliminare la parola chiave public.) Anche se si utilizza una classe astratta anziché un'interfaccia, suggerisco fortemente di rendere tutto non costante (public static final di un riferimento oggetto primitivo o immutabile) private. Più in generale "preferisci la composizione all'ereditarietà" - uno Tile non-uno-Rectangle (ovviamente, puoi giocare ai giochi di parole con "è-a" e "ha-a").

+0

Shape of Tile is-a Rectangle .. ?? (is-a e has-a mi confonde di più) – Shrey

+0

Immagino che A dovrebbe estendere B se e solo se la risposta a 'è ogni B a A' è vera ..! leggi da Java efficace. – Shrey

+1

Come può B essere un A se A estende B? Hai di nuovo in avanti. – RichieHH

0

Qualcosa di importante è stato detto da Tom:

se si utilizza l'ha-un concetto, è evitare il problema

Infatti, se invece di usare estende e attrezzi si definiscono due attributi, uno di tipo rettangolare, uno di tipo JLabel nella classe Tile, allora si può definire una Rectangle ad essere sia un interfaccia o una classe.

Inoltre, normalmente incoraggerei l'uso di interfacce in connessione con l'has-a, ma suppongo che sarebbe un eccesso nella tua situazione. Tuttavia, sei l'unico in grado di decidere su questo punto (flessibilità del tradeoff/over-engineering).

4

Java 8 ha introdotto default methods per le interfacce mediante le quali è possibile eseguire il body sui metodi. Secondo le OOP, le interfacce dovrebbero fungere da contratto tra due sistemi/parti.

Ma ancora ho trovato un modo per ottenere la memorizzazione delle proprietà nell'interfaccia. Ammetto che è una brutta implementazione.

import java.util.Map; 
    import java.util.WeakHashMap; 

interface Rectangle 
{ 

class Storage 
{ 
    private static final Map<Rectangle, Integer> heightMap = new WeakHashMap<>(); 
    private static final Map<Rectangle, Integer> widthMap = new WeakHashMap<>(); 
} 

default public int getHeight() 
{ 
    return Storage.heightMap.get(this); 
} 

default public int getWidth() 
{ 
    return Storage.widthMap.get(this); 
} 

default public void setHeight(int height) 
{ 
    Storage.heightMap.put(this, height); 
} 

default public void setWidth(int width) 
{ 
    Storage.widthMap.put(this, width); 
} 
} 

Questa interfaccia è brutta. Per l'archiviazione di una proprietà semplice, erano necessari due hashmap e ogni hashmap crea automaticamente 16 voci per impostazione predefinita. Inoltre, quando l'oggetto reale è dereferenziato, JVM deve anche rimuovere questo riferimento debole.

+0

Abbastanza interessante ma strano :). Si può persino eliminare la classe interna e memorizzare semplicemente mappe finali statiche nell'interfaccia stessa. – iMysak

Problemi correlati