2016-03-09 36 views
6

Gdybym serializować Class obiekt (na przykład HashMap.class), a następnie deserializować go w innej instancji JVM, okazuje się, że innej niż serializowana klasa jest identyczny z aktualnie załadowanego:W jaki sposób Java może deserializować obiekty klasy, zachowując ich tożsamość do aktualnie załadowanych obiektów klasy?

import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
import java.util.HashMap; 

final class DeserializationTest { 

    static String path = "/home/suseika/test.ser"; 
    static Class<HashMap> cls = HashMap.class; 

    public static void main(String[] args) throws Exception { 
     if (args[0].equals("serialize")) { 
      serialize(); 
     } else if (args[0].equals("deserialize")) { 
      final Object deserialized = deserialize(); 

      // The important line, prints "true" 
      System.out.println(deserialized == cls); 
     } 
    } 

    static Object deserialize() throws Exception { 
     ObjectInputStream in = new ObjectInputStream(new FileInputStream(path)); 
     return in.readObject(); 
    } 

    static void serialize() throws Exception { 
     FileOutputStream fileOut = new FileOutputStream(path); 
     ObjectOutputStream out = new ObjectOutputStream(fileOut); 
     out.writeObject(cls); 
     out.close(); 
     fileOut.close(); 
    } 
} 

Jak jest Java móc deserializować obiekty w tym przypadku, aby zachować tożsamość? Class nie wydaje się implementować writeObject()/readObject()/readResolve().

Czy to zachowanie można zepsuć, ładując daną klasę/używając określonego programu ładującego klasy/używając określonej konfiguracji maszyny JVM/wykonując coś podczas serializacji? Czy są przypadki, w których załadowany Class nie byłby taki sam jak deserialized jeden? Innymi słowy, czy mogę polegać na tym zachowaniu w mojej aplikacji, aby przekształcić do postaci szeregowej i deserializować obiekty o numerach Class?

+3

IMHO: a klasa postaci innej niż serializowana obiekt powinien być nie do odróżnienia "standardowego" obiektu klasy tego samego typu. Zobacz https://docs.oracle.com/javase/7/docs/api/serialized-form.html#java.lang.Class – Xvolks

Odpowiedz

2

W jaki sposób Java może deserializować obiekty w tym przypadku, aby zachować tożsamość?

Dzieje się tak, ponieważ instancje klasy są buforowane przez program ładujący klasy.

Does Java guarantee that Object.getClass() == Object.getClass()?

Czy takie zachowanie jest przełamany ładowania szczególną klasę/używanie konkretnego classloader/używanie konkretnej konfiguracji JVM/robi coś podczas serializacji?

Na odcinkach instancje klas z opakowań nie wychodząc z java.* może być przerwana przy użyciu różnych classloaders w ObjectInputStream (przykładowa here).

Dla klas w java.* jak sprawy (java.lang.Class), tylko ładowarka klasy Bootstrap można je załadować, a biorąc pod uwagę, że definicja klasy jest unikatowy za ładującego klasy (gwarantowane przez JVM spec)

Innymi słowy, mogę liczyć na to zachowanie w mojej aplikacji do serializacji i deserializacji klasy obiektów

Tak

+0

Pewnie 'Class'es są buforowane przez program ładujący klasy, co było dla mnie zaskakujące, że deserializacja klasy' created' utworzonej w _innej_ instancji JVM zachowuje tożsamość z instancjami 'Class' w bieżącej instancji JVM. Więc jeśli używam standardowej logiki deserializacji 'ObjectInputStream', używam tylko jednego programu ładującego klasy i nie mam różnych definicji dla klas o tych samych nazwach kanonicznych, to czy mogę być pewny, że tożsamość obiektów' Class' zostanie zachowana po deserializacji? – gvlasov

+0

Zauważ, że to, co określasz jako "Klasa", jest w rzeczywistości instancją klasy "Class" (przepraszam za język-twister). Więc nie można mieć wielu wystąpień na każdy moduł ładujący odpowiadający tej samej klasie FQN. Dlatego odpowiedź brzmi: tak, możesz być pewna. – idelvall

+0

Zauważ również, że przekształcenie szeregowego obiektu z serializacją (z dowolnej klasy, w tym 'Class') może prowadzić do błędów, jeśli wersje różnią się ... – idelvall

0

W jaki sposób Java może deserializować obiekty w tym przypadku, aby zachować tożsamość? Class nie wydaje się implementować writeObject()/readObject()/readResolve().

Nie trzeba zaimplementować readObject() lub writeObject() do osiągnięcia tego celu, ale może to zrobić poprzez wdrożenie readResolve() lub specjalnymi logiki w ObjectInputStream.

+0

Dzięki, ale to powinien być komentarz, a nie odpowiedź. Zmieniłem swój post, wspominając, że 'Class' nie ma' readResolve() '. – gvlasov

+0

To nie jest komentarz. Przytoczyłem teraz pytanie, na które odpowiada ta odpowiedź.Ponieważ wydaje się, że była to niepoprawna odpowiedź, zmienię ją. – EJP