Dove è specificato che Java è chiamata per valore?

4

So che Java è per impostazione predefinita per valore, ma non sono sicuro di dove sia Java Language Specification questo è indirizzato. La ricerca Google sembra solo trovarmi fonti non ufficiali, ma non indica mai dove si trova la parte effettiva della specifica che descrive questo.

Dove nel JLS si afferma che Java è call-by-value e in che modo quella parte della specifica dice effettivamente che è call-by-value piuttosto che qualche altra convenzione?

    
posta Tim Atkinson 27.11.2014 - 15:09
fonte

2 risposte

5

Sorgente definitiva per Java

Come i commenti hanno già indicato, c'è solo una specifica ufficiale per il linguaggio Java, ovvero Specifiche della lingua Java rese disponibili da Oracle.

La risposta alla tua particolare domanda sul comportamento di chiamata si trova in sezione 8.4.1 :

When the method or constructor is invoked (§15.12), the values of the actual argument expressions initialize newly created parameter variables

Fonte della confusione

Si noti, tuttavia, che le persone che scrivono il JLS potrebbero non condividere la stessa definizione di termini degli altri. In particolare, la discussione sul fatto che Java sia chiamata per valore o qualcos'altro deriva in genere dall'analisi di altre definizioni.

Call-by-value viene in genere definito come il passaggio di una copia dell'argomento alla funzione. Questo comportamento è più esposto in C ++, dove puoi scegliere se vuoi chiamare per valore o chiamare per riferimento per argomento e per chiamare per valore hai anche cose come costruttori di copie.

Questa idea generale, che call-by-reference ti permette di cambiare l'oggetto originale, mentre call-by-value lo lascia intatto è un po 'inutile in Java (almeno se ignori i tipi primitivi). A differenza della famiglia di linguaggi C, Java non ha alcun concetto di puntatore a qualche oggetto, quindi ogni singola variabile è come un puntatore a qualche oggetto. Questo dà l'impressione alle persone che hanno familiarità con C, che Java fa sempre passare dei riferimenti (dopotutto, se si passa un oggetto in una funzione, non si sa se quella funzione modifica gli attributi interni dell'oggetto).

Puoi argomentare contro questo argomento accettando la nozione di puntatori, che a sua volta significa, che una chiamata di funzione sta ancora usando call-by-value, perché crea semplicemente una copia di quel puntatore, che finirà per puntare a lo stesso oggetto di nuovo.

La cosa più confusa è che passare un oggetto a un metodo in Java non creerà mai una copia completa (profonda !?) di quell'oggetto, nonostante il fatto che Java sia chiamata per valore. Altri linguaggi (come C ++) chiamano la loro funzione chiamando anche la chiamata alla semantica, ma in quelle lingue la semantica effettiva è diversa.

Esempi di codice

Supponi di avere i seguenti due metodi nella tua classe:

private void f(C c) { 
  c.setSomething(); 
  c = new C(); 
  c.setSomething2();
}
private void g(final C c) { 
  c.setSomething();  
}

Ora sul sito di chiamata trovi qualcosa del genere:

C myC = // get some C instance
f(myC); // passes the value

Il metodo f ora modificherà gli attributi dell'oggetto myC , perché funziona esattamente sulla stessa istanza. Al contrario, la variabile c può essere assegnata a un'istanza diversa, in modo tale che la chiamata a setSomething2 non influenzi l'istanza a cui myC si riferisce.

Se si scambia f per g sul sito di chiamata, un tipico errore di rookie dai programmatori C / C ++ che è diventato programmatore Java è supporre che final in qualche modo garantisce che l'oggetto non venga modificato. Naturalmente, il codice sopra funziona ancora e modifica l'oggetto. Ciò che non funziona più a causa di final è semplicemente, che la variabile c viene nuovamente assegnata a un'istanza C diversa all'interno di quel metodo.

Questo comportamento attira anche gli sviluppatori Java più esperti. Mentre pochi dimenticano che un argomento final List<C> è autorizzato a modificare la lista, non così pochi incorrere in bug, dopo aver scritto un metodo che restituisce un List<C> (sia definitivo che non, in quanto ciò non fa alcuna differenza rilevante) e viene morso dal codice del sito di utilizzo che lo modifica.

    
risposta data 28.11.2014 - 07:46
fonte
1

Pass-by-value / pass-by-reference è una proprietà della semantica della lingua. Non spetta a qualcuno "specificare" indipendentemente dalle specifiche della lingua; piuttosto, deriva da come funziona la semantica del linguaggio (che nel caso di Java è specificata nel JLS). Se lo standard linguistico in realtà descrive la semantica pass-by-value, ma il creatore del linguaggio "specifica" la lingua da passare per riferimento, ciò non lo rende pass-per-riferimento.

In primo luogo, è necessario concordare su cosa significa pass-by-value / pass-by-reference. La definizione di uso comune è che se si esegue un'assegnazione semplice (utilizzando = ) a un parametro all'interno di una funzione e ha lo stesso effetto dell'assegnazione semplice alla variabile passata nell'ambito di chiamata, si tratta di un riferimento pass-by ; se non ha alcun effetto nell'ambito della chiamata, è pass-by-value.

In Java, le variabili di parametro sono variabili appena create per quella chiamata di metodo e inizializzate con copie del valore passato. Inoltre, l'assegnazione in Java modifica solo quella variabile, e non possibilmente alcuna altra variabile. Queste cose combinate si adattano alla definizione di pass-by-value.

    
risposta data 05.12.2014 - 01:20
fonte

Leggi altre domande sui tag