Answers:
在transient
Java中关键字用于指示字段不应该是系列化的一部分(这意味着保存,像一个文件)的过程。
从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
使用关键字防止某些字段序列化的方案。
在理解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
,因此不会存储在持久性存储中。
NameFormatter
二手车toString()
。或与配置或查看或业务逻辑相关的其他任何信息,与数据相反。
我的小贡献:
什么是瞬态场?
基本上,任何用transient
关键字修改的字段都是瞬态字段。
为什么在Java中需要瞬态字段?
该transient
关键字为您提供了序列化过程的一些控制,并允许您排除此过程中的一些对象属性。序列化过程通常用于持久化Java对象,以便在它们转移或不活动时可以保留它们的状态。有时,不序列化对象的某些属性是有意义的。
您应将哪些字段标记为瞬态?
现在我们知道了transient
关键字和瞬态字段,了解哪些字段标记为瞬态很重要。静态字段也不会序列化,因此相应的关键字也可以解决问题。但这可能会破坏您的班级设计。这就是该transient
关键字的目的所在。我尝试不允许将其值可以从其他值派生的字段进行序列化,因此我将它们标记为瞬态。如果您有一个名为interest
的字段,其值可以从其他字段(principal
,rate
&time
)中计算出来,则无需对其进行序列化。
另一个很好的例子是文章字数统计。如果要保存整篇文章,则实际上不需要保存字数,因为可以在对文章进行“反序列化”时进行计算。或考虑记录器;Logger
实例几乎不需要序列化,因此可以使其成为瞬态。
transient
transient
一个 transient
变量是可以不被序列化的变量。
一个可能在何时有用的示例是,仅在特定对象实例的上下文中有意义的变量,并且在对对象进行序列化和反序列化后这些变量将变为无效。在这种情况下,null
改用那些变量会很有用,这样您就可以在需要时用有用的数据重新初始化它们。
transient
用于表示不需要对类字段进行序列化。最好的例子可能是一个Thread
领域。通常没有理由序列化一个Thread
,因为它的状态非常“特定于流”。
A
引用了不可序列化的类B
(如Thread
您的示例),则A
必须将引用标记为transient
XOR必须覆盖默认的序列化过程,以便对B
XOR 进行合理的处理,前提是仅B
实际引用了的可序列化子类(因此实际的子类必须照顾他们的“坏”父对象B
)XOR接受序列化将失败。仅在一种情况下(标记为瞬态)B
会自动无提示地跳过。
除了本机Java之外的序列化系统也可以使用此修饰符。例如,休眠将不会保留标有@Transient或瞬态修饰符的字段。兵马俑也尊重此修饰符。
我相信修饰符的象征意义是“此字段仅用于内存使用。请勿以任何方式持久保留或将其移出此特定VM。其不可移植”。即,您不能依赖其在另一个VM内存空间中的值。就像volatile一样,您不能依赖某些内存和线程语义。
transient
如果此时已设计该关键字,那将不是关键字。他们可能会使用注释。
在回答这个问题之前,我必须向您解释SERIALIZATION,因为如果您了解科学计算机中的序列化含义,则可以轻松理解此关键字。
序列化
当对象通过网络传输/保存在物理媒体(文件,...)上时,该对象必须被“序列化”。序列化将转换字节状态对象系列。这些字节在网络上发送/已保存,并根据这些字节重新创建对象。
例
public class Foo implements Serializable
{
private String attr1;
private String attr2;
...
}
现在,如果您不想转移 / SAVED此对象的字段SO,您可以使用关键字 transient
private transient attr2;
当您不想共享序列化附带的一些敏感数据时,需要使用它。
Thread
(例如,贷记到@AH),在这种情况下,您会将其标记为瞬态。但是,线程本身并不是敏感数据,对其进行序列化(并且不可序列化)在逻辑上是没有意义的。
简而言之,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;
}
}
瞬态关键字的简化示例代码。
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);
}
}
@DoNotSerialize
?