2016-05-21 11 views
2

Kommt aus Sprachen ohne einen GC (C/C++/Rust ..) Ich frage mich, was genau passiert, wenn ein Array neu zugeordnet wird.Was ist ein Referenzwert in Java und warum ändert er sich?

wenn wir in einer c sind ++ wie Sprache (Pseudo-Code), wird dies als schlecht:

Obj *x = xarr[2]; 
xarr.push(new Obj(12)); 
do_with(x); 

Beispiel in c läuft ++ http://ideone.com/qk7vcj

nach dem Stoß kann x aufgrund freigegebenen Speicher zeigen Umverteilung von Xarr.

x ist im Grunde genommen nur eine Zeigergröße, die die Speicheradresse von xarr [2] speichert.

wenn ich das gleiche in Java mache. Das funktioniert gut und ich frage mich warum?

was genau ist x und wie und warum wird die Speicheradresse von x geändert, nachdem das Array scheinbar neu zugeordnet wurde?

offensichtlich java ist nicht deepcopying das Array, weil x2 konnte nicht ändern X wie in diesem Code, wie Sie sehen können, ändert sich auch die Adresse von x.

private static class OBJ { 
    int one; 
    String two; 

    public OBJ() { 
     this.one = 1; 
     this.two = "two"; 
    } 
} 

public static void do_it(OBJ o) { 
    System.out.println("o.two is: " + o.two); 
} 

public static void main(String[] args) 
{ 

    List<OBJ> list = new ArrayList<>(); 
    list.add(new OBJ()); 
    list.add(new OBJ()); 
    list.add(new OBJ()); 

    OBJ x = list.get(2); 

    printAddresses("Address x", x); 

    for (int idx = 0; idx < 1000000; idx++) { 
     list.add(new OBJ());  
    } 

    OBJ x2 = list.get(2); 
    x2.two = "haha"; 

    printAddresses("Address x", x); 

    do_it(x); 

} 

soll nicht dieses

Address x: 0x525554440 
Address x: 0x550882b80 
o.two is: haha 

voll funktionierendes Beispiel gefunden werden kann http://ideone.com/P3j6xF

hier ausdrucken, so dass wirft die Frage auf, wie die Adresse von x nach der Neuverteilung der Liste geändert. Und was genau ist die sogenannte "Referenz"? Ich dachte, die so genannte "Referenz" in Java ist nur ein gewöhnlicher Zeiger mit etwas wie Autodeferenzierung und keine Zeigerarithmetik, weil in Java alles nach Wert und nicht nach Referenz weitergegeben wird. dies ist in diesem Code http://ideone.com/k4Ijq0

public static void test1(OBJ o) { 
    o.one = 2; 
} 

public static void test2(OBJ o) { 
    o = new OBJ(); 
    o.two = "no reference"; 
} 

public static void main (String[] args) throws java.lang.Exception 
{ 
    OBJ x = new OBJ(); 
    test1(x); 
    test2(x); 

    System.out.println("x.one: " + x.one + " x.two: " + x.two); 
} 

Ausdrucken

x.one: 2 x.two: two 

so scheint es klar ersichtlich, wie x ist wie ein Zeiger verhalten, aber irgendwie Java ist es bei Bedarf umgeleitet wird. Wie funktioniert das? Der Begriff "Referenz" ist besonders verwirrend, warum heißt es so?

+0

Auch, [Was ist der Unterschied zwischen einer Variablen, Objekt und Referenz?] (Http://stackoverflow.com/questions/32010172/what-is-the-difference-between-a-variable-object-and -Referenz) –

+0

@ Sotirios Delimanolis dies ist nicht wirklich mein Problem anzugehen. –

+0

Bitte klären Sie dann. Was meinst du mit _bend diese Referenz_? –

Antwort

1

Die Java Virtual Machine Specification Staaten

Es gibt drei Arten von Referenztypen: Klassentypen, Array-Typen, und Schnittstellentypen. Ihre Werte sind Verweise auf dynamisch erstellte Klasseninstanzen, Arrays oder Klasseninstanzen oder Arrays, die Schnittstellen implementieren.

ähnlich ist die Java Language Specification Staaten

Die Referenzwerte (oft nur Referenzen) sind Zeiger auf diese Objekte und eine spezielle Nullreferenz, das auf kein Objekt verweist.

Mit anderen Worten, Werte für Referenztypen sind (mehr oder weniger) die Adresse eines entsprechenden Objekts. Dies wird offensichtlich von Ihnen, dem Java-Entwickler, abstrahiert. Sie müssen nie wissen, wo sich ein Objekt im Speicher befindet, da Sie keinen Speicher verwalten. Die JVM macht das.

Wenn Sie das tun

OBJ x = new OBJ(); 

oder der Referenzwert auf eine andere Weise erhalten

OBJ x = list.get(2); 

Die Variable x einfach hält, dass Referenzwert, der dem eigentlichen Objekt verweist (oder möglicherweise die null Referenz).

Java ist eine Müll-Sprache. Modern garbage collection algorithms use generational and copying strategies. Das heißt, sie bewegen sich zwischen den Generationen zwischen Objekten, da sie entscheiden, wie langlebig diese Objekte sind. Dieser Schritt ist eine Kopie und klar. Der GC wird durch einen speziellen Bereich gehen, alle Live-Objekte in einen anderen Bereich kopieren und das Original als freien Speicher markieren.

Dies ist offensichtlich problematisch für unsere zuvor genannten x Variable. Wenn es auf ein Live-Objekt im Speicher zeigte und dieser Speicher "gelöscht" wurde, bereiten wir uns auf Probleme vor. Der GC muss daher alle Variablen (Instanzvariablen, lokale Variablen, Array-Elemente) durchgehen, die den Speicherort eines verschobenen Objekts gespeichert haben, und sie aktualisieren, bevor das Programm fortfahren kann (erledigt während der Stop The World-Sammlungen).

Dies ist, was Sie mit Ihrem Unsafe Code sehen.

OBJ x = list.get(2); 
printAddresses("Address x", x); 

Die Aufgabe wird durch den Wert in x ist in einer bestimmten Stelle im Speicher gespeichert verwiesen, wenn Sie zuerst printAddresses aufrufen. Nach dem Generieren einer Menge neuer Objekte, die den Garbage Collector auslösen, wird das Objekt an eine neue Position verschoben, und alle Referenzen darauf werden aktualisiert (der Wert in x, der Wert im zugrunde liegenden Array ArrayList). Wenn Sie mehr Speicher hätten (oder weniger Objekte erstellt hätten), wäre dies (noch) nicht erfolgt.

Wie funktioniert Array-Neuzuweisung in Java?

Dies hat wirklich nichts mit dem Array zu tun. Das ArrayList Objekt enthält ein Array-Feld (elementData benannt, die ein Array-Objekt verweist. Zum Beispiel

elementData = 0x4000 

und dieses Objekt, Intern hat Verweise auf andere Objekte (Array-Elemente Variablen sind).

elementData[0] = 0x6720 
elementData[1] = 0x6808 
elementData[2] = 0x4393 
elementData[3] = 0x7121 
elementData[4] = 0x2425 
elementData[5] = 0x4867 
elementData[6] = 0x976 
elementData[7] = 0x1082 
elementData[8] = 0x4160 
elementData[9] = 0x1850 

Wenn Sie dieses Elementlimit erreichen und ArrayList das Array neu zuordnen muss, kopiert es einfach alle Referenzwerte in ein neues Array.

elementData = 0x8900; 
elementData[0] = 0x6720 (same as above) 
elementData[1] = 0x6808 
elementData[2] = 0x4393 
elementData[3] = 0x7121 
elementData[4] = 0x2425 
elementData[5] = 0x4867 
elementData[6] = 0x976 
elementData[7] = 0x1082 
elementData[8] = 0x4160 
elementData[9] = 0x1850 
elementData[10] = 0x0000 (something for null) 
... 
elementData[newLength-1] = 0x0000 

vorausgesetzt, dass keines dieser Objekte während eines Speicherbereinigungszyklus verschoben wurde. Wenn sie hätten, hätte der GC auch die Array-Variablen aktualisiert.

Noch einmal, als Java-Entwickler sollten Sie sich um nichts kümmern. Es wird sehr selten praktisch sein, wenn Java-Code geschrieben wird. Sie haben nie direkten Zugriff auf den tatsächlichen Referenzwert (außer bei der Wiedergabe mit Unsafe).

0

Die Neuzuweisung der Liste ändert nicht den Wert x. In Java enthält x einen Verweis auf das erstellte Objekt. Wenn das Array, das die Liste unterstützt, erneut zugewiesen wird, ist x immer noch eine Referenz auf dasselbe Objekt.

Was Sie sehen, sind die Adressen von Objekten, die sich wegen des Garbage Collectors ändern. Sie können die gleichen Ergebnisse sehen, wo x nicht in der Liste überhaupt:

public static void main(String[] args) { 
    List<OBJ> list = new ArrayList<>(10000000); 

    OBJ x = new OBJ(); 

    printAddresses("Address x", x); 

    for (int idx = 0; idx < 1000000; idx++) { 
     list.add(new OBJ()); 
    } 

    printAddresses("Address x", x); 
} 

Ausgang:

Address x: 0x710b05580 
Address x: 0x54d5a19c0 

Objekte im Speicher kann bewegt werden, wie der Garbage Collector seine Arbeit tut. Wenn dies geschieht, werden alle Adressen, die geändert werden müssen, gleichzeitig aktualisiert.

Auch in C++ ist Ihr Wert x ein Verweis auf ein Element in der Liste. Wenn die Liste neu zugewiesen wird, wird diese Referenz daher ungültig. In Java ist x eine Kopie eines Elements in der Liste, so dass es keine Rolle spielt, ob die Liste neu zugeordnet wird. Es ist nicht möglich, einen Verweis auf ein Element in Java zu haben.

List<OBJ> in Java ist wirklich eine Liste von Verweisen auf Objekte. Diese Objekte existieren unabhängig von der Liste. Sie können eine Kopie einer dieser Referenzen erstellen, um eine neue Referenz auf dasselbe Objekt zu erhalten.

Verwandte Themen