Why does Java have transient fields?
转载于:https://stackoverflow.com/questions/910374/why-does-java-have-transient-fields
The transient
keyword in Java is used to indicate that a field should not be serialized.
From the Java Language Specification, Java SE 7 Edition, Section 8.3.1.3. transient
Fields:
Variables may be marked
transient
to indicate that they are not part of the persistent state of an object.
For example, you may have fields that are derived from other fields, and should only be done so programmatically, rather than having the state be persisted via serialization.
Here's a GalleryImage
class which contains an image and a thumbnail derived from the image:
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();
}
}
In this example, the thumbnailImage
is a thumbnail image that is generated by invoking the generateThumbnail
method.
The thumbnailImage
field is marked as transient
, so only the original image
is serialized rather than persisting both the original image and the thumbnail image. This means that less storage would be needed to save the serialized object. (Of course, this may or may not be desirable depending on the requirements of the system -- this is just an example.)
At the time of deserialization, the readObject
method is called to perform any operations necessary to restore the state of the object back to the state at which the serialization occurred. Here, the thumbnail needs to be generated, so the readObject
method is overridden so that the thumbnail will be generated by calling the generateThumbnail
method.
For additional information, the Discover the secrets of the Java Serialization API article (which was originally available on the Sun Developer Network) has a section which discusses the use of and presents a scenario where the transient
keyword is used to prevent serialization of certain fields.
To allow you to define variables that you don't want to serialise.
In an object you may have information that you don't want to serialise/persist (perhaps a reference to a parent factory object), or perhaps it doesn't make sense to serialise. Marking these as 'transient' means the serialisation mechanism will ignore these fields.
Because not all variables are of a serializable nature
A transient
variable is a variable that may not be serialized.
One example of when this might be useful that comes to mind is, variables that make only sense in the context of a specific object instance and which become invalid once you have serialized and deserialized the object. In that case it is useful to have those variables become null
instead so that you can re-initialize them with useful data when needed.
It's needed when you don't want to share some sensitive data that go with serialization.
Serialization systems other than the native java one can also use this modifier. Hibernate, for instance, will not persist fields marked with either @Transient or the transient modifier. Terracotta as well respects this modifier.
I believe the figurative meaning of the modifier is "this field is for in-memory use only. don't persist or move it outside of this particular VM in any way. Its non-portable". i.e. you can't rely on its value in another VM memory space. Much like volatile means you can't rely on certain memory and thread semantics.
transient
is used to indicate that a class field doesn't need to be serialized. Probably the best example is a Thread
field. There's usually no reason to serialize a Thread
, as its state is very 'flow specific'.
Before understanding the transient
keyword, one has to understand the concept of serialization. If the reader knows about serialization, please skip the first point.
Serialization is the process of making the object's state persistent. That means the state of the object is converted into a stream of bytes and stored in a file. In the same way, we can use the deserialization to bring back the object's state from bytes. This is one of the important concepts in Java programming because serialization is mostly used in networking programming. The objects that need to be transmitted through the network have to be converted into bytes. For that purpose, every class or interface must implement the Serializable
interface. It is a marker interface without any methods.
transient
keyword and its purpose?By default, all of object's variables get converted into a persistent state. In some cases, you may want to avoid persisting some variables because you don't have the need to persist those variables. So you can declare those variables as transient
. If the variable is declared as transient
, then it will not be persisted. That is the main purpose of the transient
keyword.
I want to explain the above two points with the following example:
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);
}
}
And the output will be the following:
First Name : Steve
Middle Name : null
Last Name : Jobs
Middle Name is declared as transient
, so it will not be stored in the persistent storage.
My small contribution :
What is a transient field?
Basically, any field modified with the transient
keyword is a transient field.
Why are transient fields needed in Java?
The transient
keyword gives you some control over the serialization process and allows you to exclude some object properties from this process. The serialization process is used to persist Java objects, mostly so that their states can be preserved while they are transferred or inactive. Sometimes, it makes sense not to serialize certain attributes of an object.
Which fields should you mark transient?
Now we know the purpose of the transient
keyword and transient fields, it's important to know which fields to mark transient. Static fields aren't serialized either, so the corresponding keyword would also do the trick. But this might ruin your class design; this is where the transient
keyword comes to the rescue. I try not to allow fields whose values can be derived from others to be serialized, so I mark them transient. If you have a field called interest
whose value can be calculated from other fields (principal
, rate
& time
), there is no need to serialize it.
Another good example is with article word counts. If you are saving an entire article, there's really no need to save the word count, because it can be computed when article gets "deserialized." Or think about loggers; Logger
instances almost never need to be serialized, so they can be made transient.
as per google transient meaning == lasting only for a short time; impermanent.
now if want to make anything transient in java use transient keyword.
Q: where to use transient?
A: Generally in java we can save data to files by acquiring them in variables and writing those variables to files, this process is known as Serialization. Now if we want to avoid variable data to be written to file, we would make that variable as transient.
transient int result=10;
Note: transient variables cannot be local.
Before I respond to this question, I must explain to you the SERIALIZATION, because if you understand what it means serialization in science computer you can easily understand this keyword.
Serialization When an object is transferred through the network / saved on physical media(file,...), the object must be "serialized". Serialization converts byte status object series. These bytes are sent on the network/saved and the object is re-created from these bytes.
Example
public class Foo implements Serializable
{
private String attr1;
private String attr2;
...
}
Now IF YOU WANT TO do NOT TRANSFERT/SAVED field of this object SO, you can use keyword transient
private transient attr2;
Serialization is the process of saving an object’s states in a persistent format (such as file stream or database), and later restoring them back from the stream (de-serialization). In Java, an object of a class is serializable if the class implements the java.io.Serializable interface. This is a marker interface which tells the JVM that the class is eligible for serialization.
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
}
There are three important points in this model class: It must implements the Serializable interface. Otherwise, we’ll get a java.io.NotSerializableException when trying to serialize an object of the class. A constant named serialVersionUID is declared and assigned a long value:
private static final long serialVersionUID = 1234L;
This is a conventional constant which should be declared when a class implements the Serializable interface. The serial version UID strongly ensures compatibility between the serialized and de-serialized versions of objects of a class, because the process of serialization and de-serialization can happen on different computers and systems. Although this declaration is optional, it’s always recommended to declare the serialVersionUID for a serializable class.
Notice that the password field is marked as transient:
private transient String password;
Because we don’t want store the password when serializing the object. The rule is, when a variable is marked as transient, its object won’t be serialized during serialization.
A transient variable is a variable that may not be serialized. You use the transient keyword to indicate to the Java virtual machine that the indicated variable is not part of the persistent state of the object.
The access modifiers supported by Java are static, final, abstract, synchronized, native, volatile, transient and strictfp.
Following table gives the list of access specifiers and modifiers Java that can be applied to variables, methods and classes.
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
Simply put, the transient java keyword protect fields from the been Serialize as their non-transient fields counter parts.
In this code snippet our abstract class BaseJob implement Serializable interface, we extends from BaseJob but we need not serialize the remote and local data sources; serialize only organizationName and isSynced fields.
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;
}
}