¿Por qué Java tiene campos transitorios?

Respuestas:

1673

La transientpalabra clave en Java se usa para indicar que un campo no debe ser parte del proceso de serialización (lo que significa guardado, como en un archivo).

De la Especificación del lenguaje Java, Java SE 7 Edition , Sección 8.3.1.3. transientCampos :

Las variables pueden marcarse transientpara indicar que no son parte del estado persistente de un objeto.

Por ejemplo, puede tener campos que se derivan de otros campos, y solo debe hacerse de manera programática, en lugar de que el estado se mantenga a través de la serialización.

Aquí hay una GalleryImageclase que contiene una imagen y una miniatura derivada de la imagen:

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

En este ejemplo, thumbnailImagees una imagen en miniatura que se genera al invocar el generateThumbnailmétodo.

El thumbnailImagecampo está marcado como transient, por lo que solo el original imagese serializa en lugar de persistir tanto la imagen original como la imagen en miniatura. Esto significa que se necesitaría menos almacenamiento para guardar el objeto serializado. (Por supuesto, esto puede o no ser deseable dependiendo de los requisitos del sistema; esto es solo un ejemplo).

En el momento de la deserialización, readObjectse llama al método para realizar cualquier operación necesaria para restaurar el estado del objeto al estado en el que ocurrió la serialización. Aquí, la miniatura debe generarse, por lo que el readObjectmétodo se anula para que la miniatura se genere llamando al generateThumbnailmétodo.

Para obtener información adicional, el artículo Descubre los secretos del API de serialización de Java (que originalmente estaba disponible en Sun Developer Network) tiene una sección que analiza el uso y presenta un escenario en el que la transientpalabra clave se usa para evitar la serialización de ciertos campos.

Coobird
fuente
221
Pero, ¿por qué es una palabra clave y no una anotación @DoNotSerialize?
Elazar Leibovich
333
Supongo que esto es propiedad de una época en la que no había anotaciones en Java.
Peter Wippermann
46
Me resulta extraño que serializable sea interno de Java. Se puede implementar como una interfaz o clase abstracta que requiere que los usuarios anulen los métodos de lectura y escritura.
caleb
77
@MJafar: readObject generalmente se encadena a mecanismos de deserialización y, por lo tanto, se llama automáticamente. Además, en muchos casos no es necesario anularlo; la implementación predeterminada hace el truco.
Mike Adler
13
@caleb probablemente porque tratar con formatos binarios usted mismo es increíblemente doloroso en Java debido a la falta de enteros sin signo.
derecha el
435

Antes de comprender la transientpalabra clave, uno debe comprender el concepto de serialización. Si el lector sabe acerca de la serialización, omita el primer punto.

¿Qué es la serialización?

La serialización es el proceso de hacer que el estado del objeto sea persistente. Eso significa que el estado del objeto se convierte en una secuencia de bytes que se utilizará para persistir (por ejemplo, almacenar bytes en un archivo) o transferir (por ejemplo, enviar bytes a través de una red). Del mismo modo, podemos usar la deserialización para recuperar el estado del objeto desde bytes. Este es uno de los conceptos importantes en la programación Java porque la serialización se usa principalmente en la programación de redes. Los objetos que deben transmitirse a través de la red deben convertirse en bytes. Para ese propósito, cada clase o interfaz debe implementar la Serializableinterfaz. Es una interfaz de marcador sin ningún método.

Ahora, ¿cuál es la transientpalabra clave y su propósito?

Por defecto, todas las variables del objeto se convierten en un estado persistente. En algunos casos, es posible que desee evitar la persistencia de algunas variables porque no tiene la necesidad de persistir esas variables. Entonces puedes declarar esas variables como transient. Si la variable se declara como transient, entonces no será persistente. Ese es el propósito principal de la transientpalabra clave.

Quiero explicar los dos puntos anteriores con el siguiente ejemplo:

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

Y la salida será la siguiente:

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

Eltransient segundo nombre se declara como , por lo que no se almacenará en el almacenamiento persistente.

Fuente

Rahul Saxena
fuente
26
Este ejemplo está tomado de este código, puede leerlo aquí: javabeat.net/2009/02/what-is-transient-keyword-in-java
Krishna
11
Esta parte me parece extraña y posiblemente confusa: "Eso significa que el estado del objeto se convierte en una secuencia de bytes y se almacena en un archivo ". Me parece que la mayoría de las veces la serialización no implica escribir en un archivo (ejemplo: los ejemplos de redes que siguen)
Garcia Hurtado
55
El ejemplo es malo, ya que el segundo nombre claramente no es una propiedad transitoria.
Rafael
1
@Raphael Para mí, el ejemplo es útil y al menos explica el concepto. ¿Darías algún ejemplo mejor si te das cuenta?
Chaklader Asfak Arefe
@Yoda Podríamos tener una referencia a un NameFormatterusado para conducir toString(). O cualquier otra cosa relacionada con la configuración, o la visualización, o la lógica empresarial, ... a diferencia de los datos.
Raphael
84

Para permitirle definir variables que no desea serializar.

En un objeto puede tener información que no desea serializar / persistir (tal vez una referencia a un objeto de fábrica principal), o tal vez no tenga sentido serializar. Marcarlos como 'transitorios' significa que el mecanismo de serialización ignorará estos campos.

Brian Agnew
fuente
36

Mi pequeña contribución:

¿Qué es un campo transitorio?
Básicamente, cualquier campo modificado con la transientpalabra clave es un campo transitorio.

¿Por qué se necesitan campos transitorios en Java?
La transientpalabra clave le da cierto control sobre el proceso de serialización y le permite excluir algunas propiedades de objeto de este proceso. El proceso de serialización se utiliza para persistir objetos Java, principalmente para que sus estados puedan conservarse mientras se transfieren o están inactivos. A veces, tiene sentido no serializar ciertos atributos de un objeto.

¿Qué campos debes marcar como transitorios?
Ahora sabemos el propósito de latransientpalabras clave y campos transitorios, es importante saber qué campos marcar como transitorios. Los campos estáticos tampoco están serializados, por lo que la palabra clave correspondiente también funcionaría. Pero esto podría arruinar su diseño de clase; Aquí es donde la transientpalabra clave viene al rescate. Intento no permitir que se serialicen los campos cuyos valores pueden derivarse de otros, por lo que los marco como transitorios. Si tiene un campo llamado interestcuyo valor se puede calcular a partir de otros campos ( principal, rate& time), no es necesario serializarlo.

Otro buen ejemplo es con el recuento de palabras del artículo. Si está guardando un artículo completo, realmente no es necesario guardar el recuento de palabras, ya que se puede calcular cuando el artículo se "deserializa". O piense en los madereros;Logger Las instancias casi nunca necesitan ser serializadas, por lo que pueden hacerse transitorias.

Shreyos Adikari
fuente
63
Tu 'oración simple' es meramente una tautología. No explica nada. Estarías mejor sin él.
Marqués de Lorne
1
Esta es una buena explicación de dónde debería estar el campotransient
Chaklader Asfak Arefe
1
El campo de interés y el recuento de palabras son buenos ejemplos de campos transitorios.
Tarun
1
Otro buen caso de uso: si su objeto tiene componentes como zócalos y si desea serializar, ¿qué sucede con el zócalo? Si persistiera, después de deserializar, ¿qué aguantaría el zócalo? Tiene sentido hacer que ese objeto zócalo comotransient
Mohammed Siddiq
28

Una transientvariable es una variable que puede no ser serializada.

Un ejemplo de cuándo esto puede ser útil que viene a la mente es, las variables que solo tienen sentido en el contexto de una instancia de objeto específica y que se vuelven inválidas una vez que haya serializado y deserializado el objeto. En ese caso, es útil que esas variables se conviertan en su nulllugar para que pueda reinicializarlas con datos útiles cuando sea necesario.

Adrian Grigore
fuente
sí, algo como miembros de campo de "clase o crediCardPin" de una clase.
Mateen
17

transientse usa para indicar que un campo de clase no necesita ser serializado. Probablemente el mejor ejemplo es un Threadcampo. Por lo general, no hay razón para serializar a Thread, ya que su estado es muy 'específico del flujo'.

Andrei Ciobanu
fuente
Corríjame si me equivoco, pero Thread no es serializable, por lo que se omitirá de todos modos.
TFennis
3
@TFennis: si una clase serializable hace Areferencia a una clase no serializable B(como Threaden su ejemplo), entonces Adebe marcar la referencia como transientXOR debe anular el proceso de serialización predeterminado para hacer algo razonable con BXOR suponiendo que solo las subclases serializables Bestán realmente referenciadas (por lo que la subclase real debe cuidar a su padre "malo" B) XOR acepta que la serialización fallará. En solo un caso (marcado como transitorio) Bse omite automática y silenciosamente.
AH
3
@TFennis No, causará una excepción.
Marqués de Lorne
1
@AH: ¿Por qué XOR? Creo que el código que hiciera cualquier combinación de esas cosas funcionaría, y algunas combinaciones podrían ser útiles (por ejemplo, anular el proceso de serialización predeterminado puede ser útil incluso si solo se hace referencia a las subclases serializables de B, y viceversa).
supercat
15

Los sistemas de serialización que no sean el java nativo también pueden usar este modificador. Hibernate, por ejemplo, no persistirá en los campos marcados con @Transient o con el modificador transitorio . La terracota también respeta este modificador.

Creo que el significado figurativo del modificador es "este campo es solo para uso en memoria. No lo persista ni lo mueva fuera de esta VM en particular de ninguna manera. No es portátil". es decir, no puede confiar en su valor en otro espacio de memoria de VM. Al igual que volátil significa que no puede confiar en cierta memoria y semántica de subprocesos.

DragonFax
fuente
14
Creo que esa transientno sería una palabra clave si fuera diseñada en este momento. Probablemente usarían una anotación.
Joachim Sauer
9

Porque no todas las variables son de naturaleza serializable

Silfverstrom
fuente
42
Proporcione más información cuando responda.
Danny Gloudemans
7

Antes de responder a esta pregunta, debo explicarle la SERIALIZACIÓN , porque si comprende lo que significa la serialización en informática, puede comprender fácilmente esta palabra clave.

Serialización Cuando un objeto se transfiere a través de la red / se guarda en un medio físico (archivo, ...), el objeto debe ser "serializado". La serialización convierte series de objetos de estado de bytes. Estos bytes se envían en la red / se guardan y el objeto se vuelve a crear a partir de estos bytes.
Ejemplo

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

Ahora, SI DESEA NO TRANSFERIR / GUARDAR el campo de este objeto SO , puede usar la palabra clave transient

private transient attr2;

Ejemplo

BERGUIGA Mohamed Amine
fuente
6

Es necesario cuando no desea compartir algunos datos confidenciales que van con la serialización.

Setzamora
fuente
77
Hay casos de uso distintos de los datos confidenciales en los que es posible que no desee serializar un campo. Por ejemplo, probablemente nunca desee serializar un Thread(crédito a @AH por ejemplo), en cuyo caso lo marcaría como transitorio. Sin embargo, un hilo no es información confidencial en sí misma, simplemente no tiene sentido lógico serializarlo (y no es serializable).
glen3b
1
@ glen3b Ese caso no está excluido por esta respuesta. Ciertamente es necesario como están las cosas en el caso mencionado en el póster.
Marqués de Lorne
3

Según el significado transitorio de Google == que dura solo un corto tiempo; impermanente.

Ahora, si desea hacer algo transitorio en java, use una palabra clave transitoria.

P: ¿dónde usar transitorios?

R: Generalmente, en Java podemos guardar datos en archivos adquiriéndolos en variables y escribiendo esas variables en archivos, este proceso se conoce como serialización. Ahora, si queremos evitar que los datos variables se escriban en el archivo, haríamos que esa variable sea transitoria.

transient int result=10;

Nota: las variables transitorias no pueden ser locales.

Mateen
fuente
0

En pocas palabras, la palabra clave java transitoria protege los campos de Serialize como sus contrapartes de campos no transitorios.

En este fragmento de código, nuestra clase abstracta BaseJob implementa la interfaz serializable, ampliamos desde BaseJob pero no necesitamos serializar las fuentes de datos remotas y locales; serializar solo los 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;

   }
}
nyulan
fuente
0

Código de ejemplo simplificado para transient-keyword.

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);
    }
}
Habeeb Perwad
fuente
0

Un campo que se declara con un modificador transitorio no participará en el proceso serializado. Cuando un objeto se serializa (se guarda en cualquier estado), los valores de sus campos transitorios se ignoran en la representación en serie, mientras que el campo que no sea transitorio tomará parte en el proceso de serialización. Ese es el propósito principal de la palabra clave transitoria.

Vishal Sheth
fuente