2013-03-21 36 views
5

item 74 di efficace libro Java v'è un paragrafo (2 ° comma dello scorso della voce 74) che cita come sotto:Effective Java No. 74 (sulla serializzazione): Implementare Serializable giudiziosamente

Le classi interne (elemento 22) non dovrebbero implementare serializzabili. Utilizzano i campi sintetici generati dal compilatore per memorizzare i riferimenti alle istanze e per memorizzare i valori delle variabili locali dagli ambiti . Come questi campi corrispondono alla definizione di classe è non specificato, come lo sono i nomi delle classi anonime e locali. Pertanto, la forma serializzata predefinita di una classe interna è ill- definita.

So che la classe interna utilizza il campo sintetico generato dal compilatore per memorizzare il riferimento alle istanze che includono, ad es. se la classe che racchiude è MyEnclosing e la classe interna è MyInner, il riferimento di chiusura è MyEnclosing.this. Ma non sono in grado di ottenere la parte BOLD. Per favore aiutami a capire il significato. Grazie!!!

risposta

6

Supponiamo di avere una classe locale come questo:

class OuterClass { 
    Runnable run; 

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

Ora supponiamo che io cerco di serializzare this, che contiene un oggetto di questo tipo di classe interna. Il mio compilatore chiama la classe OuterClass$1 e gli assegna un campo chiamato val$a. Ma i nomi esatti da usare in questa situazione non fanno parte delle specifiche del compilatore. Un altro compilatore potrebbe scegliere di chiamare la classe interna OuterClass$method$1. In tal caso, la serializzazione in una versione compilata e la deserializzazione nell'altra non riuscirebbe, anche se è stato utilizzato lo stesso file sorgente.

(. Inoltre, c'è anche il problema che una classe interna anonima non ha un costruttore senza args Ma a causa del problema di cui sopra, anche una classe interna di nome non si può attendibilmente serializzare)

+0

grazie per il vostro sforzo. Fondamentalmente intendi dire che val $ a è la variabile memorizzata nella classe interna dal compilatore che (val $ a) fa parte della classe out. Ho ragione? Se sono corretto, qual è il problema non è serializzare la classe interiore. Fondamentalmente non sono in grado di ottenere il tuo "Ma i nomi esatti da utilizzare in questa situazione non fanno parte delle specifiche del compilatore". – Trying

+1

Sono abbastanza sicuro che ho visto file di classe con una convenzione di denominazione che avrebbe chiamato la classe interna qui 'OuterClass $ metodo $ 1' invece di' OuterClass $ 1' (anche se ho provato diversi compilatori solo ora e non ero in grado per riprodurlo). Il punto è il il [spec] (http://jcp.org/aboutJava/communityprocess/maintenance/JLS/innerclasses.pdf) richiede solo che il compilatore di creare un nome univoco aggiungendo qualche combinazione di $ 's, lettere, e numeri dopo il nome della classe allegata. E se il nome della classe fosse cambiato, la deserializzazione fallirebbe. –

+0

Sono un po 'confuso ... Perché il vostro anonimo classe 'Runnable' ottenere serializzato quando sei serializzazione' this'? Solo i campi della tua classe esterna vengono serializzati. E la domanda in realtà si riferisce alla classe interna/locale/anonima stessa che è 'Serializable' ... –

1

Si consideri il seguente codice:

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

mio compilatore chiama la classe interna anonima Main$1. Quando ho smontarlo, vedo che una copia del valore della x dal campo di applicazione esterna è memorizzato in un campo privato chiamato val$x:

private final int val$x; 

Questo è un esempio di ciò che il grassetto parte sta parlando.

0

Una classe interna è una classe non statica definita all'interno di qualche altra classe:

class Outer implements Serializable { 
    private String someString; 

    class Inner implements Serializable { 
     private int someInt; 
    } 

} 

Dopo aver un'istanza della classe Inner, quando si serializzare esso, deve avere un riferimento alla classe esterna (che accede internamente tramite il riferimento Outer.this) e il modo in cui questo viene ottenuto per un oggetto serializzato non è specificato. Lo stesso vale per una classe locale:

class Outer implements Serializable { 
    private String someString; 

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

Se si serializzare il valore restituito da method(), sarebbe necessario disporre di un riferimento a i, ma non è affidabile.