提问



为什么Java有瞬态字段?

最佳参考


Java中的transient关键字用于指示不应序列化字段。


来自Java语言规范,Java SE 7 Edition,第8.3.1.3节。 transient字段:[37] [38]



  变量可以标记transient
  表明他们不属于
  对象的持久状态。



例如,您可能具有从其他字段派生的字段,并且只应以编程方式执行,而不是通过序列化保持状态。


这是一个GalleryImage类,它包含一个图像和从图像派生的缩略图:


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


在此示例中,thumbnailImage是通过调用generateThumbnail方法生成的缩略图图像。


thumbnailImage字段标记为transient,因此只有原始image被序列化而不是同时保留原始图像和缩略图图像。这意味着保存序列化对象所需的存储空间更少。 (当然,根据系统的要求,这可能是也可能不合适 - 这只是一个例子。)


在反序列化时,调用readObject方法来执行将对象状态恢复到序列化发生状态所需的任何操作。这里需要生成缩略图,因此覆盖readObject方法,以便通过调用generateThumbnail方法生成缩略图。[39]


有关其他信息,请参阅发现Java序列化API的秘密一文(最初在Sun Developer Network上提供),其中有一节讨论了transient关键字用于防止序列化的用法并提供了一个场景。某些领域。[40]

其它参考1


在理解transient关键字之前,必须先了解序列化的概念。如果读者知道序列化,请跳过第一点。


什么是序列化?



序列化是使对象的状态持久化的过程。这意味着对象的状态被转换为字节流并存储在文件中。同样,我们可以使用反序列化来恢复对象的从字节状态。这是Java编程中的重要概念之一,因为序列化主要用于网络编程。需要通过网络传输的对象必须转换为字节。为此,每个类或接口都必须实现Serializable接口。它是一个没有任何方法的标记界面。[41]


现在transient关键字及其用途是什么?



默认情况下,所有对象的变量都会转换为持久状态。在某些情况下,您可能希望避免持久化某些变量,因为您不需要持久保存这些变量。所以你可以将这些变量声明为transient。如果变量声明为transient,那么它将不会被持久化。这是transient关键字的主要目的。


我想通过以下示例解释上述两点:


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


输出将如下:


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


中间名被声明为transient,因此它不会存储在持久存储中。


[42]

其它参考2


允许您定义不想序列化的变量。


在一个对象中,您可能拥有不想序列化/持久化的信息(可能是对父工厂对象的引用),或者序列化可能没有意义。将这些标记为瞬态意味着序列化机制将忽略这些字段。

其它参考3


我的小贡献:


Java中的瞬态变量是什么?

简单地说,任何使用transient关键字修改的变量都会成为java中的瞬态变量。


为什么我们需要java中的瞬态变量?

Transient关键字为您提供了对序列化过程的一些控制,并使您可以灵活地从序列化过程中排除某些对象属性。有些时候,不管序列化对象的某些属性是否有意义,我们将看到哪些变量不应该被序列化,并且应该在下一节中变为瞬态。


您应该将哪个变量标记为瞬态?

由于我们知道临时关键字或具有瞬态变量的目的,因此考虑哪个变量应该标记为瞬态是有意义的。我的规则是,任何其值可以从其他变量计算的变量都不需要保存。例如,如果你有一个名为interest的字段,其值可以从其他字段派生,例如原则,速率,时间等,那么那里不需要序列化它。

另一个例子是单词计数,如果您正在保存文章,则无需保存单词计数,因为它可以在文章被反序列化时创建。 transient关键字的另一个很好的例子是Logger,因为大部分时间你都有用于登录Java的记录器实例,但你肯定不希望它序列化正确吗?

其它参考4


transient变量是可能未序列化的变量。


想到这可能有用的一个例子是,变量只在特定对象实例的上下文中有意义,并且在序列化和反序列化对象后变为无效。在这种情况下,让这些变量变为null非常有用,这样您就可以在需要时使用有用的数据重新初始化它们。

其它参考5


transient用于表示类字段不需要序列化。
可能最好的例子是Thread字段。通常没有理由将序列化Thread,因为它的状态非常特定于流程。

其它参考6


因为并非所有变量都具有可序列化的性质

其它参考7


除本机java之外的序列化系统也可以使用此修饰符。例如,Hibernate不会保留标有 @Transient 瞬态修饰符的字段。兵马俑也尊重这个修饰符。


我相信修饰符的比喻意思是此字段仅供内存使用。不要以任何方式持久存在或将其移出此特定VM。它是非便携的。即你不能依赖它在另一个虚拟机内存空间中的价值。很像 volatile 意味着你不能依赖某些内存和线程语义。

其它参考8


序列化是以持久格式(例如文件流或数据库)保存对象状态,然后从流中恢复它们(反序列化)的过程。
在Java中,如果类实现java.io.Serializable接口,则类的对象是可序列化的。这是一个标记接口,它告诉JVM该类有资格进行序列化。


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

}


此模型类中有三个重点:
它必须实现Serializable接口。否则,在尝试序列化类的对象时,我们将得到java.io.NotSerializableException。
声明了一个名为serialVersionUID的常量并赋值为long值:


private static final long serialVersionUID = 1234L;


这是一个常规常量,应该在类实现Serializable接口时声明。串行版本UID强烈确保类的对象序列化和反序列化版本之间的兼容性,因为序列化和反序列化的过程可能发生在不同的计算机和系统上。尽管此声明是可选的,但始终建议为可序列化类声明serialVersionUID。


请注意,密码字段标记为瞬态:


private transient String password;


因为我们不希望在序列化对象时存储密码。规则是,当变量标记为瞬态时,其对象在序列化期间不会被序列化。


瞬态变量是可能未序列化的变量。您可以使用transient关键字向Java虚拟机指示指示的变量不是对象持久状态的一部分。


Java支持的访问修饰符是static,final,abstract,synchronized,native,volatile,transient和strictfp。


下表给出了可以应用于变量,方法和类的访问说明符和修饰符Java列表。


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

其它参考9


在回答这个问题之前,我必须向您解释 SERIALIZATION ,因为如果您了解科学计算机中序列化的含义,您就可以轻松理解这个关键字。


序列化
当对象通过网络传输/保存在物理介质(文件,...)上时,该对象必须序列化。序列化转换字节状态对象系列。这些字节在网络上发送/保存,并从这些字节重新创建对象
实施例



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


现在,如果您不想 TRANSFERT / SAVED 此对象 SO 字段,您可以使用关键字 transient


private transient attr2;


示例

其它参考10


当你不想分享一些与序列化有关的敏感数据时,需要它。

其它参考11


按照谷歌
暂时意义==只持续很短的时间;暂时的。


现在如果想在java中做任何瞬态使用transient关键字。


问:在哪里使用瞬态?


答:通常在java中,我们可以通过在变量中获取数据并将这些变量写入文件来将数据保存到文件中,此过程称为序列化。现在,如果我们想要避免将可变数据写入文件,我们会将该变量设置为瞬态。


transient int result=10;


注意:瞬态变量不能是本地的。

其它参考12


简单地说,瞬态java关键字保护来自Serialize的字段作为非瞬态字段计数器部分。


在这段代码片段中,我们的抽象类BaseJob实现了Serializable接口,我们从BaseJob扩展,但我们不需要序列化远程和本地数据源;仅序列化organizationName和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;

   }
}