Pagina 1 di 1

[Java] Dubbio passaggio per riferimento

MessaggioInviato: 25 ago 2017, 17:08
da Patras
Ciao a tutti! Ho appena fatto un esercizio e mi sorge il dubbio riguardo al passaggio per riferimento in java.
Quando ho un oggetto per esempio del tipo Node (nodo di una lista) e faccio qualcosa del genere:
Codice: Seleziona tutto
static void metodo(LinkedList listOne)
{
   Node<T> s = new Node<T>();
   u = listOne.getFirst();
   getK( u ,...., s );
   String parola = s.getElement(); //contiene quella del decimo di ListOne??
}
static void <T> getK( Node<T> v,... , Node<T> nk )
{
   for(int i=0; i<10; i++)
      v=v.getNext();
   nk=v;
}

Ora s punta al decimo nodo della listOne? ciò nonostante il fatto di aver passato s come parametro?

Re: [Java] Dubbio passaggio per riferimento

MessaggioInviato: 25 ago 2017, 17:35
da AjeieBrazov
Gli oggetti vengono sempre passati come riferimenti.
Se non vuoi alterare un oggetto devi farne una copia.

Re: [Java] Dubbio passaggio per riferimento

MessaggioInviato: 25 ago 2017, 17:41
da Patras
quindi mi pare di capire che no, perché ora nk punta a v[10] ma s non punta a nk... s rimane quello di prima.

A sto punto mi chiedo ma non esiste davvero un modo per risolvere questo? Nel mio caso per esempio...
in C se non sbaglio basta mettere una & davanti al parametro...

Re: [Java] Dubbio passaggio per riferimento

MessaggioInviato: 25 ago 2017, 17:46
da AjeieBrazov
In Java l'oggetto "fisico" risiede nel heap, quello che viene assegnato alla variabile di tipo oggetto è sempre e solo il puntatore all'indirizzo del heap dove l'oggetto è memorizzato.
E' come se lavorassi in C usando (quasi) solo puntatori. Se passi un puntatore e modifichi la variabile da esso puntata la modifichi in modo permanente.
In Java solo i tipi primitivi vengono passati per valore.

Re: [Java] Dubbio passaggio per riferimento

MessaggioInviato: 25 ago 2017, 17:49
da rugweri
Java non permette il passaggio per riferimento: qualsiasi parametro Java è passato by value.

Precisamente: tutti gli oggetti in Java sono indicati tramite puntatori: se esegui l'istruzione

Codice: Seleziona tutto
String s = new String()


Crei un nuovo oggetto, e dichiari di voler usare l'identificatore s per riferirti a lui. Ora, se tu passi s come parametro alla funzione

Codice: Seleziona tutto
void change(String sl)
{
    String k = "Ciao";
    sl = k;
    return;
}


Quello che succede è che tu passi alla funzione un puntatore il cui valore è stato ricopiato in un altro puntatore. Ora, quando tu effettui l'assegnamento
Codice: Seleziona tutto
sl = k


Quello che stai facendo è sostanzialmente cambiare il valore del puntatore, ovvero stai dicendo al tuo programma "prendi il puntatore sl e mettici dentro il valore del puntatore k", ovvero ancora stai cambiando l'oggetto cui il tuo puntatore sl punta, ma non stai modificando assolutamente l'oggetto cui puntava prima.

Tutto chiaro? ;-)


Già che ci siamo: per convincerti di ciò che dico, prova ad eseguire questo codice:

Codice: Seleziona tutto
   public static void change(String ls)
   {
      String k = new String("Prova");
      
      System.out.println("INIZIO: ls = " + ls);
      
      ls = k;
      
      System.out.println("FINE: ls = " + ls);
      
      return;
   }
   
   public static void main(String args[])
   {
      String s;
      
      s = new String("Ciao");
      
      change(s);
      
      System.out.println("s = " + s);
   }

Re: [Java] Dubbio passaggio per riferimento

MessaggioInviato: 25 ago 2017, 18:18
da AjeieBrazov
Codice: Seleziona tutto
public class Persona {
  public String nome;
  public String cognome;
  public Persona(String nome, String cognome) {
    this.nome = nome;
    this.cognome = cognome;
  }
  @Override
  public String toString() {
    String s = "Nome: " + this.nome + "\nCognome: " + this.cognome;
    return s;
  }
}


Codice: Seleziona tutto
public class Prova {
  private static void cambia(Persona p) {
    p.cognome = "sempronio";
  }
  public static void main(String[] args) {
    Persona p = new Persona("tizio","caio");
    System.out.println(p);
    cambia(p);
    System.out.println(p);
  }
}


Output
Codice: Seleziona tutto
Nome: tizio
Cognome: caio
Nome: tizio
Cognome: sempronio


Magari è solo una questione di terminologia ma mi hanno insegnato che questo è un passaggio per riferimento, nel senso che non passi il valore dell'oggetto ma il riferimento all'oggetto.

Re: [Java] Dubbio passaggio per riferimento

MessaggioInviato: 25 ago 2017, 18:37
da Patras
Grazie mille siete stati chiarissimi :ok:

Re: [Java] Dubbio passaggio per riferimento

MessaggioInviato: 25 ago 2017, 18:50
da rugweri
Purtroppo la differenza è sottile e non viene mai spiegata bene, perché tutti i docenti di informatica passano mesi a mostrare listati infiniti e imbottire gli studenti di frammenti di codice già pronti ma nessuno perde un paio di giorni a spiegare cosa davvero vogliano dire le righe di codice...

La parola d'ordine è evaluation strategy, ovvero "come e quando i linguaggi valutano i parametri di una funzione".
Senza dilungarci troppo, ci sono linguaggi (come C o Java) che valutano i parametri sempre e soltanto by value, ovvero (semplificando all'estremo) assegnano il valore dei parametri a delle variabili locali della funzione chiamata; in sostanza, quando tu passi un puntatore ad una funzione C, per il compilatore tu non stai passando un riferimento ad una variabile, bensì stai passando il valore di un puntatore (tra l'altro, in C il puntatore a dato è un tipo a sè stante... ma non divaghiamo).
Altri linguaggi, come se ben ricordo il C# e FORTRAN, permettono invece (anzi, siamo precisi: C# permette, FORTRAN impone) il passaggio by reference, ovvero (sempre semplificando all'estremo) effettuano il passaggio di parametri fornendo alla funzione un riferimento alla specifica locazione di memoria in cui risiede il dato usato come parametro al momento della chiamata.
[Ci sono anche altre strategie di valutazione, ma non le tratto per non perdere tempo]

Come avrai intuito, certi linguaggi che usano il passaggio per valore possono "simulare" il passaggio per riferimento (il C lo fa con il passaggio dei puntatori, ad esempio), e per il programmatore quadratico medio più o meno il risultato è equivalente ad un vero e proprio passaggio by value... ma non è così: i compilatori sono progettati in modo tale da analizzare ed ottimizzare il codice secondo le specifiche del linguaggio, per cui è possibile che la simulazione di un passaggio by reference sia meno efficiente di un vero passaggio by reference, o addirittura la simulazione potrebbe risultare (a me non è mai capitato, ma in linea di principio è possibile) in qualche errore che il compilatore potrebbe non rilevare correttamente.

Re: [Java] Dubbio passaggio per riferimento

MessaggioInviato: 25 ago 2017, 22:57
da Patras
Grazie mille per la dettagliata descrzione
rugweri ha scritto:Come avrai intuito, certi linguaggi che usano il passaggio per valore possono "simulare" il passaggio per riferimento (il C lo fa con il passaggio dei puntatori, ad esempio)

Si ma credevo che riuscissero a renderla molto veloce ottimizzando magari i codici del livello più basso (tipo assembly). Grazie per avermi avvisato.

Infatti per la mia esperienza da studente posso dirti che hai perfettamente ragione. Continuavano a dirci che il passaggio è "per riferimento" parlando degli oggetti, discorso che stava in piedi fino a un certo punto quando arrivi ai parametri del metodo dove bisogna approfondire un attimo. Leggendo anche su qualche sito internazionale trovavo "passed by value, but the value is a reference" che mi ha confuso di nuovo.
Comunque ora ho capito tutto grazie alle vostre spiegazioni. :ok:

Re: [Java] Dubbio passaggio per riferimento

MessaggioInviato: 25 ago 2017, 23:03
da AjeieBrazov
Mi permetto un suggerimento: hai occasione di studiare il Java, quindi studialo bene. Adoro il Java perché è, a mio avviso (e qui mi tirerò dietro le ire di molti) è semplicemente una genialata.
Per lavoro programmo (quasi) sempre in C ma quando ho la necessità di scrivere una utilty che giri su PC uso il Java, e mi diverto tantissimo (non ostante i 30 e più anni di codice scritto per lavoro). ;-)