为什么Java有瞬态字段?

 2019-04-22 

Why does Java have transient fields?

为什么Java有瞬态字段?


Java中的EDCOX1×0×关键字用于指示字段不应该是序列化(即保存到文件)过程的一部分。

从Java语言规范,Java SE 7版,第83.1.3节。transient字段:

Variables may be marked transient to
indicate that they are not part of the
persistent state of an object.

例如,您可能拥有从其他字段派生的字段,并且只能通过编程方式实现,而不是通过序列化来持久化状态。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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开发者网络上可用)的秘密有一节讨论使用,并提出一种场景,其中使用EDCX1"0"关键字来防止某些字段的序列化。


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

什么是序列化?

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

现在,transient关键字是什么?它的用途是什么?

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

我想用下面的例子来解释上述两点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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);
    }
}

输出结果如下:

1
2
3
First Name : Steve
Middle Name : null
Last Name : Jobs

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

来源


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

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


我的小贡献:

什么是瞬变场?基本上,任何用transient关键字修改的字段都是临时字段。为什么Java中需要瞬态字段?transient关键字为您提供了一些对序列化过程的控制,并允许您从这个过程中排除一些对象属性。序列化过程用于保存Java对象,主要是使它们的状态可以在它们被转移或不活动时保存。有时,不序列化对象的某些属性是有意义的。您应该标记哪些字段为瞬态?现在我们知道了transient关键字和瞬态字段的用途,了解哪些字段标记瞬态非常重要。静态字段也没有序列化,因此相应的关键字也可以实现这一点。但是这可能会破坏你的类设计;这是transient关键字用来救援的地方。我尽量不让值可以从其他字段派生的字段被序列化,所以我将它们标记为瞬时的。如果您有一个名为interest的字段,它的值可以从其他字段(principalratetime计算出来,则不需要序列化它。另一个很好的例子是文章字数统计。如果要保存整个文章,实际上不需要保存字数,因为可以在文章"反序列化"或考虑记录器时计算字数;Logger实例几乎不需要序列化,因此它们可以是暂时的。


transient变量是不能序列化的变量。

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


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


除了本机Java之外的序列化系统也可以使用这个修饰符。例如,Hibernate将不持久标记为@Transient或Transient修饰符的字段。陶土也尊重这个修饰语。

我认为修饰语的比喻意义是"这个字段仅用于内存中。不要以任何方式将它持久化或移动到这个特定的虚拟机之外。它是不可移植的"。也就是说,您不能依赖它在另一个虚拟机内存空间中的值。就像volatile一样,意味着您不能依赖特定的内存和线程语义。


因为并非所有变量都是可序列化的


respond之前,这个问题,我必须向你解释的序列化,因为如果你明白什么意思的序列化,在计算机科学,你可以很容易的理解这个关键字。

序列化 当冰转移的对象通过网络在线/救物理媒体(文件)的对象,必须"序列化"。converts字节状态序列化对象的系列。这些字节是在网络/晚救冰和对象重新创造了从这些字节。
例如

1
2
3
4
5
6
public class Foo implements Serializable
{
 private String attr1;
 private String attr2;
 ...
}

现在,如果你想传递/不救场本对象的婊子,你可以使用关键字的transient

1
private transient attr2;

实例


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


简单的说,《Java关键字的瞬态保护领域的"serialize已经为他们的非瞬态场的对手方。

在这段代码用于实现我们的抽象类basejob Serializable接口,我们basejob extends虔诚,但我们需要的不是serialize远程和本地数据源;serialize organizationname和issynced只读字段。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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;

   }
}


按照谷歌短暂的意思==短暂的;短暂的。

现在,如果你想让Java中的任何东西都使用临时关键字。

问:在哪里使用瞬变?

答:通常在Java中,我们可以通过在变量中获取数据并将这些变量写入文件,从而将数据保存到文件中,这个过程称为序列化。现在,如果我们想避免将变量数据写入文件,我们将使该变量成为瞬态变量。

1
transient int result=10;

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


给一个实例,使透明的东西, 请读《accepted回答。 在这里,我将在另一个实例诠释。

1
2
3
4
5
6
7
8
9
10
    class Employee{
    String name;
    Date dob;
    transient int age;
    public int calculateAge(Date dob){
        int age = 0;
        //calculate age based on Date of birth
        return age;
    }
}

在这里,在上面的实例中有"时代"的方式为瞬变。当我写两个时代档案信息的价值是不可存储的需求。在这里,有一个功能calculates时代基于DOB。 我们可以使用这些变量的瞬态两人谁,我们不想写两个磁盘。

希望它helps。!