Serialização, erro ao deserializar subclasses

7 respostas
B

Ola a todos
Estou aqui estudando serialização e, qdo estava fazendo alguns testes aconteceu o seguinte:

package br.com.certificacao.cap_6.classes;

import java.io.*;
/**
 * Classe que vai nos ajudara entender o conceito de herança com objetos
 * serializados.
 * A superclasse Animal não é serializada
 * */
public class Bird extends Animal implements Serializable{

	String tipo;
	public Bird(String tipo, int weight) {
		super("Passaro");


		System.out.println("Construtor de Bird this.weight= "+this.weight);
		this.tipo= tipo;
		this.weight = weight;
		System.out.println("Ja preencheu os valores de Bird");
	}

	public String getTipo(){
		return this.tipo;
	}
	public int getWeight(){
		return this.weight;
	}

}
package br.com.certificacao.cap_6.classes;
public class Animal {

               int weight = 42;

	Animal(String a){
		System.out.println("Construtor de animal "+a);
	}

	Animal(){
		System.out.println("Construtor de animal ");
	}

}
package br.com.certificacao.cap_6;

import br.com.certificacao.cap_6.classes.*;
import java.io.*;

public class Serializacao_33 {

	public static void main(String[] args){
		Bird bird = new Bird("Pardal", 12);
		System.out.println(" Antes de serializar \n tipo= "+bird.getTipo()+", tamanho= "+bird.getWeight());

		try{
			FileOutputStream fos = new FileOutputStream("testeSerBird.ser");
			ObjectOutputStream oos = new ObjectOutputStream(fos);
			oos.writeObject(bird);
			oos.close();
		}catch(IOException e){}


		try {
			FileInputStream fis = new FileInputStream("testeSerBird.ser");
			ObjectInputStream ois = new ObjectInputStream(fis);

			bird= (Bird)ois.readObject();
			ois.close();
		}catch(IOException io){
			io.printStackTrace();
		}catch(ClassNotFoundException ce){ce.printStackTrace();}

		System.out.println(" DEPOIS de serializar \n tipo= "+bird.getTipo()+", tamanho= "+bird.getWeight());
	}
}

Pois bem, o que aconteceu é que se eu comentar o construtor Animal() qdo for deserializar ocorre um erro:

java.io.InvalidClassException: br.com.certificacao.cap_6.classes.Bird; no valid constructor

at java.io.ObjectStreamClass.<init>(Unknown Source)

at java.io.ObjectStreamClass.lookup(Unknown Source)

at java.io.ObjectOutputStream.writeObject0(Unknown Source)

at java.io.ObjectOutputStream.writeObject(Unknown Source)

Achei isso “sinistro”!!
Sera que para de-serializar a superclasse não pode conter um construtor sobrecarregado?
Ou eu to fazendo algo errado?

T+!

7 Respostas

rsakurai

Oi Babol,

faz sua classe Animal implementar Serializable:

mduques

Coloque um construtor default na classe Bird

public Bird(){

}

io.InvalidClassException: br.com.certificacao.cap_6.classes.Bird; no valid constructor

ricardo13

olá,

o engraçado q aki deu certo !!!
do msm modo q vc fez … só naum está com o msm nome das classes…mas as vaiaveis estão iguais.

Ricardo

ricardo13

olá,

agora q eu vi do construtor Animal comentado.

o erro acontece pelo fato de seu método Animal(String a) …chamar logo em seguinda o this()…dai como vc comentou o Animal() … ele vai falar q naum existe o construtor

Um abraço

Ricardo

B

Ola pessoal…

Desculpa a demora, mas vcs sabem o que é projeto com o prazo perto do fim né …hehehehe

mduques
Minha duvida é justamente essa. Se eu sobrecarregar um construtor e nao declarar o default (que todos nos sabemos que nao é criado qdo sobrecarregamos) vai ter problema para de-serializar ?!?

Isso é uma baita pegadinha não?

T+

Fabio_Kym_Nascimento

Olá

Quando você recupera um objeto serializado a JVM da new no construtor padrão e popula os atributos que não estavam marcados como transient, pra isso ela precisa de um construtor padrão, sem argumentos, ela (JVM) não consegue adivinhar que é possível construir um objeto através de um construtor que recebe argumentos e depois popular o restante.

Agora vem a pergunta: Se Bird não extende Animal (e nenhuma outra classe explicitamente), ele não precisa de um construtor padrão mesmo declarando um construtor com argumentos, mas ueh, é sabido que se você declara um construtor qualquer que difere do padrão, o java não cria mais o padrão “non-arg”, então “wtf”?

Essa “mágica” é feita ao implementar Serializable, embora essa interface “não tenha nada”, o compilador “cria” um construtor padrão non-arg pra você, automaticamente! Isso mesmo, essa é a única maneira que eu conheço de ter um construtor padrão mesmo declarando um outro qualquer automaticamente! Só que o construtor padrão não está no bytecode, e sim no objeto serializado (i.e. no arquivo ou outro meio qualquer que você usou para serializar o objeto), logo você não vai conseguir dar new explicitamente sem passar argumentos necessários pelos outros construtores que a classe tenha!

Avançando mais um pouco, ao fazer Bird implementar Serializable e extender Animal, você deve obrigatoriamente ter um construtor padrão non-arg em Animal, porque Animal não está marcado como Serializable! Logo a JVM não vai “criar” um para você!

Solução: Ou você implementa Serializable em Animal, fazendo com que todas as classes que a extendam (como Bird no caso) sejam “serialiaveis”, ou você deve obrigatoriamente ter um construtor padrão na super classe (explicito ou implicito)! E isso serve pra hieraquia completa, se Bird implementa Serializable e extendesse Animal que por sua vez extendesse “SerVivo”, ambas as “super classes” de Bird devem prover um construtor padrão non-arg (implicita ou explicitamente), ou você implementa Serializable direto em SerVivo, fazendo com que todos que o extendam sejam serializáveis.

Isso está no javadoc de Serializable, as follows:

http://java.sun.com/javase/6/docs/api/java/io/Serializable.html

To allow subtypes of non-serializable classes to be serialized, the subtype may assume responsibility for saving and restoring the state of the supertype’s public, protected, and (if accessible) package fields. The subtype may assume this responsibility only if the class it extends has an accessible no-arg constructor to initialize the class’s state. It is an error to declare a class Serializable if this is not the case. The error will be detected at runtime.

During deserialization, the fields of non-serializable classes will be initialized using the public or protected no-arg constructor of the class. A no-arg constructor must be accessible to the subclass that is serializable. The fields of serializable subclasses will be restored from the stream.

A resposta ficou meio longa, mas espero que de pra entender :stuck_out_tongue:

BTW, da onde são esses exercícios? Também estou me preparando para a prova e gostaria muito de te-los se possível!

Ah, sim, isso é uma bela de uma pegadinha :stuck_out_tongue:

[]
Kym

Jeferson_Manetti

olá pessoal estou um pouco atrasado…
mas gostaria de participar ^^

bom no meu ponto de vista acontece o seguinte…

a sua super (Animal) tem 2 construtores [vcs ja sabem disso] um default e outro com args.
sua super não implementa Serializable…

então temos…

segundo a regra da des-serialização diz que se sua super classe (no caso Animal) NÂO implementa a interface… então qnd vc fizer a des-serialização a JVM vai chamar o construtor da sua Super…
portanto se vc comentar o construtor padrão ele não vai ter um construtor para chamar (isso pq ele utiliza o default [sem args]) e devido a nossa regrinha de sobrecarga de construtores q diz q ao sobrecarregar um const. vc perdera o default… então acontece isso ^^

bom esse e meu ponto de vista…

sera q eu certo -.-’

bom oq vale e participar ne… XD

flw t+

Criado 23 de outubro de 2008
Ultima resposta 17 de nov. de 2008
Respostas 7
Participantes 6