Por que o Java possui campos transitórios?


Respostas:


1673

A transientpalavra-chave em Java é usada para indicar que um campo não deve fazer parte do processo de serialização (que significa salvo, como em um arquivo).

Na Especificação da Linguagem Java, Java SE 7 Edition , Seção 8.3.1.3. transientCampos :

As variáveis ​​podem ser marcadas transientpara indicar que não fazem parte do estado persistente de um objeto.

Por exemplo, você pode ter campos derivados de outros campos e deve ser feito apenas de forma programática, em vez de persistir o estado via serialização.

Aqui está uma GalleryImageclasse que contém uma imagem e uma miniatura derivada da imagem:

class GalleryImage implements Serializable
{
    private Image image;
    private transient Image thumbnailImage;

    private void generateThumbnail()
    {
        // Generate thumbnail.
    }

    private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException
    {
        inputStream.defaultReadObject();
        generateThumbnail();
    }    
}

Neste exemplo, thumbnailImageé uma imagem em miniatura gerada chamando o generateThumbnailmétodo

O thumbnailImagecampo é marcado como transient, portanto, apenas o original imageé serializado em vez de persistir tanto na imagem original quanto na miniatura. Isso significa que seria necessário menos armazenamento para salvar o objeto serializado. (Obviamente, isso pode ou não ser desejável, dependendo dos requisitos do sistema - este é apenas um exemplo.)

No momento da desserialização, o readObjectmétodo é chamado para executar quaisquer operações necessárias para restaurar o estado do objeto de volta ao estado em que a serialização ocorreu. Aqui, a miniatura precisa ser gerada, para que o readObjectmétodo seja substituído para que a miniatura seja gerada chamando o generateThumbnailmétodo.

Para obter informações adicionais, o artigo Descubra os segredos do Java Serialization API (originalmente disponível na Sun Developer Network) possui uma seção que discute o uso e apresenta um cenário em que a transientpalavra-chave é usada para impedir a serialização de determinados campos.


221
Mas por que é uma palavra-chave e não uma anotação @DoNotSerialize?
Elazar Leibovich 26/03

333
Eu acho que isso pertence a uma época em que não havia anotações em Java.
precisa saber é o seguinte

46
Acho estranho que serializável seja interno ao Java. Ele pode ser implementado como uma interface ou classe abstrata que requer que os usuários substituam os métodos de leitura e gravação.
caleb

7
@MJafar: readObject é geralmente encadeado em mecanismos de desserialização e, portanto, chamado automaticamente. Além disso, em muitos casos, você não precisa substituí-lo - a implementação padrão faz o truque.
Mike Adler

13
@caleb provavelmente porque lidar com formatos binários é incrivelmente doloroso em Java devido à falta de números inteiros não assinados.
rightfold

435

Antes de entender a transientpalavra - chave, é preciso entender o conceito de serialização. Se o leitor souber sobre serialização, pule o primeiro ponto.

O que é serialização?

Serialização é o processo de tornar o estado do objeto persistente. Isso significa que o estado do objeto é convertido em um fluxo de bytes para ser usado para persistir (por exemplo, armazenar bytes em um arquivo) ou transferir (por exemplo, enviar bytes pela rede). Da mesma maneira, podemos usar a desserialização para recuperar o estado do objeto de bytes. Este é um dos conceitos importantes na programação Java, porque a serialização é usada principalmente na programação de redes. Os objetos que precisam ser transmitidos pela rede precisam ser convertidos em bytes. Para esse fim, toda classe ou interface deve implementar a Serializableinterface. É uma interface de marcador sem nenhum método.

Agora, qual é a transientpalavra - chave e seu objetivo?

Por padrão, todas as variáveis ​​do objeto são convertidas em um estado persistente. Em alguns casos, convém evitar a persistência de algumas variáveis ​​porque não é necessário persistir essas variáveis. Então você pode declarar essas variáveis ​​como transient. Se a variável for declarada como transient, ela não será mantida. Esse é o principal objetivo da transientpalavra - chave.

Quero explicar os dois pontos acima com o seguinte exemplo:

package javabeat.samples;

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

class NameStore implements Serializable{
    private String firstName;
    private transient String middleName;
    private String lastName;

    public NameStore (String fName, String mName, String lName){
        this.firstName = fName;
        this.middleName = mName;
        this.lastName = lName;
    }

    public String toString(){
        StringBuffer sb = new StringBuffer(40);
        sb.append("First Name : ");
        sb.append(this.firstName);
        sb.append("Middle Name : ");
        sb.append(this.middleName);
        sb.append("Last Name : ");
        sb.append(this.lastName);
        return sb.toString();
    }
}

public class TransientExample{
    public static void main(String args[]) throws Exception {
        NameStore nameStore = new NameStore("Steve", "Middle","Jobs");
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("nameStore"));
        // writing to object
        o.writeObject(nameStore);
        o.close();

        // reading from object
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("nameStore"));
        NameStore nameStore1 = (NameStore)in.readObject();
        System.out.println(nameStore1);
    }
}

E a saída será a seguinte:

First Name : Steve
Middle Name : null
Last Name : Jobs

Nome do meio é declarado como transient, portanto, não será armazenado no armazenamento persistente.

Fonte


26
Este exemplo é retirado esse código, você pode lê-lo aqui: javabeat.net/2009/02/what-is-transient-keyword-in-java
Krishna

11
Esta parte me parece estranha e possivelmente confusa: "Isso significa que o estado do objeto é convertido em um fluxo de bytes e armazenado em um arquivo ". Parece-me que a maioria da serialização tempo não envolve escrever para um arquivo (caso em questão: os exemplos de redes que follow)
Garcia Hurtado

5
O exemplo é ruim, pois o nome do meio claramente não é uma propriedade transitória.
Raphael

1
@ Rafael Para mim, o exemplo é útil e pelo menos explica o conceito. Você daria algum exemplo melhor se estiver ciente?
Chaklader Asfak Arefe 5/11

@Yoda Poderíamos ter uma referência a um NameFormatterusado para dirigir toString(). Ou qualquer outra coisa relacionada à configuração, exibição ou lógica de negócios ... em oposição aos dados.
Raphael

84

Para permitir que você defina variáveis ​​que você não deseja serializar.

Em um objeto, você pode ter informações que não deseja serializar / persistir (talvez uma referência a um objeto de fábrica pai) ou talvez não faça sentido serializar. Marcá-los como 'transitórios' significa que o mecanismo de serialização ignorará esses campos.


36

Minha pequena contribuição:

O que é um campo transitório?
Basicamente, qualquer campo modificado com a transientpalavra-chave é um campo transitório.

Por que os campos transitórios são necessários em Java?
A transientpalavra-chave fornece algum controle sobre o processo de serialização e permite excluir algumas propriedades do objeto desse processo. O processo de serialização é usado para persistir objetos Java, principalmente para que seus estados possam ser preservados enquanto são transferidos ou inativos. Às vezes, faz sentido não serializar certos atributos de um objeto.

Quais campos você deve marcar como transitório?
Agora sabemos o propósito dotransientpalavra-chave e campos transitórios, é importante saber quais campos marcar como transitórios. Os campos estáticos também não são serializados; portanto, a palavra-chave correspondente também funcionaria. Mas isso pode arruinar o design da sua classe; é aqui que a transientpalavra - chave vem em socorro. Tento não permitir que os campos cujos valores possam ser derivados de outros sejam serializados, marco-os como transitórios. Se você possui um campo chamado interestcujo valor pode ser calculado a partir de outros campos ( principal, rate& time), não é necessário serializá-lo.

Outro bom exemplo é com a contagem de palavras do artigo. Se você estiver salvando um artigo inteiro, não há realmente necessidade de salvar a contagem de palavras, pois ela pode ser calculada quando o artigo é "desserializado". Ou pense em madeireiros;Logger As instâncias quase nunca precisam ser serializadas, para que possam se tornar transitórias.


63
Sua "frase simples" é apenas uma tautologia. Isso não explica nada. Você ficaria melhor sem ele.
Marquês de Lorne

1
Esta é uma boa explicação onde o campo deve sertransient
Chaklader Asfak Arefe

1
o campo de interesse e a contagem de palavras são bons exemplos de campos transitórios.
Tarun

1
Outro bom caso de uso: se seu objeto possui componentes como soquetes e se você deseja serializar, o que acontece com o soquete? Se persistisse, depois de desserializar o que o soquete estaria segurando? Faz sentido fazer essa tomada objeto comotransient
Mohammed Siddiq

28

Uma transientvariável é uma variável que pode não ser serializada.

Um exemplo de quando isso pode ser útil que vem à mente é: variáveis ​​que só fazem sentido no contexto de uma instância de objeto específica e que se tornam inválidas depois de serializar e desserializar o objeto. Nesse caso, é útil que essas variáveis ​​se tornem, nullpara que você possa reinicializá-las com dados úteis quando necessário.


sim, algo como membros de campo "senha ou crediCardPin" de uma classe.
Mateen

17

transienté usado para indicar que um campo de classe não precisa ser serializado. Provavelmente, o melhor exemplo é um Threadcampo. Geralmente, não há razão para serializar a Thread, pois seu estado é muito "específico do fluxo".


Corrija-me se eu estiver errado, mas o Thread não é serializável, portanto será ignorado de qualquer maneira?
TFennis

3
@TFennis: Se uma classe serializável Areferenciar uma classe não serializável B(como Threadno seu exemplo), Amarque a referência, pois o transientXOR deve substituir o processo de serialização padrão para fazer algo razoável com o BXOR, assumindo que apenas as subclasses serializáveis Bsão realmente referenciadas (portanto, a subclasse real deve cuidar de seu pai "ruim" B). O XOR aceita que a serialização falhará. Em apenas um caso (marcado como transitório) Bé automaticamente e silenciosamente ignorado.
AH

3
@TFennis Não, isso causará uma exceção.
Marquês de Lorne

1
@AH: Por que XOR? Eu acho que o código que fez qualquer combinação dessas coisas funcionaria, e algumas combinações podem ser úteis (por exemplo, substituir o processo de serialização padrão pode ser útil mesmo que apenas as subclasses serializáveis ​​de B sejam referenciadas e vice-versa).
Supercat

15

Sistemas de serialização diferentes do java nativo também podem usar esse modificador. O Hibernate, por exemplo, não persistirá nos campos marcados com @Transient ou com o modificador transitório . A terracota também respeita esse modificador.

Acredito que o significado figurativo do modificador é "esse campo é apenas para uso na memória. Não persista ou mova-o para fora desta VM específica de forma alguma. É não-portátil". ou seja, você não pode confiar em seu valor em outro espaço de memória da VM. Muito parecido com volátil significa que você não pode confiar em certa memória e semântica de threads.


14
Eu acho que transientnão seria uma palavra-chave se fosse projetada no momento. Eles provavelmente usariam uma anotação.
Joachim Sauer


7

Antes de responder a esta pergunta, devo explicar a SERIALIZAÇÃO , porque se você entender o que significa serialização em computadores científicos, poderá entender facilmente essa palavra-chave.

Serialização Quando um objeto é transferido pela rede / salvo na mídia física (arquivo, ...), o objeto deve ser "serializado". A serialização converte a série de objetos de status de bytes. Esses bytes são enviados na rede / salvos e o objeto é recriado a partir desses bytes.
Exemplo

public class Foo implements Serializable 
{
 private String attr1;
 private String attr2;
 ...
}

Agora, SE QUER NÃO TRANSFERIR / SALVAR o campo deste objeto , SO , você pode usar a palavra-chave transient

private transient attr2;

Exemplo


6

É necessário quando você não deseja compartilhar alguns dados confidenciais que acompanham a serialização.


7
Existem casos de uso diferentes de dados confidenciais nos quais você pode não querer serializar um campo. Por exemplo, você provavelmente nunca desejaria serializar um Thread(crédito para @AH por exemplo); nesse caso, você o marcaria como transitório. No entanto, um encadeamento não é um dado sensível por si só, não faz sentido lógico serializá-lo (e não é serializável).
Glen3b

1
@ glen3b Esse caso não é excluído por esta resposta. Certamente é necessário, pois as coisas estão no caso mencionado no pôster.
Marquês de Lorne

3

De acordo com o significado transitório do google ==, durando apenas por um curto período de tempo; impermanente.

Agora, se você deseja tornar qualquer coisa transitória em java, use a palavra-chave transitória.

Q: onde usar transitório?

R: Geralmente em java, podemos salvar dados em arquivos adquirindo-os em variáveis ​​e gravando essas variáveis ​​em arquivos, esse processo é conhecido como serialização. Agora, se quisermos evitar que dados variáveis ​​sejam gravados em arquivo, nós a tornaremos transitória.

transient int result=10;

Nota: variáveis ​​transitórias não podem ser locais.


0

Simplificando, a palavra-chave java transitória protege os campos de Serialize, pois seus campos não transitórios se contrapõem.

Nesse trecho de código, nossa classe abstrata BaseJob implementa a interface serializável, estendemos a partir do BaseJob, mas não precisamos serializar as fontes de dados remotas e locais; serialize apenas os campos organizationName e isSynced.

public abstract class BaseJob implements Serializable{
   public void ShouldRetryRun(){}
}

public class SyncOrganizationJob extends BaseJob {

   public String organizationName;
   public Boolean isSynced

   @Inject transient RemoteDataSource remoteDataSource;
   @Inject transient LocalDaoSource localDataSource;

   public SyncOrganizationJob(String organizationName) {
     super(new 
         Params(BACKGROUND).groupBy(GROUP).requireNetwork().persist());

      this.organizationName = organizationName;
      this.isSynced=isSynced;

   }
}

0

Código de exemplo simplificado para palavra-chave transitória.

import java.io.*;

class NameStore implements Serializable {
    private String firstName, lastName;
    private transient String fullName;

    public NameStore (String fName, String lName){
        this.firstName = fName;
        this.lastName = lName;
        buildFullName();
    }

    private void buildFullName() {
        // assume building fullName is compuational/memory intensive!
        this.fullName = this.firstName + " " + this.lastName;
    }

    public String toString(){
        return "First Name : " + this.firstName
            + "\nLast Name : " + this.lastName
            + "\nFull Name : " + this.fullName;
    }

    private void readObject(ObjectInputStream inputStream)
            throws IOException, ClassNotFoundException
    {
        inputStream.defaultReadObject();
        buildFullName();
    }
}

public class TransientExample{
    public static void main(String args[]) throws Exception {
        ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("ns"));
        o.writeObject(new NameStore("Steve", "Jobs"));
        o.close();

        ObjectInputStream in = new ObjectInputStream(new FileInputStream("ns"));
        NameStore ns = (NameStore)in.readObject();
        System.out.println(ns);
    }
}

0

Um campo declarado com modificador transitório não participará do processo serializado. Quando um objeto é serializado (salvo em qualquer estado), os valores de seus campos transitórios são ignorados na representação serial, enquanto o campo diferente dos campos transitórios participará do processo de serialização. Esse é o principal objetivo da palavra-chave transitória.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.