wake-up-neo.com

löschen oder auf null setzen für objekte in java

Ich habe vor kurzem nach Speicherplatz gesucht, der von Java-Objekten belegt ist. Dabei wurde ich verwirrt, wie Objekte in Java kopiert werden (flach/tief) und wie man versehentlich das Löschen/Annullieren von Objekten verhindert, während sie noch verwendet werden.

Betrachten Sie folgende Szenarien:

  1. ArrayList<Object> als Argument an eine Methode übergeben.
  2. Übergeben eines ArrayList<Object> an eine ausführbare Klasse, die von einem Thread verarbeitet werden soll.
  3. einen ArrayList<Object> in eine HashMap setzen.

Wenn ich nun list = null; oder list.clear(); anrufe, was passiert dann mit den Objekten? In diesem Fall gehen die Objekte verloren, und in diesen Fällen wird nur die Referenz auf Null gesetzt.

Ich denke, es hat mit dem flachen und tiefen Kopieren von Objekten zu tun, aber in welchen Fällen geschieht das flache Kopieren und in welchem ​​Fall geschieht das tiefe Kopieren in Java?

15
anzaan

Erstens setzen Sie niemals ein object auf null. Dieses Konzept hat keine Bedeutung. Sie können einer Variable einen Wert von null zuweisen, aber Sie müssen die Begriffe "Variable" und "Objekt" sehr sorgfältig unterscheiden. Sobald Sie das getan haben, wird Ihre Frage sich selbst beantworten :)

In Bezug auf "flache Kopie" vs. "tiefe Kopie" sollte der Begriff "flache Kopie" hier wahrscheinlich vermieden werden, da bei einer flachen Kopie normalerweise ein neues Objekt erstellt wird, die Felder eines vorhandenen Objekts jedoch direkt kopiert werden. Bei einer tiefen Kopie wird auch eine Kopie der Objekte angefordert, auf die sich diese Felder beziehen (für Referenztypfelder). Eine einfache Aufgabe wie diese:

ArrayList<String> list1 = new ArrayList<String>();
ArrayList<String> list2 = list1;

... tut nicht entweder eine flache Kopie oder eine tiefe Kopie in diesem Sinne. Die Referenz wird einfach kopiert. Nach dem obigen Code sind list1 und list2 unabhängige Variablen - sie haben gerade die gleichen Werte (Referenzen). Wir könnten den Wert eines von ihnen ändern und den anderen nicht beeinflussen:

list1 = null;
System.out.println(list2.size()); // Just prints 0

Wenn Sie nun statt der variables eine Änderung an dem Objekt vornehmen, auf das sich die Werte der Variablen beziehen, wird diese Änderung auch über die andere Variable sichtbar:

list2.add("Foo");
System.out.println(list1.get(0)); // Prints Foo

Zurück zu Ihrer ursprünglichen Frage - Sie speichern niemals tatsächliche Objekte in einer Karte, Liste, Array usw. Sie speichern immer nur Referenzen . Ein Objekt kann nur dann gesammelt werden, wenn "live" Code nicht mehr möglich ist. Also in diesem Fall:

List<String> list = new ArrayList<String>();
Map<String, List<String>> map = new HashMap<String, List<String>>();
map.put("Foo", list);
list = null;

... das ArrayList-Objekt kann immer noch nicht aufgesammelt werden, da die Map einen Eintrag hat, der darauf verweist.

40
Jon Skeet

So löschen Sie die Variable

Nach meinem Wissen

Wenn Sie die Variable wiederverwenden möchten, verwenden Sie

               Object.clear();

Wenn Sie nicht wiederverwenden möchten, definieren Sie

               Object=null;

Hinweis: Vergleiche mit removeAll (), clear () ist schneller.

Bitte korrigieren Sie mich, wenn ich mich irre ....

6
softmage99

Java GC beansprucht die Objekte automatisch, wenn sie nirgendwo referenziert werden. In den meisten Fällen müssen Sie die Referenz daher explizit als null festlegen

Sobald der Gültigkeitsbereich der Variablen endet, wird das Objekt für GC zugelassen und wird freigegeben, wenn keine andere Referenz auf das Objekt verweist.

Java ist pass by value Wenn Sie also die Liste in der Methode auf null setzen, hat dies keinen Einfluss auf den ursprünglichen Verweis, der Ihnen in der Methode übergeben wurde. 

public class A{

    private List<Integer> list = new ArrayList<Integer>();
    public static void main(String[] args) {
       A a = new A();
       B b = new B();

       b.method(a.list);

       System.out.println(a.list.size()); //Will print 0 and not throw NullPointerException
    }   

}

class B{
    public void method(List<Integer> list){
        list = null;
        //just this reference is set to null and not the original one
        //so list of A will not be GCed
    }
}
2
Narendra Pathai

Wenn Sie eine ArrayList an eine Methode übergeben haben, hat list = null keine Auswirkung, wenn ein Live-Verweis auf die Liste irgendwo z. B. im aufrufenden Code vorhanden ist. Wenn Sie list.clear () an einer beliebigen Stelle im Code aufrufen, werden die Verweise auf die Objekte aus dieser Liste auf Null gesetzt. Das Übergeben eines Verweises an eine Methode ist kein flaches Kopieren. Es wird ein Referenzwert nach Wert übergeben

2

Es hängt davon ab, wie viele Variablen auf jedes Ihrer Objekte verweisen. Um dies zu erklären, wäre es besser, etwas Code zu verwenden:

Object myAwesomeObject = new Object();
List<Object> myList = new ArrayList<Object>();

myList.add(myAwesomeObject);

myList = null; // Your object hasn't been claimed by the GC just yet, your variable "myAwesomeObject" is still refering to it

myAwesomeObject = null; // done, now your object is eligible for garbage collection.

Es hängt also nicht davon ab, ob Sie Ihre ArrayList als Argument an eine Methode oder ähnliches übergeben, sondern hängt davon ab, wie viele Variablen sich noch auf Ihre Objekte beziehen.

1
morgano

Wenn Sie die Liste in eine Hash-Map einfügen, enthält die Hash-Map jetzt einen Verweis auf die Liste.

Wenn Sie die Liste als Argument an eine Methode übergeben, hat die Methode für die Dauer der Methode einen Verweis darauf.

Wenn Sie es an einen Thread übergeben, der bearbeitet werden soll, hat der Thread einen Verweis auf das Objekt, bis er beendet wird.

Wenn Sie in allen diesen Fällen list = null einstellen, werden die Verweise weiterhin beibehalten, aber sie verschwinden, nachdem diese Verweise verschwunden sind.

Wenn Sie einfach die Liste löschen, sind die Verweise weiterhin gültig, zeigen jedoch jetzt auf eine Liste, die plötzlich geleert wurde, und zwar durch Mittel, die dem Programmierer möglicherweise unbekannt sind und als Fehler betrachtet werden können, insbesondere wenn Sie den Thread verwenden.

1
tbodt

Ich habe vor kurzem nach Speicherplatz gesucht, der von Java-Objekten belegt ist.

Ein Ratschlag.

Es ist normalerweise eine schlechte Idee darüber nachzudenken. Und es ist normalerweise eine schlechtere Idee, zu versuchen, "zu helfen". In 99,8% der Fälle kann der Java-Garbage-Collector den Müll besser einsammeln, wenn Sie ihn einfach so weitermachen lassen ... und keine Verschwendung durch die Zuweisung von null an Dinge verschwenden. In der Tat besteht die Chance, dass sich die Felder, die Sie auf Null setzen, in Objekten befinden, die sowieso nicht erreichbar sind. In diesem Fall wird der GC nicht einmal die Felder betrachten, die Sie auf Null gesetzt haben.

Wenn Sie diese (pragmatische) Sichtweise einnehmen, ist alles, was Sie über flache oder tiefe Kopien denken und wann es sicher ist, die Dinge auf Null zu stellen, irrelevant.


In einigen Fällen ist es ratsam, null ... zuzuweisen, um mittel- oder langfristige Speicherlecks zu vermeiden. Und wenn Sie sich in einer dieser seltenen Situationen befinden, in denen Objekte "recycelt" werden, ist eine gute Idee, dann ist auch das Nullen zu empfehlen.

0
Stephen C