Protetto nelle interfacce


111

Perché tutti i metodi in una interfacedefinizione sono implicitamente public? Perché non consente un protectedmetodo?


22
Domanda molto buona. Per quasi ogni altra cosa in Java ho trovato una vera ragione per le scelte fatte, ma per questa non l'ho fatto. Per me ha perfettamente senso definire un metodo protetto in un'interfaccia che consenta a un'altra classe all'interno dello stesso pacchetto di utilizzare questo metodo su un oggetto di implementazione senza richiedere di esporre quel metodo, che potrebbe non essere pensato per essere chiamato da nessun altro oltre al membri del pacchetto, al resto del mondo.
Markus A.

4
@MarkusA. Ma le interfacce funzionano in due direzioni, cioè possono essere implementate anche da classi esterne al pacchetto corrente (e quindi magari passate come argomenti ai metodi all'interno di questo pacchetto). In che modo una classe esterna al pacchetto corrente sarebbe in grado di implementare metodi "protetti" di qualche interfaccia pubblica?
MartinStettner

8
@ MartinStettner: non lo sarebbe. Questo sarebbe il punto. Un pacchetto potrebbe avere più classi non correlate che implementano un'interfaccia e desidera garantire a qualsiasi codice che riceve un riferimento di quel tipo di interfaccia che si comporterà in un certo modo. Tale garanzia potrebbe essere resa molto più forte se si potesse impedire al codice esterno di affermare di implementare l'interfaccia mentre si comporta in modo contrario al suo contratto.
supercat

1
@MarkusA. hai sollevato un buon punto, dovresti essere in grado di raggiungerlo con il sistema di moduli di Java 9
Nir Alfasi

1
se l'interfaccia ha un protectedmetodo, tutta la classe di implementazione sarà vista come un sottotipo dell'interfaccia. e tutte queste classi POSSONO accedere a metodi protetti. non rende protectedinutile la parola chiave sul metodo? fintanto che non abbiamo alcun modo per limitare chi implementa questa parola chiave protetta dall'interfaccia sul metodo è inutile. correggimi se sbaglio!
amarnath harish

Risposte:


67

Perché un'interfaccia dovrebbe significare "ciò che puoi vedere dall'esterno della classe". Non avrebbe senso aggiungere metodi non pubblici.


16
Ma perché non avere funzioni che solo i membri dello stesso pacchetto dell'interfaccia "possono vedere dall'esterno della classe"? Ho avuto diversi casi d'uso in cui lo desideravo.
Markus A.

5
@MarkusA. Mi rendo conto che è tardi, ma poi puoi fare un completo abstract class, che è tutto ciò interfaceche sono, e specificare qualsiasi accesso desideri. Certo, ciò perde il vantaggio di più implementazioni interfaceottenute in Java, ma stabilire onestamente un contratto che aderisca alle limitazioni di qualche altro pacchetto sarebbe non verificabile e confuso, poiché non saresti praticamente in grado di accedere al metodo della tua implementazione al di fuori di quel pacchetto .
pickypg

10
@pickypg Ma se la classe che implementerebbe l'interfaccia estende già un'altra classe, non puoi farla estendere un'altra classe. Non lo troverei confuso per un'interfaccia utilizzata solo all'interno di un pacchetto.
Flamma

24
@Raveline, -1, Questo pone la domanda "perché un'interfaccia dovrebbe significare ciò che puoi vedere dall'esterno della classe?" Java 8 consente già il corpo del metodo nelle interfacce, quindi perché non consentire anche metodi astratti protetti?
Pacerier

8
Ho letto spesso questa spiegazione, ma IMHO è sbagliata. Un'interfaccia è una sorta di "protocollo di scambio standard", non importa se si parla di OOP, API di comunicazione o hardware. La porta USB del mio PC è chiaramente un'interfaccia pubblica. Ma i pin sulla mia scheda madre, che si trova dietro una custodia con chiusura a chiave, che forniscono l'accesso alle porte USB opzionali sono chiaramente un'interfaccia "protetta". Poi abbiamo il chip BIOS, che è anche un'interfaccia standardizzata, ma non è mai stata resa pubblica in alcun modo, solo poche aziende conoscono i dettagli esatti in privato. Quindi, ovviamente, le interfacce possono avere qualsiasi visibilità! Perché non in OOP?
Foo Bar

55

Sebbene la ragione spesso citata sia che "le interfacce definiscono le API pubbliche", penso che sia una semplificazione eccessiva. (E "odora" anche di logica circolare.)

Non sarebbe privo di significato avere interfacce che hanno una combinazione di modificatori di accesso; ad esempio, in parte pubblico e in parte limitato ad altre classi nello stesso pacchetto dell'interfaccia. In effetti, in alcuni casi questo potrebbe essere utile in basso a destra, IMO.

In realtà, penso che la parte del ragionamento che sta dietro a rendere i membri di un'interfaccia implicitamente pubblici sia che rende il linguaggio Java più semplice :

  • I membri dell'interfaccia implicitamente pubblica sono più semplici da gestire per i programmatori. Quante volte hai visto codice (classi) in cui i modificatori di accesso al metodo sono stati scelti apparentemente a caso? Molti programmatori "normali" hanno difficoltà a capire come gestire al meglio i confini di astrazione Java 1 . L'aggiunta di public / protected / package-private alle interfacce rende le cose ancora più difficili.

  • I membri dell'interfaccia implicitamente pubblica semplificano la specifica del linguaggio ... e quindi l'attività per gli autori di compilatori Java e le persone che implementano le API di Reflection.

La linea di pensiero che "le interfacce definiscono le API pubbliche" è probabilmente una conseguenza (o caratteristica) della decisione di progettazione del linguaggio semplificante ... non il contrario. Ma in realtà, le due linee di pensiero si sono sviluppate probabilmente in parallelo nella mente dei progettisti Java.

In ogni caso, la risposta ufficiale alla RFE in JDK-8179193 chiarisce che il team di progettazione Java ha deciso 2 che consentire le protectedinterfacce aggiunge complessità con pochi vantaggi reali. Complimenti a @skomisa per aver trovato le prove .

Le prove nella RFE risolvono la questione. Questo è il motivo ufficiale per cui non è stato aggiunto.


1 - Naturalmente, i migliori programmatori non hanno difficoltà con queste cose e potrebbero accogliere una gamma più ricca di funzioni di controllo degli accessi. Ma cosa succede quando il loro codice viene consegnato a qualcun altro per mantenerlo?

2 - Potresti non essere d'accordo con la loro decisione o il loro ragionamento dichiarato, ma questo è discutibile.


21

Devo dire che questa domanda è stata riaperta dall'introduzione di metodi predefiniti in Java 8. Il progetto su cui sto lavorando in questo momento è, simile alla natura di base di un'interfaccia, inteso ad astrarre l'intenzione dall'implementazione.

Ci sono diversi casi in cui potrei semplificare drasticamente il mio codice con un metodo "protetto di default". Si scopre che in realtà non funziona, poiché le interfacce si attaccano ancora alla logica di Java 7. Un normale metodo protetto non ha particolarmente senso, per i motivi sopra menzionati; ma se un metodo pubblico predefinito richiede una risorsa di basso livello che probabilmente non cambierà e può essere fornita da un metodo protetto, mi sembra che avere un lavoro "protetto per impostazione predefinita" non solo manterrebbe un codice più pulito, ma proteggerebbe gli utenti futuri da abusi accidentali.

(Questo tragicamente non cambia il fatto che devo ancora complicare eccessivamente il mio codice con abstract altrimenti non necessari; ma intendo inserire una richiesta di funzionalità in Oracle.)


Sono d'accordo al 100%. Le classi astratte erano una valida alternativa prima dell'introduzione dei metodi predefiniti. Tuttavia, le limitazioni che impongono all'ereditarietà multipla significano che non sono perfette. Le interfacce con metodi predefiniti sono normalmente un'alternativa migliore in un mondo> = JDK 1.8, ma poiché non possono memorizzare lo stato si basano sulla definizione di altri metodi astratti per esporre lo stato, il che significa che lo stato è reso pubblico, il che non è sempre ciò che tu vuoi.
Padre Jeremy Krieg

10

Perché le interfacce definiscono le API pubbliche. Tutto ciò che è protetto è un dettaglio interno che non appartiene a un'interfaccia.

È possibile utilizzare classi astratte con metodi astratti protetti, ma le interfacce sono limitate ai metodi pubblici e ai campi finali statici pubblici.


5
Hai affermato "perché le interfacce definiscono le API pubbliche". Allora qual è il motivo per cui le interfacce dovrebbero definire solo le publicAPI? C'è una differenza tra "dettaglio interno" e "dettaglio implementazione", protectedin Java non è sicuramente un dettaglio interno in quanto ora è un'interfaccia pubblica pubblicata a tutti coloro che possono sottoclassarlo, che è fondamentalmente il mondo intero.
Pacerier

1
Non è più vero con i metodi predefiniti di Java 8.
Mario Rossi

@MarioRossi E inoltre non è più vero con i metodi di interfaccia privata di Java 9.
skomisa

7

Forse perché è un'interfaccia , cioè è lì per dire ai clienti cosa possono fare con le istanze, piuttosto che per dire loro cosa non possono fare.


1
Non vedo perché un'interfaccia non possa dire anche alle sottoclassi cosa possono fare senza esporre tale implementazione al mondo esterno. Questa è stata una decisione progettuale che è stata presa in un momento in cui le classi astratte potevano essere utilizzate come alternativa perfetta. Ma con l'avvento dei metodi predefiniti nelle interfacce, le classi astratte sono ora un'alternativa imperfetta.
Padre Jeremy Krieg

6

Sono fermamente convinto che le interfacce dovrebbero consentire metodi protetti; chi ha detto che le interfacce devono essere visibili a tutti nel mondo intero? Quanto al tuo punto che potrebbe confondere i programmatori "ordinari" (leggi: incompetenti): gran parte dell'OOP riguarda la strutturazione corretta di oggetti, classi, pacchetti ecc., Se un programmatore ha difficoltà a fare tutto ciò correttamente, ha un problema molto più grande. Java è stato creato per quel tipo di cose.


Questo non risponde alla domanda.
Stephen C

5

Diverse risposte qui impiegano un ragionamento circolare per spiegare perché i metodi di interfaccia non possono essere protetti: è perché devono essere pubblici, quindi ovviamente non possono essere protetti!

Ciò non spiega nulla, ma fortunatamente qualcuno ha sollevato una richiesta di miglioramento per i metodi protetti nelle interfacce come un bug JDK un paio di anni fa, il che fa luce sul problema:

Metodi protetti nelle interfacce: condivisione tra pacchetti

Poiché i modificatori sono un po 'limitati in Java, un modo per condividere metodi tra i pacchetti è limitato ai metodi pubblici. A volte è pericoloso rendere pubblico un metodo, ma deve esserlo a causa della mancanza di modificatori adeguati. La mia soluzione supera questa limitazione.

La specifica del linguaggio Java attualmente non consente il modificatore protetto per i metodi di interfaccia. Possiamo trarre vantaggio da questo fatto e utilizzare metodi di interfaccia protetti per questa nuova funzionalità.

Se un metodo di interfaccia è contrassegnato come protetto e l'interfaccia è implementata da una classe in un altro pacchetto, il metodo non deve essere pubblico, ma potrebbe anche essere privato o almeno protetto da pacchetto. Il metodo è visibile, cosa mai la classe dichiara di essere e inoltre è visibile nel pacchetto sorgente dell'interfaccia (e sotto-pacchetti?).

In questo modo potremmo condividere alcuni metodi tra pacchetti ben noti.

E questa è la risposta a quella richiesta di miglioramento, che è stata chiusa con lo stato Won't fix:

Questa proposta tenta di risolvere un problema in un modo che aggiunge complessità e casi speciali per un guadagno effettivo minimo. Un modo tipico per risolvere questo problema è disporre di una classe privata che implementa un'interfaccia pubblica. I metodi di implementazione sono pubblici, ma sono all'interno di una classe privata, quindi rimangono privati.

Un'alternativa disponibile a partire da Java 9 consiste nel rendere pubblici classi e metodi, ma all'interno di un modulo che ha un'esportazione qualificata in moduli "amici" specifici invece di essere esportato al pubblico in generale.

Quindi le conclusioni autorevoli da quella segnalazione di bug sono:

  • La situazione attuale non cambierà; è improbabile che le interfacce supportino maiprotected metodi.
  • La giustificazione per non supportare i protectedmetodi nelle interfacce è che " aggiunge complessità e casi speciali per un guadagno effettivo minimo ".
  • A partire da Java 9 esiste un approccio alternativo per fornire accesso a livello di pacchetto ai metodi. Utilizzare il Java Platform Module System (JPMS) per " rendere pubbliche classi e metodi, ma all'interno di un modulo che ha un'esportazione qualificata in specifici moduli" amici "invece di essere esportati al pubblico in generale ".

4

Poiché una classe di implementazione deve implementare TUTTI i metodi dichiarati nella tua interfaccia, cosa accadrebbe se la tua classe di implementazione fosse in un pacchetto diverso?


2

Interfaccia Se vuoi usare qualcosa come hai descritto vai avanti con classi astratte o interfacce annidate.

Un estratto dallo stile del codice sulle variabili di interfaccia, ma si applica comunque ai metodi:

Le variabili di interfaccia sono implicitamente pubbliche perché le interfacce hanno lo scopo di fornire un'API (Application Programming Interface) completamente accessibile ai programmatori Java per fare riferimento e implementare nelle proprie applicazioni. Poiché un'interfaccia può essere utilizzata in pacchetti Java diversi dal proprio, la visibilità pubblica garantisce che il codice del programma possa accedere alla variabile.

2

La dichiarazione di sottointerfacce interne è una buona pratica, ma non è possibile dichiarare i metodi interni come protected in un'interfaccia in Java, tecnicamente.

Naturalmente, puoi creare un'altra interfaccia per uso interno che estende l'interfaccia pubblica:

package yourpackage;

public interface PublicInterface {

    public void doThing1();

    public void doThing2();

    public void doThing3();

}

package yourpackage;

interface InternalInterface extends PublicInterface {

    void doAnyInternalThing1();

    void doAnyInternalThing2();

}

Puoi usare l' InternalInterfaceinterfaccia all'interno del pacchetto, ma dovresti accettare qualsiasi sottotipo di PublicInterface(nei metodi pubblici):

package yourpackage;

public class SomeClass {

    public void someMethod(PublicInterface param) {
        if (param instanceof InternalInterface) {
            // run the optimized code
        } else {
            // run the general code
        }
    }

}

Al di fuori del pacchetto gli utenti possono utilizzare PublicInterfacesenza problemi.

Di solito i programmatori creano classi astratte in situazioni simili. Tuttavia, in questo caso perdiamo i vantaggi dell'ereditarietà multipla.


1
Al di fuori del pacchetto possono essere utilizzati YourPublicInterface.Internalanche gli utenti. Tutto in un'interfaccia, comprese le interfacce nidificate, è pubblico indipendentemente dalla presenza o dall'assenza della publicparola chiave.
Greg Roelofs

1

L'unico scenario in cui avrebbe senso è quando si desidera limitare la visibilità allo stesso pacchetto. Tutti gli altri usi di protectednon sono applicabili. In particolare, i protectedmetodi vengono spesso utilizzati per fornire l'accesso ad alcuni dettagli di implementazioni di livello inferiore per i discendenti. Ma dichiararlo in un'interfaccia non ha senso, poiché non esiste un'implementazione di livello inferiore da esporre.

E anche lo scenario del pacchetto non è proprio ciò di cui si occupano le interfacce.

Per ottenere ciò che probabilmente desideri, hai bisogno di due interfacce, una per uso interno e una che esponi nell'API pubblica. (Con quello interno forse, ma non necessariamente estendendo quello pubblico.) O, come altri hanno sottolineato, una superclasse astratta.


Una superclasse astratta può impedire a se stessa di essere derivata da tipi esterni al suo pacchetto. Qualcuno che riceve un riferimento di questo tipo di superclasse, che si fida dell'autore del pacchetto, può essere certo che l'oggetto si comporterà come dichiarato. Se un pacchetto ha più classi che vogliono esporre alcune funzionalità comuni, ma non si adattano a una gerarchia appropriata (ad esempio un implementa le funzioni X e Y, una Y e Z e una X e Z) sarebbe utile se potesse esporre la funzionalità che utilizza le interfacce pur promettendo che le istanze a cui fanno riferimento i tipi di interfaccia sarebbero "autentiche".
supercat

0

I metodi protetti sono sempre accessibili dalla sottoclasse solo se la sottoclasse estende la classe base.

In caso di interfaccia, la sottoclasse non estende mai l'interfaccia. Implementa l'interfaccia.

I metodi protetti sono accessibili tramite estensione e non con implement .


che differenza quale parola chiave, non importa.
Alex78191

0

Le interfacce hanno lo scopo di esporre i metodi al mondo esterno . Quindi questi metodi sono pubblici per natura. Tuttavia, se si desidera introdurre l' astrazione all'interno della stessa famiglia di classi , è possibile creare un altro livello di astrazione tra l'interfaccia e la classe di implementazione, ovvero una classe astratta. Di seguito è illustrato un esempio.

public interface MyInterface {
    public void publicMethod(); // needs to be public
}

public abstract class MyAbstractClass implements MyInterface {
    @Override
    public void publicMethod() {
        protectedMethod(); // you can call protected method here
        // do other stuff
    }
    protected abstract void protectedMethod(); // can be protected
}

public class MyClass extends MyAbstractClass {
    @Override
    protected void protectedMethod() {
        // implement protected method here, without exposing it as public
    }
}

2
Ma i metodi privati ​​che nessuno vedrà sono consentiti nelle interfacce.
Alex78191

java ha metodi predefiniti nelle interfacce, ovvero un'interfaccia è una stampella per bypassare l'ereditarietà multipla delle classi astratte. Lascia che sia consentita l'ereditarietà multipla di classi astratte. I conflitti tra i metodi predefiniti non sono diventati un problema.
Alex78191

Hai ragione. A partire da Java 9, i metodi privati ​​sono consentiti nelle interfacce. Questi non possono essere astratti e vengono implementati e utilizzati all'interno dell'interfaccia, principalmente da altri metodi predefiniti o statici (se sono essi stessi statici).
Stefanos Kargas

1
Questa risposta ignora semplicemente la domanda posta: perché le interfacce non possono avere metodi protetti? I metodi protetti continuerebbero a "esporre i metodi al mondo esterno" e l'affermazione che "questi metodi sono pubblici per natura" è semplicemente falsa. Sono pubblici perché il linguaggio è stato progettato in questo modo, ma avrebbe potuto consentire metodi protetti nelle interfacce. L'OP sta semplicemente chiedendo perché.
skomisa
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.