Referenz Frage

Migu

Mitglied
Hallo

Ich bin gerade am Versuche zu verstehen wie Referenzen in Java funktionieren, und je mehr ich darüber lese desto verwirrter bin ich.
Ich habe mir mal ein Minimalbeispiel:

Java:
import java.awt.Point;

public class Test {
    public static void add(Point p) {
        p.x++;
    }
    
    public static void add(Integer i) {
        i++;
    }
    
    public static void main(String[] args) {
        
        Point q = new Point(5, 5);
        System.out.println("q.x = " + q.x);
        add(q);
        System.out.println("q.x = " + q.x);
        
        Integer myInt = new Integer(10);
        System.out.println(myInt.intValue());
        add(myInt);
        System.out.println(myInt.intValue());

    }
}

So nun ist die Ausgabe
q.x = 5
q.x = 6
10
10

warum?
Ich hätte erwartet dass das Point-Object in der main-Funktion unverändert bleibt, also sowie bei Integer. Kann mir jemand erklären warum das so passiert?
Soweit ich weiss wird beim erzeugen eines Objects (zB q) eigentlich, unter der Haube einen Pointer definiert der auf den Speicherplatz zeigt. Also wie in C++
Code:
Point *q
.
Das würde aber wiederrum heissen das nur der Wert (der Pointer) an die Funktion übergeben wird, also call-by-value...

Ich checks nicht!

Danke im voraus
Migu
 
Vielleicht hilft dir folgender Beitrag bei deinem Verständnis Problem:
http://www.java-forum.org/allgemeines/4904-call-value-call-reference.html

Das kann man aber auch sehr viel einfacher formulieren 🙂 Immer wenn du eine Zuweisung auf einen Parameter machst, arbeitest du in der Methode auf einem neuen Objekt und der Caller kriegt nichts davon mit.
Statt mit [c]Integer[/c] hier ein Beispiel mit [c]int[/c]:
Java:
public static void add(int i) {
    i++;
}
Ausformuliert heisst das sowas:
Java:
public static void add(int i) {
    i = i + 1;
}
Der Code für Integer kann ausformuliert etwa so lauten:
Java:
public static void add(Integer i) {
    i = Integer.valueOf(i.intValue() + 1);
}
Wie du siehst, haben wir hier ebenfalls eine Zuweisung. Das betrifft alle Objekte, welche immutable sind. Das sind z.B. die Wrapperklassen (Integer, Float) und natürlich String.
 
Zusammengefasst: die Pointer aus C/C++ gibt´s erstmal in JAVA nicht, das, was dem am nächsten kommt, sind die Referenzen. Soweit erstmal richtig.
Das würde aber wiederrum heissen das nur der Wert (der Pointer) an die Funktion übergeben wird, also call-by-value...
Das stimmt aber nicht mehr. Wenn du an eine Funktion einen Pointer übergibst, ist deine Funktion call-By-Reference, denn du sagst damit der Methode, an welcher Stelle im Speicher die Variable steht und damit wie man sie verändern kann. Mit Referenzen (In JAVA, nicht zu verwechseln mit Referenzen in C/C++) ist es ähnlich, du übergibst eine Referenz AUF das Objekt und sagst somit, wie dieses verändert werden kann.

Noch kürzer: Call-By-Value gibt´s in JAVA nur für primitive Datentypen wie
Code:
int
und
Code:
double
.
Code:
String
und
Code:
Integer
(nicht int!) sind immutables (unveränderlich), die sind also ein bisschen außen vor. Objekte sind in JAVA immer Call-By-Reference.
 
Hab dir mal was zusammen geschrieben:


Diese Beispiel zeigt in Java Call by Value.
Dies bedeutet, dass eine in der main Methode festgelegte Variable, in diesem Fall:
x= 5, an die Methode doSomething(int x) übergeben wird.

Der Parameter könnte auch ein String sein, wenn man in der main-Methode einen String
erstellen würde und diesen übergeben möchte.


Java:
public class CallBy {

  public static void main(String[] args) {
	int x = 5;
		   
	// die variable x wird kopiert und somit nicht durch die methode verändert
		   
	//CallBy test = new CallBy();
		   
	// immer noch 5
	 System.out.println(x);
		   
	doSomething(x);	  
	}

// Der in der Main-Methode festgelegte Wert von x wird der Methode übergeben(Call-by-Value)

	public static void doSomething(int x) {

	 System.out.println(x = x+1);

	}
}



Wie bereits erwähnt könnte man nun noch einen String ändern, der Parameter ist als int
nur ein Beispiel. Somit müsste das Programm so aussehen:


Java:
public class CallBy {

	public static void main(String[] args){


		   
		   String s= "Hallo";
		   
		// s noch "Hallo"
		   System.out.println(s);

		// s nun: "Hallo, wie gehts?"
		   changeString(s);

		}

		
		public static void changeString(String s){
			System.out.println(s + " ,wie gehts?");
		}
}


Hoffe, du verstehst das Prinzip jetzt.

Gruß
 
mhm das Bsp zeigt nicht wirklich das Problem.

du erzeugst einen neuen String, dass der nicht der selbe wie s ist, das ist logisch.

ausserdem machst du nur was in den Methoden, es waere an sich interessant zu sehen, was nach dem Methodenaufruf mit der jeweiligen Variable geschieht.
 
Nach dem Methodenaufruf haben die Variablen wieder den ursprünglichen Wert?
Oder was meinst..?

gut eig. müsste es so aussehen..

Java:
public static void changeString(String s){
			System.out.println(s= s + " ,wie gehts?");
		}
 
EnHancEd[];865059 hat gesagt.:
Nach dem Methodenaufruf haben die Variablen wieder den ursprünglichen Wert?
Oder was meinst..?

gut eig. müsste es so aussehen..

Java:
public static void changeString(String s){
			System.out.println(s= s + " ,wie gehts?");
		}


Die Variable s aus deiner Main wurde nicht in der Methode angefasst. Es wurde eine Copy erstellt von s und mit der wird in der Methode gearbeitet. Daher ist die Aussage mit ursprünglichen Wert nicht korrekt.
 
Es geht ja auch drum, dass eine Kopie erstellt wird.

Nimm eben das Beispiel wenn dir das andere nicht gefällt:

Java:
class ArrayAendern
{
  void ausgeben ( int[] x )
  {
    for ( int j=0; j < x.length; j++ )
      System.out.print( x[j] + " " );
    System.out.println( );
  }

  void setElementZero ( int[] x, int index )      // 6.
  {
    if ( index < x.length )                       // 7.
      x[ index ] = 0;                             // 8.
  }
}



class ArrayAendernTest
{
  public static void main ( String[] args )       // 1.
  {
    ArrayAendern arrAendern = new ArrayAendern(); // 2.
    int[] arr = {27, 19, 34, 5, 12} ;             // 3.
    System.out.println( "Vorher:" );              // 4.
    arrAendern.ausgeben( arr );

    arrAendern.setElementZero( arr, 0 );          // 5.
    System.out.println( "Nachher:" );             // 9.
    arrAendern.ausgeben( arr );
  }
}

Erläuterung der Schritte:

1) Das Programm beginnt mit der static main() Methode zu starten.
2) Ein ArrayAendern-Objekt wird konstruiert.
3) Das int[]-Objekt arr wird konstruiert und initialisiert.
4) Die in arr enthaltenen Werte werden ausgegeben.
5) Vorher: 27 19 34 5 12 wird ausgegeben
6) Die setElementZero() Methode wird mit den Parametern arr und 0 aufgerufen.
7) Eine Referenz auf das Array arr wird in den Parameter x kopiert und 0 wird in den Parameter index kopiert.
8) Die setElementZero() Methode überprüft, ob das gewünschte Element (hier 0) existiert
9) Element 0 des Arrays wird auf 0 gesetzt.
10) Die jetzt in arr enthaltenen Werte werden ausgegeben.
11) Nachher: 0 19 34 5 12 wird ausgegeben
 
Ja danke erstmal für euren Input.
Aber je mehr man liest desto verwirrter ist man... Im Internet steht es mal so, mal so.

Aber so wie ich das aus obigen Beiträgen verstehen konnte gibt es doch call-by-reference für Objekte, jedoch nur wenn sie keine Integer oder String oder eine der primitiven Datentypen sind.

Ist das so korrekt??

Den Beitrag vor mir, habe ich ähnlich mit einem Vektor ausprobiert

Java:
import java.util.Vector;

public class Test {
    
    public static void setToZero(Vector<Integer> vec) {
        for ( int i=0; i<vec.size(); i++ ) {
            vec.set(i, 0);
        }
    }
    
    public static void main(String[] args) {
        
        Vector<Integer> vec = new Vector<>();
        vec.add(5); 
        vec.add(155); 
        vec.add(41);
        for(Integer i : vec) {
            System.out.println(i);
        }
        setToZero(vec);
        for(Integer i : vec) {
            System.out.println(i);
        }
    }
}

Ausgabe ist
0
0
0

Es funktioniert also.

Was aber passiert bei Java intern wenn man so eine Referenz an eine Funktion übergibt??
Werden die Werte aus deren Speicherort kopiert und geändert oder ist das eher ein Vorgang wie bei einem Pointer in C/C++?

Migu
 
Java erstellt eine Kopie des Zeigers. Du hast also zwei unterschiedliche Referenzen, die aber auf das selbe Objekt zeigen.
 

Zurück
Oben