2013-03-21 13 views
5

To pozycja nr 74 skutecznej książki java jest paragraf (2 para od ostatniego punktu 74), który wspomina, jak na poniżej:Efektywna Java Nr 74 (na serializacji): Wdrożenie Serializable rozważnie

Klasy wewnętrzne (pozycja 22) nie powinny implementować Serializable. Używają one syntetycznych pól generowanych przez kompilator do przechowywania odwołań do obudowań instancji i do przechowywania wartości zmiennych lokalnych z zakresu obejmującego zakresy . Sposób, w jaki te pola odpowiadają definicji klasy, jest nieokreślony, podobnie jak nazwy klas anonimowych i lokalnych. Dlatego domyślna serializowana postać klasy wewnętrznej jest zdefiniowana jako niezdefiniowana.

Wiem o klasie wewnętrznej używa pola syntetycznego generowanego przez kompilator do przechowywania odwołania do zamkniętych wystąpień, np. jeśli otaczającą klasą jest MyEnclosing, a wewnętrzną klasą jest MyInner, wówczas otaczającym odnośnikiem jest MyEnclosing.this. Ale nie jestem w stanie uzyskać części BOLD. Pomóż mi zrozumieć znaczenie. Dzięki!!!

Odpowiedz

6

Załóżmy, że masz lokalny klasa tak:

class OuterClass { 
    Runnable run; 

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

Załóżmy teraz staram się szeregować this, który zawiera obiekt tego typu klasy wewnętrznej. Mój kompilator nazywa tę klasę OuterClass$1 i nadaje jej pole o nazwie val$a. Dokładne nazwy używane w tej sytuacji nie są jednak częścią specyfikacji kompilatora. Inny kompilator może wybrać wywołanie wewnętrznej klasy OuterClass$method$1. W takim przypadku serializacja w jednej skompilowanej wersji i deserializacja w drugiej zakończyłaby się niepowodzeniem, mimo że użyto tego samego pliku źródłowego.

(. Dodatkowo, istnieje również problem, że anonimowa klasa wewnętrzna nie ma no-args konstruktora Ale ze względu na powyższy problem, nawet nazwany klasa wewnętrzna nie może wiarygodnie serializacji)

+0

dzięki za wysiłek. Zasadniczo masz na myśli, że val $ a jest zmienną przechowywaną w klasie wewnętrznej przez kompilator, który (val $ a) jest częścią zewnętrznej klasy. Mam rację? Jeśli mam rację, to nie jest serializowanie klasy wewnętrznej. Zasadniczo nie jestem w stanie uzyskać "Ale dokładne nazwy do wykorzystania w tej sytuacji nie są częścią części specyfikacji kompilatora". – Trying

+1

Jestem prawie pewien, że widziałem pliki klas z konwencją nazewnictwa, która nazwałaby wewnętrzną klasę tutaj 'OuterClass $ method $ 1' zamiast' OuterClass $ 1' (chociaż wypróbowałem teraz kilka kompilatorów i nie byłem w stanie aby to powtórzyć). Chodzi o to, że [spec] (http://jcp.org/aboutJava/communityprocess/maintenance/JLS/innerclasses.pdf) wymaga tylko, aby kompilator tworzył unikalną nazwę, dołączając kombinację $, liter i liczby po nazwie klasy zamykającej. A jeśli nazwa klasy się zmieni, deserializacja zakończy się niepowodzeniem. –

+0

Jestem nieco zdezorientowany ... Dlaczego twoja anonimowa klasa "Runnable" zostanie przekształcona do postaci szeregowej, gdy serializujesz "this"? Tylko pola twojej zewnętrznej klasy są serializowane. I pytanie właściwie odnosi się do wewnętrznej/lokalnej/anonimowej klasy, która sama jest "Serializable" ... –

1

Rozważmy następujący kod:

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

Mój kompilator wywołuje anonimową klasę wewnętrzną Main$1. Kiedy rozbierać go, widzę, że odpis wartości x z zakresu zewnętrznej jest przechowywana w prywatnym polu zwanym val$x:

private final int val$x; 

To jest przykład tego, co bold część mówi.

0

Wewnętrzna klasa to klasa non-statyczne zdefiniowane w innej klasie:

class Outer implements Serializable { 
    private String someString; 

    class Inner implements Serializable { 
     private int someInt; 
    } 

} 

Po utworzeniu instancji klasy Inner, kiedy go szeregować, musi mieć odniesienie do zewnętrznej klasy (do którego uzyskuje dostęp wewnętrznie poprzez odniesienie Outer.this) i jak osiąga się to w przypadku serializowanego obiektu, nie jest określone. To samo odnosi się do lokalnej klasy:

class Outer implements Serializable { 
    private String someString; 

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

Jeśli wartość zwracana przez method() ty serializacji, to muszą mieć odniesienie do i, ale to nie jest wiarygodne.

Powiązane problemy