Argomenti finali nei metodi di interfaccia: qual è il punto?


189

In Java, è perfettamente legale definire finalargomenti nei metodi di interfaccia e non obbedire a ciò nella classe di implementazione, ad esempio:

public interface Foo {
    public void foo(int bar, final int baz);
}

public class FooImpl implements Foo {

    @Override
    public void foo(final int bar, int baz) {
        ...
    }
}

Nell'esempio sopra bare bazha le finaldefinizioni opposte nella classe VS l'interfaccia.

Allo stesso modo, nessuna finallimitazione viene applicata quando un metodo di classe ne estende un altro, abstracto meno.

Mentre finalha qualche valore pratico all'interno del corpo del metodo di classe, c'è qualche punto che specifica i finalparametri del metodo di interfaccia?


finalcomunque non fa nulla con i tipi nativi, poiché sono copiati.
Paul Tomblin,

11
Proprio come punto di discussione: l'ho appena provato e se due interfacedefinizioni variano solo finalnell'attributo di un argomento, i .classfile risultanti sono identici byte per byte (e ovviamente javap -vproducono lo stesso output). Lo stesso vale per due classi che differiscono solo finalper un attributo, tra l'altro!
Joachim Sauer,

2
@Paul: fa esattamente la stessa cosa dei tipi di riferimento: impedisce che gli argomenti stessi vengano modificati (se usati nell'implementazione).
Joachim Sauer,

Ha la stessa rilevanza del pubblico nella firma del metodo.
Robin,

2
@Deepak: ti vedo chiedere esempi di lavoro su tutti i tipi di domande, anche quando non sembra avere molto senso. Penso che dovresti provare ad imparare un po 'di pensiero astratto: prova a pensare a un problema senza avere un codice eseguibile di fronte a te. Ti aiuterà molto a lungo termine.
Joachim Sauer,

Risposte:


104

Non sembra che ci sia alcun motivo. Secondo la specifica del linguaggio Java 4.12.4 :

Dichiarare un finale variabile può servire come utile documentazione che il suo valore non cambierà e può aiutare a evitare errori di programmazione.

Tuttavia, un finalmodificatore su un parametro di metodo non è menzionato nelle regole per la corrispondenza delle firme dei metodi sostituiti e non ha alcun effetto sul chiamante, solo all'interno del corpo di un'implementazione. Inoltre, come notato da Robin in un commento, il finalmodificatore su un parametro di metodo non ha alcun effetto sul codice byte generato. (Questo non è vero per altri usi di final.)


Il parametro del metodo si qualifica anche come variabile? Ovviamente è in pratica, ma è nel contesto delle specifiche?
mindas,

11
Non può essere utilizzato per abbinare le firme poiché non viene visualizzato nel file .class effettivo. È solo per il compilatore.
Robin,

@mindas - JLS afferma che esistono sette tipi di variabili . I parametri del metodo sono al quarto posto nell'elenco.
Ted Hopp,

3
La documentazione è quasi inutile, tuttavia, poiché il finalmodificatore non viene applicato sulla classe di implementazione. La firma della tua interfaccia potrebbe semplicemente mentire.
Stefan Haberl,

Le specifiche del linguaggio Java 8 ora dicono che ci sono otto tipi di variabili (rispetto a sette - hanno aggiunto parametri lambda ). I parametri del metodo sono ancora al quarto posto nell'elenco (almeno alcune cose nella vita sembrano stabili. :-)).
Ted Hopp,

25

Alcuni IDE copieranno la firma del metodo astratto / interfaccia quando si inserisce un metodo di implementazione in una sottoclasse.

Non credo che faccia differenza per il compilatore.

EDIT: Anche se credo che questo fosse vero in passato, non credo che gli IDE attuali lo facciano più.


2
Punto valido, anche se non credo che ci fossero molti IDE quando questa funzionalità è stata implementata (o lasciata per errore) :-)
mindas

2
Penso che sia nella categoria dei static transientcampi. ;)
Peter Lawrey,

1
E costruttori pubblici su una classe astratta.
Peter Lawrey,

1
IntelliJ fa questo. La mia versione è IntelliJ IDEA 2016.1.3 Build # IU-145.1617.
Ghiro

1
@Dormouse, è interessante, perché Android Studio (3.1.4 Build # AI-173.4907809) non lo fa :(
Il Padrino,

18

Le annotazioni finali dei parametri del metodo sono sempre rilevanti solo per l'implementazione del metodo mai per il chiamante. Pertanto, non esiste alcun motivo reale per utilizzarli nelle firme del metodo di interfaccia. A meno che non si desideri seguire lo stesso standard di codifica coerente, che richiede i parametri del metodo finale, in tutte le firme del metodo. Quindi è bello poterlo fare.


6

Aggiornamento: la risposta originale di seguito è stata scritta senza comprendere appieno la domanda e pertanto non affronta direttamente la domanda. :)Tuttavia, deve essere informativo per coloro che desiderano comprendere l'uso generale della finalparola chiave.

Per quanto riguarda la domanda, vorrei citare il mio commento dal basso.

Credo che non sei costretto ad attuare la finalità di un argomento per lasciarti libero di decidere se dovrebbe essere definitivo o meno nella tua implementazione.

Ma sì, sembra piuttosto strano che tu possa dichiararlo finalnell'interfaccia, ma averlo non definitivo nell'implementazione. Avrebbe avuto più senso se uno dei due:

un. finalparola chiave non consentita per gli argomenti del metodo di interfaccia (astratto) (ma è possibile utilizzarlo nell'implementazione) oppure
b. dichiarare un argomento come finalnell'interfaccia lo costringerebbe ad essere dichiarato finalin attuazione (ma non forzato per le non finali).


Posso pensare a due motivi per cui una firma del metodo può avere finalparametri: Beans and Objects ( In realtà, sono entrambi la stessa ragione, ma contesti leggermente diversi ) .

Oggetti:

public static void main(String[] args) {
    StringBuilder cookingPot = new StringBuilder("Water ");
    addVegetables(cookingPot);
    addChicken(cookingPot);
    System.out.println(cookingPot.toString());
    // ^--- OUTPUT IS: Water Carrot Broccoli Chicken ChickenBroth 
    //      We forgot to add cauliflower. It went into the wrong pot.
}

private static void addVegetables(StringBuilder cookingPot) {
    cookingPot.append("Carrot ");
    cookingPot.append("Broccoli ");
    cookingPot = new StringBuilder(cookingPot.toString());
    //   ^--- Assignment allowed...
    cookingPot.append("Cauliflower ");
}

private static void addChicken(final StringBuilder cookingPot) {
    cookingPot.append("Chicken ");
    //cookingPot = new StringBuilder(cookingPot.toString());
    //     ^---- COMPILATION ERROR! It is final.
    cookingPot.append("ChickenBroth ");
}

La finalparola chiave ha assicurato che non avremmo creato accidentalmente una nuova pentola locale mostrando un errore di compilazione quando abbiamo tentato di farlo. Ciò ha assicurato che il brodo di pollo fosse aggiunto alla nostra pentola originale addChickenottenuta con il metodo. Paragonalo a quello in addVegetablescui abbiamo perso il cavolfiore perché lo ha aggiunto a una nuova pentola locale invece della pentola originale che ha ottenuto.

Fagioli: è lo stesso concetto degli oggetti (come mostrato sopra) . I fagioli sono essenzialmente Objectdi Java. Tuttavia, i bean (JavaBeans) vengono utilizzati in varie applicazioni come modo conveniente per archiviare e trasferire una raccolta definita di dati correlati. Proprio come addVegetablespotrebbe rovinare il processo di cottura creando una nuova pentola StringBuildere gettandola via con il cavolfiore, potrebbe anche fare lo stesso con una pentola JavaBean .


Ok. Non è davvero una risposta corretta alla domanda, (dal momento che non sono costretto a fare in modo che la mia implementazione del metodo dell'interfaccia prenda gli argomenti finali, anche se l'interfaccia lo dice), ma è comunque utile, in quanto è una bella spiegazione del perché rendere definitivi i parametri del metodo è una buona idea per cominciare.
Phil

Credo che non sei costretto ad attuare la finalità di un argomento per lasciarti libero di decidere se dovrebbe essere definitivo o meno nella tua implementazione. Ma sì, sembra piuttosto strano che tu possa dichiararlo finalnell'interfaccia, ma averlo non definitivo nell'implementazione. Sarebbe stato più sensato se una (a) final parola chiave non fosse consentita per gli argomenti del metodo (astratto) dell'interfaccia (ma è possibile utilizzarla nell'implementazione), oppure (b) dichiarare un argomento come finalnell'interfaccia forzerebbe la sua dichiarazione finalnell'implementazione (ma non forzato per le non finali).
ADTC,

"Non è proprio una risposta corretta alla domanda" Hai ragione, non so cosa stavo pensando ... devono essere state le prime ore di luglio o qualcosa del genere. :)
ADTC,

2

Credo che possa essere un dettaglio superfluo, dato che è definitivo o meno un dettaglio di implementazione.

(Un po 'come dichiarare metodi / membri in un'interfaccia come pubblica.)

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.