为什么Java有瞬态字段?


Answers:


1672

transientJava中关键字用于指示字段不应该是系列化的一部分(这意味着保存,一个文件)的过程。

Java语言规范,Java SE 7中版第8.3.1.3节。transient领域

可以标记变量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方法来生成缩略图。

有关更多信息,“ 发现Java序列化API的秘密”一文(最初在Sun Developer Network上提供)中的一节讨论了的用法,并提出了transient使用关键字防止某些字段序列化的方案。


221
但是,为什么它是关键字而不是注释@DoNotSerialize
Elazar Leibovich

333
我想这是Java时代没有注释的时代。
Peter Wippermann

46
我觉得奇怪的是,可序列化是Java内部的。它可以实现为接口或抽象类,要求用户重写读取和写入方法。
caleb 2012年

7
@MJafar:readObject通常链接到反序列化机制中,因此会自动调用。此外,在许多情况下,您不需要覆盖它-默认实现可以解决问题。
Mike Adler

13
@caleb可能是因为在Java中,由于缺少无符号整数,所以自己处理二进制格式非常痛苦。
2014年

434

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

什么是序列化?

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

现在,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,因此不会存储在持久性存储中。

资源


25
本示例摘自该代码,您可以在此处阅读:javabeat.net/2009/02/what-is-transient-keyword-in-java
克里希纳,

11
这部分让我感到奇怪,并可能引起混淆:“这意味着对象的状态将转换为字节流并存储在文件中 ”。在我看来,大多数情况下序列化不涉及写入文件(例如:后续的网络示例)
Garcia Hurtado 2014年

5
该示例是一个不好的示例,因为中间名显然不是过渡属性。
拉斐尔

1
@Raphael对我而言,该示例很有帮助,并至少说明了这一概念。如果您知道,您会提供更好的示例吗?
Chaklader Asfak Arefe

@Yoda我们可能会引用一个NameFormatter二手车toString()。或与配置或查看或业务逻辑相关的其他任何信息,与数据相反。
拉斐尔

84

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

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


36

我的小贡献:

什么是瞬态场?
基本上,任何用transient关键字修改的字段都是瞬态字段。

为什么在Java中需要瞬态字段?
transient关键字为您提供了序列化过程的一些控制,并允许您排除此过程中的一些对象属性。序列化过程通常用于持久化Java对象,以便在它们转移或不活动时可以保留它们的状态。有时,不序列化对象的某些属性是有意义的。

您应将哪些字段标记为瞬态?
现在我们知道了transient关键字和瞬态字段,了解哪些字段标记为瞬态很重要。静态字段也不会序列化,因此相应的关键字也可以解决问题。但这可能会破坏您的班级设计。这就是该transient关键字的目的所在。我尝试不允许将其值可以从其他值派生的字段进行序列化,因此我将它们标记为瞬态。如果您有一个名为interest的字段,其值可以从其他字段(principalratetime)中计算出来,则无需对其进行序列化。

另一个很好的例子是文章字数统计。如果要保存整篇文章,则实际上不需要保存字数,因为可以在对文章进行“反序列化”时进行计算。或考虑记录器;Logger 实例几乎不需要序列化,因此可以使其成为瞬态。


63
您的“简单句子”只是一个重言式。它什么也没解释。没有它,你会更好。
user207421

1
这是该字段应该在哪里的一个很好的解释transient
Chaklader Asfak Arefe'Nov

1
兴趣字段和字数统计是瞬态字段的很好示例。
塔伦

1
另一个很好的用例:如果您的对象具有套接字等组件,并且要序列化,那么套接字会发生什么?如果仍然存在,则在反序列化之后,套接字将保持什么状态?使该套接字对象成为transient
Mohammed Siddiq

28

一个 transient变量是可以不被序列化的变量。

一个可能在何时有用的示例是,仅在特定对象实例的上下文中有意义的变量,并且在对对象进行序列化和反序列化后这些变量将变为无效。在这种情况下,null改用那些变量会很有用,这样您就可以在需要时用有用的数据重新初始化它们。


是的,有些东西,例如“密码或crediCardPin”类的成员。
MATEEN

17

transient用于表示不需要对类字段进行序列化。最好的例子可能是一个Thread领域。通常没有理由序列化一个Thread,因为它的状态非常“特定于流”。


如果我错了,请纠正我,但是Thread无法序列化,因此无论如何都会被跳过?
TFennis

3
@TFennis:如果可序列化的类A引用了不可序列化的类B(如Thread您的示例),则A必须将引用标记为transientXOR必须覆盖默认的序列化过程,以便对BXOR 进行合理的处理,前提是仅B实际引用了的可序列化子类(因此实际的子类必须照顾他们的“坏”父对象B)XOR接受序列化将失败。仅在一种情况下(标记为瞬态)B会自动无提示地跳过。
2013年

3
@TFennis不,它将导致异常。
user207421

1
@AH:为什么要XOR?我认为将这些内容进行任何组合的代码都将起作用,并且某些组合可能会有用(例如,即使仅引用B的可序列化子类,覆盖默认的序列化过程也可能有用,反之亦然)。
超级猫

15

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

我相信修饰符的象征意义是“此字段仅用于内存使用。请勿以任何方式持久保留或将其移出此特定VM。其不可移植”。即,您不能依赖其在另一个VM内存空间中的值。就像volatile一样,您不能依赖某些内存和线程语义。


14
我认为,transient如果此时已设计该关键字,那将不是关键字。他们可能会使用注释。
Joachim Sauer 2010年


7

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

序列化 当对象通过网络传输/保存在物理媒体(文件,...)上时,该对象必须被“序列化”。序列化将转换字节状态对象系列。这些字节在网络上发送/已保存,并根据这些字节重新创建对象。

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

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

private transient attr2;


6

当您不想共享序列化附带的一些敏感数据时,需要使用它。


7
除了敏感数据,还有一些用例,您可能不想序列化字段。例如,您可能永远不想序列化Thread(例如,贷记到@AH),在这种情况下,您会将其标记为瞬态。但是,线程本身并不是敏感数据,对其进行序列化(并且不可序列化)在逻辑上是没有意义的。
glen3b 2014年

1
@ glen3b此答案未排除该情况。鉴于海报中提到的情况,肯定是需要的。
user207421

3

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

现在,如果要在Java中进行任何瞬态操作,请使用Transition关键字。

问:在哪里使用瞬态?

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

transient int result=10;

注意:瞬时变量不能是局部的。


0

简而言之,transient java关键字保护字段免受序列化的影响,因为它们的非临时字段是计数器的一部分。

在此代码段中,我们的抽象类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;

   }
}

0

瞬态关键字的简化示例代码。

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

用瞬态修饰符声明的字段将不参与序列化过程。当对象被序列化(以任何状态保存)时,其瞬态字段的值在串行表示中将被忽略,而瞬态字段以外的其他字段将参与序列化过程。这是瞬时关键字的主要目的。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.