¿Por qué Java tiene campos transitorios?


¿Por qué Java tiene campos transitorios ?



Answers



La palabra clave transient en Java se usa para indicar que un campo no debe ser serializado.

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

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

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

Aquí hay una clase GalleryImage 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, thumbnailImage es una imagen en miniatura que se genera al invocar el método generateThumbnail .

El campo thumbnailImage está marcado como transient , por lo que solo la image original se serializa en lugar de persistir tanto en la imagen original como en 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 según los requisitos del sistema; esto es solo un ejemplo).

En el momento de la deserialización, se llama al método readObject para realizar cualquier operación necesaria para restablecer el estado del objeto al estado en el que se produjo la serialización. Aquí, la miniatura debe generarse, por lo que el método readObject se reemplaza para que la miniatura se genere llamando al método generateThumbnail .

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




Antes de entender la palabra clave transient , uno tiene que entender el concepto de serialización. Si el lector conoce 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 y se almacena en un archivo. Del mismo modo, podemos utilizar la deserialización para recuperar el estado del objeto desde bytes. Este es uno de los conceptos importantes en la programación de Java porque la serialización se utiliza 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 interfaz Serializable . Es una interfaz de marcador sin ningún método.

Ahora, ¿cuál es la palabra clave transient 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 persistir algunas variables porque no tiene la necesidad de mantener esas variables. Entonces puedes declarar esas variables como transient . Si la variable se declara transient , no se conservará. Ese es el objetivo principal de la palabra clave transient .

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

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

Fuente




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 realizar la serialización. Marcar estos como 'transitorios' significa que el mecanismo de serialización ignorará estos campos.




Mi pequeña contribución:

¿Qué es la variable transitoria en Java?
En una oración simple, cualquier variable que se modifique con la palabra clave transitoria se convierte en variable transitoria en java.

¿Por qué necesitamos una variable transitoria en Java?
La palabra clave transitoria le proporciona cierto control sobre el proceso de serialización y le brinda flexibilidad para excluir algunas de las propiedades del objeto del proceso de serialización. En algún momento tiene sentido no serializar ciertos atributos de un objeto, veremos qué variables no deberían ser serializadas y deberían hacerse transitorias en la próxima sección.

¿Qué variable debe marcar transitoria?
Dado que conocemos el propósito de la palabra clave transitoria o que tiene una variable transitoria, tiene sentido pensar qué variable debe marcarse como transitoria. Mi regla es que cualquier variable cuyo valor se puede calcular a partir de otras variables no requiere ser guardada. Por ejemplo, si tiene un campo llamado "interés" cuyo valor puede derivarse de otros campos, por ejemplo, principio, tasa, tiempo, etc., entonces no hay necesidad de serializarlo.
Otro ejemplo es el recuento de palabras, si está guardando un artículo, entonces no es necesario guardar el conteo de palabras, ya que se puede crear cuando el artículo se deserializa. Otro buen ejemplo de palabra clave transitoria es "Logger", ya que la mayoría de las veces tiene una instancia de registrador para iniciar sesión en Java, pero ciertamente no desea que la serialización sea correcta.




Una variable transitoria es una variable que puede no ser serializada.

Un ejemplo de cuándo esto podría ser útil que viene a la mente son 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 vuelvan nulas para que pueda reinicializarlas con datos útiles cuando sea necesario.




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




Porque no todas las variables son de naturaleza serializable




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 el modificador transitorio . Terracota también respeta este modificador.

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




La serialización es el proceso de guardar los estados de un objeto en un formato persistente (como flujo de archivos o base de datos) y luego restaurarlos desde la secuencia (deserialización). En Java, un objeto de una clase es serializable si la clase implementa la interfaz java.io.Serializable. Esta es una interfaz de marcador que le dice a la JVM que la clase es elegible para la serialización.

public class User implements Serializable {

    private static final long serialVersionUID = 1234L;

    private String username;
    private String email;
    private transient String password;
    private Date birthday;
    private int age;

    public User(String username, String email, String password, Date birthday,
            int age) {
        this.username = username;
        this.email = email;
        this.password = password;
        this.birthday = birthday;
        this.age = age;
    }

    public void printInfo() {
        System.out.println("username: " + username);
        System.out.println("email: " + email);
        System.out.println("password: " + password);
        System.out.println("birthday: " + birthday);
        System.out.println("age: " + age);
    }

    // getters and setters

}

Hay tres puntos importantes en esta clase de modelo: debe implementar la interfaz Serializable. De lo contrario, obtendremos una excepción java.io.NotSerializableException al intentar serializar un objeto de la clase. Una constante llamada serialVersionUID se declara y se le asigna un valor largo:

private static final long serialVersionUID = 1234L;

Esta es una constante convencional que debe declararse cuando una clase implementa la interfaz Serializable. La versión en serie del UID asegura fuertemente la compatibilidad entre las versiones serializadas y deserializadas de los objetos de una clase, porque el proceso de serialización y deserialización puede ocurrir en diferentes computadoras y sistemas. Aunque esta declaración es opcional, siempre se recomienda declarar el serialVersionUID para una clase serializable.

Tenga en cuenta que el campo de contraseña está marcado como transitorio:

private transient String password;

Porque no queremos almacenar la contraseña al serializar el objeto. La regla es que cuando una variable se marca como transitoria, su objeto no se serializará durante la serialización.

Una variable transitoria es una variable que puede no ser serializada. Utiliza la palabra clave transitoria para indicar a la máquina virtual Java que la variable indicada no es parte del estado persistente del objeto.

Los modificadores de acceso admitidos por Java son estáticos, finales, abstractos, sincronizados, nativos, volátiles, transitorios y strictfp.

La siguiente tabla proporciona la lista de especificadores y modificadores de acceso Java que se pueden aplicar a variables, métodos y clases.

SPECIFIER/MODIFIER  LOCAL VARIABLE  INSTANCEVARIABLE    METHOD   CLASS
public              NA              A                   A         A
protected           NA              A                   A         NA
default             A               A                   A         A
private             NA              A                   A         NA
final               A               A                   A         A
static              NA              A                   A         NA
synchronized        NA              NA                  A         NA
native              NA              NA                  A         NA
volatile            NA              A                   NA        NA
transient           NA              A                   NA        NA
strictfp            NA              NA                  A         A



Antes de responder a esta pregunta, debo explicarte la SERIALIZACIÓN , porque si entiendes lo que significa la serialización en una computadora científica, puedes entender 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 la serie de objetos de estado de byte. Estos bytes se envían a 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 NO QUIERES TRANSFERIR / GUARDAR el campo de este objeto SO , puedes usar palabra clave transient

private transient attr2;

Ejemplo




Es necesario cuando no desea compartir algunos datos confidenciales que acompañan a la serialización.




según el significado transitorio de google == que dura solo por un corto tiempo; impermanente.

ahora si quieres hacer algo transitorio en java usa 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 un archivo, haríamos que esa variable sea transitoria.

transient int result = 10;

Nota: las variables transitorias no pueden ser locales.




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, se extiende desde BaseJob pero no necesitamos serializar las fuentes de datos locales y remotas; serializar solo los campos organizationName y 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;

   }
}