2016-03-09 15 views
6

Nếu tôi serialize một đối tượng Class (ví dụ, HashMap.class), và sau đó deserialize nó trong một thể hiện của JVM, nó quay ra rằng lớp deserialized là giống hệt với một hiện nạp:Làm thế nào để Java có thể deserialize các đối tượng Class trong khi vẫn giữ bản sắc của chúng cho các đối tượng Class đang được nạp?

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(); 
    } 
} 

thế nào là Java có thể deserialize các đối tượng trong trường hợp này để danh tính được bảo tồn? Class dường như không thực hiện writeObject()/readObject()/readResolve().

Hành vi này có thể bị hỏng khi tải một lớp cụ thể/sử dụng trình nạp lớp cụ thể/sử dụng thiết lập JVM cụ thể/thực hiện điều gì đó trong quá trình tuần tự hóa không? Có trường hợp nào được tải Class sẽ không giống với trường hợp được deserialized không? Nói cách khác, tôi có thể dựa vào hành vi này trong ứng dụng của tôi để tuần tự hóa và deserialize Class đối tượng?

+3

IMHO: một đối tượng lớp deserialized nên không thể phân biệt của đối tượng lớp "chuẩn" cùng loại. Xem https://docs.oracle.com/javase/7/docs/api/serialized-form.html#java.lang.Class – Xvolks

Trả lời

2

Làm thế nào để Java có thể deserialize các đối tượng trong trường hợp này để danh tính được bảo tồn?

Điều này là do các phiên bản lớp được lưu trữ bởi trình nạp lớp.

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

hành vi này có thể bị phá vỡ với tải một lớp học đặc biệt/sử dụng một classloader đặc biệt/sử dụng một thiết lập JVM đặc biệt/làm một cái gì đó trong serialization?

Đối với trường hợp serialized của các lớp học từ gói không bắt đầu với java.* này có thể bị phá vỡ bằng classloaders khác nhau trong ObjectInputStream (một ví dụ here).

Đối với các lớp học trong java.* như trường hợp của bạn (java.lang.Class), chỉ có lớp loader Bootstrap có thể tải chúng, và cho rằng định nghĩa lớp là duy nhất cho mỗi lớp loader (đảm bảo bởi JVM spec)

Nói cách khác, tôi có thể dựa vào hành vi này trong ứng dụng của tôi để serialize và deserialize lớp đối tượng

+0

Chắc chắn 'Lớp' được lưu trữ bởi bộ nạp lớp, điều đáng ngạc nhiên đối với tôi là sự kiện deserializing một' Lớp' được tạo trong cá thể JVM _another_ duy trì danh tính với các cá thể 'Lớp' trong cá thể JVM hiện tại. Vì vậy, nếu tôi sử dụng logic deserialization chuẩn của 'ObjectInputStream', chỉ sử dụng một trình nạp lớp đơn và không có định nghĩa khác nhau cho các lớp có cùng tên chuẩn, thì tôi có thể chắc chắn rằng danh tính của các đối tượng' Lớp' sẽ được giữ lại sau khi deserialization? – gvlasov

+0

Lưu ý rằng điều này bạn gọi là "Lớp" trong thực tế là một thể hiện của lớp 'Lớp' (xin lỗi cho lưỡi-twister). Vì vậy, bạn không thể có nhiều trường hợp cho mỗi trình nạp lớp đại diện cho cùng một lớp FQN. Vì vậy, câu trả lời là có, bạn có thể chắc chắn – idelvall

+0

Cũng lưu ý rằng deserializing một đối tượng serialized (từ bất kỳ lớp học bao gồm 'Class') có thể dẫn đến lỗi nếu các phiên bản khác nhau ... – idelvall

0

Làm thế nào để Java có thể deserialize các đối tượng trong trường hợp này để danh tính được bảo tồn? Class dường như không thực hiện writeObject()/readObject()/readResolve().

Nó không cần phải thực hiện readObject() hoặc writeObject() để thực hiện điều này, nhưng nó có thể làm điều đó bằng cách thực hiện readResolve(), hoặc bằng logic đặc biệt trong ObjectInputStream.

+0

Cảm ơn, nhưng đây phải là nhận xét chứ không phải là câu trả lời. Tôi đã chỉnh sửa bài viết của mình đề cập đến rằng 'Lớp' không có' readResolve() '. – gvlasov

+0

Nó không phải là một bình luận. Bây giờ tôi đã trích dẫn câu hỏi được trả lời bằng câu trả lời này.Có vẻ như đó là câu trả lời sai, tôi đã sửa đổi nó. – EJP

Các vấn đề liên quan