Pergunta

Em java, se uma classe implementa Serializable mas é abstrata, deveria ter um serialVersionUID longa declarado, ou que as subclasses só exigem isso?

Neste caso, é de fato a intenção de que todos os sub classes de lidar com a serialização como o propósito do tipo é para ser usado em chamadas RMI.

Foi útil?

Solução

O serialVersionUID é fornecido para determinar a compatibilidade entre um objeto deseralized ea versão atual da classe. Como tal, não é realmente necessário na primeira versão de uma classe, ou, neste caso, em uma classe base abstrata. Você nunca terá uma instância dessa classe abstrata para serializar / desserializar, por isso não precisa de um serialVersionUID.

(Claro, ele faz gerar um aviso do compilador, o que você quer se livrar de, certo?)

Acontece comentário james está correto. O serialVersionUID de uma classe base abstrata não se propagado para subclasses. À luz disso, você do precisa do serialVersionUID em sua classe de base.

O código de teste:

import java.io.Serializable;

public abstract class Base implements Serializable {

    private int x = 0;
    private int y = 0;

    private static final long serialVersionUID = 1L;

    public String toString()
    {
        return "Base X: " + x + ", Base Y: " + y;
    }
}



import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Sub extends Base {

    private int z = 0;

    private static final long serialVersionUID = 1000L;

    public String toString()
    {
        return super.toString() + ", Sub Z: " + z;
    }

    public static void main(String[] args)
    {
        Sub s1 = new Sub();
        System.out.println( s1.toString() );

        // Serialize the object and save it to a file
        try {
            FileOutputStream fout = new FileOutputStream("object.dat");
            ObjectOutputStream oos = new ObjectOutputStream(fout);
            oos.writeObject( s1 );
            oos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        Sub s2 = null;
        // Load the file and deserialize the object
        try {
            FileInputStream fin = new FileInputStream("object.dat");
            ObjectInputStream ois = new ObjectInputStream(fin);
            s2 = (Sub) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println( s2.toString() );
    }
}

Execute o principal em Sub uma vez para obtê-lo para criar e salvar um objeto. Em seguida, mudar o serialVersionUID na classe Base, comente as linhas em principal que salvar o objeto (por isso não salva-lo novamente, você apenas deseja carregar o antigo), e executá-lo novamente. Isso resultará em uma exceção

java.io.InvalidClassException: Base; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

Outras dicas

Sim, em geral, pela mesma razão que qualquer outra classe precisa de um ID de série - para evitar um ser gerado por ele. Basicamente qualquer classe (não interface) que implementa serializável deve definir de série id versão ou corre o risco de erros de-serialização quando a mesma compilação .class não está nas JVMs de cliente e servidor.

Existem outras opções, se você está tentando fazer algo extravagante. Eu não tenho certeza do que você quer dizer com "é intenção dos sub aulas ...". Você vai escrever métodos de serialização personalizadas (ex. WriteObject, readObject)? Se assim for, há outras opções para lidar com uma classe super.

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

HTH Tom

Na verdade, apontando para fora da ligação de Tom se serialVersionID falta é realmente calculado por serialização de tempo de execução ou seja, não durante a compilação

Se uma classe serializável não explicitamente declarar um serialVersionUID, em seguida, o tempo de execução serialização irá calcular um valor serialVersionUID padrão para essa classe com base em vários aspectos da classe ...

Isso torna as coisas ainda mais complicadas com diferentes versões do JRE.

Conceitualmente, o olhar dados serializados como esta:

subClassData(className + version + fieldNames + fieldValues)
parentClassData(className + version + fieldNames + fieldValues)
... (up to the first parent, that implements Serializable)

Assim, quando você desserializar, incompatibilidade na versão em qualquer uma das classes na hierarquia faz com que a desserialização a falhar. Nada é armazenado para interfaces, por isso não há necessidade de especificar a versão para eles.

Resposta: sim, você precisa fornecer serialVersionUID na classe abstrata de base também. Mesmo se ele não tem campos (className + version são armazenados mesmo se não houver campos).

Além disso, observe o seguinte:

  1. Se a classe não tem um campo, que é encontrado nos dados serializados (um campo removido), é ignorado.
  2. Se a classe tem um campo, que não está presente nos dados serializados (um novo campo), ele é definido como 0 / / null falsa (não para o valor padrão como seria de esperar).
  3. se um campo muda tipo de dados, o valor desserializado deve ser atribuído para o novo tipo. Por exemplo. se você tivesse um campo Object com valor String, mudando o tipo de campo para String terá êxito, mas mudando para Integer não. No entanto, alterar campo de int para long não vai funcionar, mesmo que você pode atribuir valor int a variável long.
  4. Se subclasse não se estende a classe principal, que se estende nos dados em série, que é ignorado (como no caso 1).
  5. Se uma subclasse agora se estende uma classe, que não é encontrado em dados serializados, campos de classe pai são restaurados com o valor 0 / false / null (como no caso 2).

Em palavras simples: você pode reordenar campos, adicionar e removê-los, até mesmo alterar a hierarquia de classes. Você não deve renomear campos ou classes (não irá falhar, mas os valores não será desserializado). Você não pode mudar o tipo de campos com tipo primitivo, e você pode mudar campos de tipo de referência, desde que o novo tipo pode ser atribuído a partir de todos os valores.

. Nota: Se a classe base não implementa Serializable e só a subclasse faz, então campos da classe base se comportaria como transient

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top