Java: quand ajouter readObjectNoData() pendant la sérialisation?

je suis en train de lire le chapitre de sérialisation dans "Java efficace". J'essaie de comprendre le paragraphe ci-dessous du livre.

Si vous implémentez une classe avec des champs d'instance qui est sérialisable et extensible, il y a une mise en garde dont vous devriez être conscient. Si classe a des invariants qui seraient violés si son champ d'instance être initialisé à leurs valeurs par défaut (zéro pour les types intégraux, faux pour booléen, et nul pour objet les types de référence), vous devez ajouter cette méthode readObjectNoData à la classe:

    // readObjectNoData for stateful extendable serializable classes
     private void readObjectNoData() throws InvalidObjectException {
             throw new InvalidObjectException("Stream data required");
     }

Je ne suis pas sûr de ce que signifie la déclaration ci-dessus .

pour tester ceci, j'ai créé une personne de classe (à la fois sérialisable et extensible)

   class Person   implements Serializable{

       private String name;

       private int age;

      Person() {
         this("default",1);
      }


     Person(String name, int y) {
       this.name = name;
        this.age = y;
      }
    }

et un employé de la classe qui l'étend.

     class Employee extends Person  {

      String address ;


    public Employee()
    {
        super();
        address ="default_address";
    }

    public Employee(String name , int age, String address)
    {
        super(name,age);
        this.address = address;
    }
           }

y a-t-il des invariants dans la classe de personnes que j'ai créée ? Quand seront-ils respectés ? J'ai copié collé le code de la méthode readObjectData() dans la classe des employés, mais il n'a jamais été appelé. Quand la méthode readObject() s'appelle ? Ai-je raté quelque chose ?

22
demandé sur Geek 2011-09-16 17:14:41

4 réponses

readObjectNoData section dans Java Object Serialization Specification semble intéressant (voir ci-dessous).

Vos modifications à la question donnez un exemple parfait. Si Employeeserialized quand il ne s'est pas étendu Person et après deserialized quand il fait alors le Person partie serait initialisée pour vider la chaîne et l'âge 0. En utilisant cette méthode, vous pouvez initialiser "nom" et 1 respectivement.

pour les objets sérialisables, le la méthode readObjectNoData permet une classe pour contrôler l'initialisation de ses propres champs dans le cas où un l'instance de la sous-classe est désérialisée et le flux de sérialisation ne ne pas inscrire la classe en question comme une superclasse de la deserialized objet. Cela peut se produire lorsque la partie de une version différente de la classe de l'instance désérialisée partie d'envoi, et la version du récepteur étend les classes qui ne sont pas prolongé par la version de l'expéditeur. Cela peut se produisent également si le le flux de sérialisation a été altéré; par conséquent, readObjectNoData est utile pour initialiser correctement les objets désérialisés malgré un source" hostile " ou source incomplète.

private void readObjectNoData() throws ObjectStreamException;

chaque classe sérialisable peut définir sa propre méthode readObjectNoData. Si une classe serialisable ne définit pas une méthode readObjectNoData, alors dans les circonstances énumérées ci-dessus les champs de la classe sera initialisé à leurs valeurs par défaut (comme listée à la section 4.5.5 de la Java Langage de Spécification, Deuxième Édition); ce comportement est conforme à celui D'ObjectInputStream avant la version 1.4 du JavaTM 2 SDK, Édition Standard, lorsque la prise en charge de readObjectNoData méthodes a été introduit. Si une classe serialisable ne définit pas la méthode readObjectNoData et les conditions susmentionnées se produisent, puis readObjectNoData sera invoqué au moment de la désérialisation lorsqu'une méthode de readObject définie par classe autrement appelé a la classe en question a été répertoriée par le stream comme une superclasse de la instance en cours de desérialisation.

21
répondu Miserable Variable 2011-09-16 13:37:28

y a-t-il des invariants dans la classe de personnes que j'ai créée? Quand seront-ils respectés?

aucune explicitement, mais imaginez que d'autres méthodes de la classe supposent que name n'est jamais null et jeter NullPointerException si ça l'a jamais été. Dans ce cas, la non-nullité de name est un invariant.

j'ai copié le code pour readObjectData() méthode Employee classe , mais ça n'a jamais été appelé. Quand la méthode readObject() être appelé ?

Il n'y a pas de méthode readObjectData() impliqué avec la sérialisation, ce doit être une faute de frappe. readObject() méthode est appelée à chaque fois qu'un objet sérialisé est désérialisé.

readObjectNoData() la méthode est activée pour un cas de coin obscur lors de la desérialisation d'un sous-classe de la classe qui contient la méthode.

avancé de sérialisation l'article sur le Soleil le site Web D'Oracle couvre l'objet de ces la sérialisation des méthodes d'assistance. Je vous suggère de commencer par là et de poster toutes les questions suivantes que vous pourriez rencontrer.

(mise à jour)

dans le cas où vous êtes curieux, la méthode readObjectNoData a été ajoutée dans la version 1.4 pour couvrir un cas de coin impliquant l'ajout d'une superclasse serialisable à une classe serialisable existante. Les détails se trouvent dans la spécification de sérialisation la Sérialisation, 3.5.

Le texte référencé est:

pour les objets sérialisables, la méthode readObjectNoData permet à une classe de contrôler l'initialisation de ses propres champs dans le cas où une instance de sous-classe est désérialisée et que le flux de sérialisation ne Liste pas la classe en question comme une superclasse de l'objet désérialisé. Cela peut se produire dans les cas où la partie de réception utilise une version différente de la classe de l'instance désérialisée que la partie d'envoi, et la version du destinataire étend les classes qui ne sont pas étendues par la version de l'expéditeur. Cela peut aussi se produire si le flux de sérialisation a été altéré; par conséquent, readObjectNoData est utile pour initialiser correctement les objets désérialisés malgré un flux source "hostile" ou incomplet.

Donc cela peut se produire dans deux cas:

  • la JVM qui décode le flux d'objets a une version plus récente de la sous-classe en cours de desérialisation (Employee), qui étend une certaine classe de parent (Person). La JVM à l'origine *en*codé le flux d'objets a une version différente et plus ancienne de ces classes, où Person n'était pas encore une superclasse deEmployee.
  • Quelqu'un a intentionnellement trafiqué le flux d'objets afin de casser des choses.
3
répondu Barend 2011-09-16 13:41:25

"Extensible" signifie "peut avoir une sous-classe".

readObjectNoData est utilisé dans un cas inhabituel où le serializer (écrivain) travaille avec une version d'une classe sans classe de base, tandis que le deserializer (lecteur) de la classe a une version de la classe qui est basée sur une sous-classe. La sous-classe peut dire "c'est ok si ma classe de base n'est pas dans les données sérialisées - il suffit d'en créer une vide" en implémentant readObjectNoData. Voir ces notes de mise à jour.

3
répondu Ed Staub 2013-11-18 18:08:30

un invariant dans votre classe de personnes pourrait être quelque chose comme:

age must be greater than 0

Ainsi, lorsque la classe Person est instanciée avec la valeur par défaut, 0 (voir ici:http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html) vous aurez violé cet invariant.

Toutefois, étant donné le constructeur par défaut, vous serez bien :)

0
répondu Mark Pope 2011-09-16 13:24:32