2013-03-21 19 views
5

Nó item không 74 của cuốn sách java hiệu quả có một đoạn (para thứ 2 từ cuối cùng của mục 74) mà đề cập đến theo dưới đây:hiệu quả java mục không 74 (trên serialization): Thực hiện Serializable sáng suốt

Các lớp bên trong (Mục 22) không nên thực hiện Serializable. Họ sử dụng các trường tổng hợp do biên dịch tạo ra để lưu trữ các tham chiếu kèm theo các trường hợp và để lưu trữ các giá trị của biến địa phương từ bao gồm phạm vi . Cách các trường này tương ứng với định nghĩa lớp là không xác định, cũng như tên của các lớp ẩn danh và cục bộ. Do đó, dạng tuần tự mặc định của một lớp bên trong là ill- được xác định.

Tôi biết về lớp bên trong sử dụng trình biên dịch tạo ra trường tổng hợp để lưu trữ tham chiếu đến các trường hợp kèm theo, ví dụ: nếu lớp kèm theo là MyEnclosing và lớp bên trong là MyInner thì tham chiếu kèm theo là MyEnclosing.this. Nhưng tôi không thể lấy phần BOLD. Xin hãy giúp tôi hiểu ý nghĩa. Cảm ơn!!!

Trả lời

6

Giả sử bạn có một lớp địa phương như thế này:

class OuterClass { 
    Runnable run; 

    void method() { 
     final int a = 8; 
     this.run = new Runnable() { 
      public void run() { 
      System.out.println(a); 
      } 
     }; 
    } 
} 

Bây giờ giả sử tôi cố gắng serialize this, trong đó có một đối tượng kiểu lớp bên này. Trình biên dịch của tôi đặt tên là lớp OuterClass$1 và cung cấp cho nó một trường có tên là val$a. Nhưng các tên chính xác được sử dụng trong tình huống này không phải là một phần của spec của trình biên dịch. Trình biên dịch khác có thể chọn gọi lớp bên trong là OuterClass$method$1. Trong trường hợp đó, việc tuần tự hóa trong một phiên bản được biên dịch và giải tuần tự hóa trong một phiên bản khác sẽ thất bại, mặc dù cùng một tệp nguồn đã được sử dụng.

(. Thêm vào đó, có cũng là vấn đề mà một lớp bên trong vô danh không có một constructor không có args Nhưng do vấn đề trên, thậm chí là một lớp bên trong được đặt tên không thể đáng tin cậy serialize)

+0

cảm ơn vì nỗ lực của bạn. Về cơ bản, bạn muốn nói là val $ a là biến được lưu trong lớp bên trong bởi trình biên dịch (val $ a) là một phần của lớp ngoài. Tôi có đúng không? Nếu tôi đúng thì vấn đề là gì không phải là tuần tự hóa lớp bên trong. Về cơ bản tôi không thể có được của bạn "Nhưng tên chính xác được sử dụng trong tình huống này không phải là một phần của spec của trình biên dịch" một phần. – Trying

+1

Tôi khá chắc chắn rằng tôi đã thấy các tệp lớp với quy ước đặt tên có thể gọi là lớp bên trong ở đây 'OuterClass $ method $ 1' thay vì' OuterClass $ 1' (mặc dù tôi đã thử một vài trình biên dịch vừa rồi và không thể để tái tạo điều đó). Vấn đề là [spec] (http://jcp.org/aboutJava/communityprocess/maintenance/JLS/innerclasses.pdf) chỉ yêu cầu trình biên dịch tạo ra một tên duy nhất bằng cách nối thêm một số tổ hợp của $, chữ cái, và số sau tên lớp kèm theo. Và nếu tên lớp đã thay đổi, việc deserialization sẽ thất bại. –

+0

Tôi hơi bối rối ... Tại sao lớp Vô danh 'Runnable' của bạn lại được serialize khi bạn đang tuần tự hóa' this'? Chỉ các trường của lớp ngoài của bạn mới được đăng. Và câu hỏi thực sự đề cập đến lớp bên trong/địa phương/ẩn danh là 'Serializable' ... –

1

Xét đoạn mã sau:

public class Main { 
    public static void main(String[] args) { 
     final int x = Integer.valueOf(args[0]); 
     new Object() { 
      void print() { 
       System.out.println(x); 
      } 
     }.print(); 
    } 
} 

Trình biên dịch của tôi gọi lớp bên trong vô danh Main$1. Khi tôi tháo rời nó, tôi thấy rằng một bản sao của giá trị của x từ phạm vi bên ngoài được lưu trữ trong một lĩnh vực riêng gọi là val$x:

private final int val$x; 

Đây là một ví dụ về những gì đậm phần đang nói về.

0

Một lớp bên trong là một lớp không tĩnh được định nghĩa trong một số lớp khác:

class Outer implements Serializable { 
    private String someString; 

    class Inner implements Serializable { 
     private int someInt; 
    } 

} 

Một khi bạn có một thể hiện của lớp Inner, khi bạn serialize nó, nó phải có một tham chiếu đến các lớp bên ngoài (mà nó truy cập nội bộ thông qua các tài liệu tham khảo Outer.this) và làm thế nào điều này đạt được cho một đối tượng serialized là không xác định. Điều tương tự cũng áp dụng cho một lớp địa phương:

class Outer implements Serializable { 
    private String someString; 

    Serializable method(final int i) { 
     class Inner implements Serializable { 
      Inner() { 
       System.out.println(i); 
      } 
     } 
     return new Inner(); 
    } 
} 

Nếu bạn serialize giá trị trả về bởi method(), nó sẽ cần phải có một tài liệu tham khảo để i, nhưng đó là không đáng tin cậy.

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