Kleine Verständisfrage: Werden bei Java Funktionsparameter als Referenz oder Kopie übergeben?



  • Ich habe da grad einen Hänger. Unser Prof. gibt uns diesen Quelltext:

    public static void swap( int[] feld, int i, int j)
      {
        int temp = feld[ i];
        feld[ i] = feld[ j];
        feld[ j] = temp;
      }
    

    Und Sie meinte, dass dies 2 Zahlen vertauscht. Nur das geht ja nur, wenn die Parameter als Referenz, also Zeiger übergeben werden.

    Unter diesem Link steht ganz unten unter "Call by Reference gibt es in Java nicht – ein Blick auf C und C++", dass es in Java kein Call by Reference gibt.

    Also wie schauts hier nun aus? Parameterübergabe mittels Call by Ref. oder Val.?

    Grüße



  • e86 schrieb:

    Ich habe da grad einen Hänger. Unser Prof. gibt uns diesen Quelltext:

    public static void swap( int[] feld, int i, int j)
      {
        int temp = feld[ i];
        feld[ i] = feld[ j];
        feld[ j] = temp;
      }
    

    Und Sie meinte, dass dies 2 Zahlen vertauscht. Nur das geht ja nur, wenn die Parameter als Referenz, also Zeiger übergeben werden.

    Unter diesem Link steht ganz unten unter "Call by Reference gibt es in Java nicht – ein Blick auf C und C++", dass es in Java kein Call by Reference gibt.

    Also wie schauts hier nun aus? Parameterübergabe mittels Call by Ref. oder Val.?

    Grüße

    Arrays sind in Java Objekte. Wenn Du mit

    int[] zahlen = new int[7];
    

    ein neues Arrayobjekt erzeugst, dann ist die Variabel "zahlen" eine Referenz auf das Arrayobjekt das mit "new int[7]" erzeugt wird. "new" ruft dabei den Konstruktor auf.



  • Nachtrag bezüglich des Links:

    Es ist richtig das in Java "Call By Value" übergeben wird. Der Text ist richtig. Primitive Werte werden bei der Übergabe kopiert, bei den oben genanten Objektreferenzen verhält sich das genau so. Eine Objektreferenzvariabel wird bei der Übergabe an die Funktion kopiert, ist somit nur lokal in der Funktion gültig.

    Dies wird ja auch an dem Beispiel

    static void clear( Point p ) 
    { 
      p = new Point(); 
    }
    

    deutlich. Der Objektreferenz "p" wird nur in der Funktion ein neuer Wert zugewiesen.Der Wert in der aufrufenden Funktion bleibt aber gleich.



  • Ok, also bei:

    public static void swap( int[] feld, int i, int j)
    {
        int temp = feld[ i];
        feld[ i] = feld[ j];
        feld[ j] = temp;
    }
    

    findet nur eine Vertauschung innerhalb der Funktion statt.

    Ein Aufruf der Funktion ähnlich

    swap (i,j);
    

    vertauscht die Werte von i und j also nicht.



  • e86 schrieb:

    Ok, also bei:

    public static void swap( int[] feld, int i, int j)
    {
        int temp = feld[ i];
        feld[ i] = feld[ j];
        feld[ j] = temp;
    }
    

    findet nur eine Vertauschung innerhalb der Funktion statt.

    Ein Aufruf der Funktion ähnlich

    swap (i,j);
    

    vertauscht die Werte von i und j also nicht.

    Doch. Denn die übergebene (kopierte) Referenz auf das int-Array ist ja nicht Gegenstand der Manipulation, sondern das int-Array-Objekt selbst.

    Der aufgerufenen Funktion wird in der Argementliste mit "int[] feld" eine Kopie der Referenz der aufrufenden Funktion auf das Arrayobjekt auf dem Heap übergeben. Das Arrayobjekt selbst gibt es nur ein mal und wird in der aufrufenden Funktion und in der aufgerufenen Funktion jeweils durch eine EIGENE, lokale Referenz referenziert. Du übergibst mit

    public static void swap( int[] feld, int i, int j)
    

    ja nicht das Array selbst.



  • Aber warum man das dann nicht "Call by Reference" nennt weiß ich auch nicht genau. Richtig, es werden Objektreferenzen als Kopie übergeben, also aus Sicht der übrgebenen Referenz ist es "Call by Value".

    Aber an sich ist es ja nicht so viel anders in C wenn ich einen Zeiger übergebe. Folgendes Beispiel:

    #include <stdio.h>
    #include <stdlib.h>
    
    void func(int *ptr) {
         int *ptr_local = NULL;
         ptr = ptr_local;
    
         printf("in func: ptr = %d \n", ptr);
    }
    
    int main() {
        int a = 10;
        int *ptr = &a;
    
        printf("in main: ptr = %d \n", ptr);
        func(ptr);
        printf("in main nach func(): ptr = %d \n\n", ptr);
        getchar();
        return EXIT_SUCCESS;
    }
    

    Hier gilt ja "Call by Reference", da ich statt einer Kopie der eigentlichen Variabel einen Zeiger auf "int a" übergebe. Allerdings wird auch der Zeiger bei der Übergabe an die aufgerufene Funktion kopiert, wie man unschwer an der Ausgabe erkennen kann. Das ist bei Java ja nicht viel anders, ausser das es da statt eines Zeigers eine Objektreferenzvariabel ist. Ist der Unterschied rein definitionsbezogen ?

    Oder ich bin jetzt auch schon zu müde...

    Vielen dank !



  • Ist der Unterschied rein definitionsbezogen ?

    Nein, es gibt einen kleinen aber feinen Unterschied, den "nochmal" schon erläutert hat. Wenn Du ein neues Objekt an die Referenz bindest, dann hat das keine Auswirkungen auf die ursprüngliche Referenz ausserhalb des Scopes, weil diese Referenz bei der Übergabe ja kopiert wurde. Du kannst also nur das Objekt manipulieren, das referenziert ist. Du kannst aber nicht implizit Referenzen ausserhalb des Scopes über den Parameter manipulieren.



  • byto schrieb:

    Nein, es gibt einen kleinen aber feinen Unterschied, den "nochmal" schon erläutert hat. Wenn Du ein neues Objekt an die Referenz bindest, dann hat das keine Auswirkungen auf die ursprüngliche Referenz ausserhalb des Scopes, weil diese Referenz bei der Übergabe ja kopiert wurde. Du kannst also nur das Objekt manipulieren, das referenziert ist. Du kannst aber nicht implizit Referenzen ausserhalb des Scopes über den Parameter manipulieren.

    Ja, richtig. Ich war im Übrigen auch "normal". Aber das ist bei Zeigern in C ja nichts anderes. Wenn ich eine Funktion aufrufe, und einen Zeiger als Argument übergebe, und dann dem Zeiger in der aufgerufenen Funktion eine neue Adresse zuweise hat das ja auch keine Auswirkung auf den Wert des Zeigers in der aufrufenden Funktion. Er zeigt immer noch auf dieselbe Adresse auf die er vorher gezeigt hat. Ich weiß allerdings nicht wie sich das in C++ verhält.



  • in c++ ist es auch so. man muss halt unterscheiden zwischen zeiger, zeiger auf zeiger und referenz auf zeiger



  • Ja richtig. Bei der Übergabe eines Zeigers auf einen Zeiger kann das tatsächlich schiefgehen, bei einem einfachen aber nicht.



  • DrStrangelove schrieb:

    Aber warum man das dann nicht "Call by Reference" nennt weiß ich auch nicht genau. Richtig, es werden Objektreferenzen als Kopie übergeben, also aus Sicht der übrgebenen Referenz ist es "Call by Value".

    Aber an sich ist es ja nicht so viel anders in C wenn ich einen Zeiger übergebe.

    Genau. Darum gibt es in C auch nur Call by Value. Erst mit C++ gibt es Call by Reference.

    Siehe auch
    http://ag-kastens.uni-paderborn.de/lehre/material/gps/folien/Folie607.html



  • Gut. Häufig wird nämlich in der Literatur eine Pointerübergabe in C als "Call by Reference" bezeichnet. Was ja im Grunde falsch ist.


Anmelden zum Antworten