为什么Java有瞬态字段?

Ani*_*esh 1406 java field transient

为什么Java有瞬态字段?

coo*_*ird 1623

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

来自Java语言规范,Java SE 7 Edition,第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();
    }    
}
Run Code Online (Sandbox Code Playgroud)

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

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

在反序列化时,readObject调用该方法以执行将对象的状态恢复回序列化发生状态所需的任何操作.这里,需要生成缩略图,因此readObject重写该方法,以便通过调用generateThumbnail方法生成缩略图.

有关其他信息,请参阅" 发现Java序列化API的秘密"一文(最初在Sun Developer Network上提供),其中有一节讨论了使用transient关键字并使用关键字来防止某些字段序列化的方案.

  • 我想,这是在Java中没有注释的时候拥有的. (323认同)
  • 但为什么它是一个关键字,而不是一个注释`@ DoNotSerialize`? (214认同)
  • 我发现奇怪的是serializable是Java内部的.它可以实现为需要用户覆盖读取和写入方法的接口或抽象类. (44认同)
  • @caleb可能是因为由于缺少无符号整数而在Java中处理二进制格式非常痛苦. (12认同)
  • @MJafar:readObject通常链接到反序列化机制,因此自动调用.此外,在许多情况下,您不需要覆盖它 - 默认实现可以解决问题. (7认同)
  • @ElazarLeibovich我认为是因为这个关键字比注释旧:http://en.wikipedia.org/wiki/Java_annotation#History (4认同)
  • @zatenzu子类可以实现Serializable (4认同)
  • @novaterata:当`Serializable`子类扩展非``Serializable`类时,子类负责存储和恢复其超类的所有相关状态(并且超类必须具有可访问的无参数构造函数) .因此,非``Serializable`超类'字段上的`transient`修饰符仍然没有相关性.但语言规范并未禁止将"transient"用于序列化以外的存储机制. (3认同)
  • @caleb:多年后,甲骨文同意你的看法——他们想放弃序列化:https://www.infoworld.com/article/3275924/java/oracle-plans-to-dump-risky-java-serialization.html (3认同)
  • 当类没有实现 Serialized 接口时,为什么我可以在类的实例变量上设置瞬态?这没有任何意义... (2认同)

Rah*_*ena 417

在理解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);
    }
}
Run Code Online (Sandbox Code Playgroud)

输出将如下:

First Name : Steve
Middle Name : null
Last Name : Jobs
Run Code Online (Sandbox Code Playgroud)

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

资源

  • 此示例取自此代码,您可以在此处阅读:http://www.javabeat.net/2009/02/what-is-transient-keyword-in-java/ (23认同)
  • 这部分让我觉得奇怪而且可能令人困惑:"这意味着对象的状态被转换为字节流并且*存储在文件中*".在我看来,大多数时候序列化不涉及写入文件(例如:后面的网络示例) (10认同)
  • 这个例子很糟糕,因为中间名显然不是*瞬态属性. (5认同)
  • @Raphael 对我来说,这个例子很有帮助,至少解释了这个概念。如果你知道,你会提供更好的例子吗? (4认同)

Bri*_*new 82

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

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


Shr*_*ari 35

我的小贡献:

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

为什么Java中需要瞬态字段?
transient关键字使您可以控制序列化过程,并允许您从此过程中排除某些对象属性.序列化过程用于持久化Java对象,主要是为了在传输或非活动状态时保留它们的状态.有时,不序列化对象的某些属性是有意义的.

您应该在哪些字段标记瞬态?
现在我们知道transient关键字和瞬态字段的用途,了解哪些字段标记瞬态非常重要.静态字段也没有序列化,因此相应的关键字也可以实现.但这可能会破坏你的课堂设计; 这是transient关键字拯救的地方.我尽量不允许其值可以从其他字段派生的字段被序列化,所以我将它们标记为瞬态.如果您有一个字段,interest其值可以从其他字段(principal,rate&time)计算,则无需序列化它.

另一个很好的例子是文章字数.如果要保存整篇文章,则实际上不需要保存单词计数,因为可以在文章被"反序列化"时计算.或者想想伐木工; Logger实例几乎从不需要序列化,因此它们可以是瞬态的.

  • 你的"简单句子"只是一个重言式.它没有解释.没有它你会好起来的. (62认同)

Adr*_*ore 25

transient变量是可以不被序列化的变量.

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


And*_*anu 15

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

  • @TFennis:如果一个可序列化的类`A`引用一个不可序列化的类`B`(在你的例子中就像`Thread`),那么`A`必须将引用标记为`transient` XOR必须按顺序覆盖默认的序列化过程使用`B` XOR做一些合理的事情假设只有'B`的可序列化子类实际被引用(所以实际的子类必须注意它们的"坏"父"B")XOR接受序列化将失败.只有一种情况(标记为瞬态),"B"会自动且无声地跳过. (3认同)
  • @TFennis不,它会引起异常. (3认同)

Dra*_*Fax 14

除本机java之外的序列化系统也可以使用此修饰符.例如,Hibernate不会持久标记用@Transienttransient修饰符标记的字段.兵马俑也尊重这个修饰符.

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

  • 我认为如果它是在此时设计的那么`transient`就不是关键词.他们可能会使用注释. (14认同)

Sil*_*rom 8

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

  • 当您给出答案时,请提供更多信息. (41认同)

BER*_*ine 6

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

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

public class Foo implements Serializable 
{
 private String attr1;
 private String attr2;
 ...
}
Run Code Online (Sandbox Code Playgroud)

现在,如果你想不TRANSFERT/救了这个对象的字段SO,您可以使用关键字 transient

private transient attr2;
Run Code Online (Sandbox Code Playgroud)


set*_*ora 5

当您不想共享一些与序列化相关的敏感数据时,需要它。

  • 除了敏感数据之外,还有一些用例可能不希望序列化字段。例如,您可能永远不想序列化“线程”(例如归功于@AH),在这种情况下,您会将其标记为瞬态。但是,线程本身并不是敏感数据,序列化它没有逻辑意义(并且它不可序列化)。 (8认同)

Mat*_*een 5

根据谷歌瞬态含义==仅持续很短的时间;暂时的。

现在,如果你想在java中使任何东西瞬态,请使用transient关键字。

问:在哪里使用瞬态?

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

transient int result=10;
Run Code Online (Sandbox Code Playgroud)

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