To be honest, friends who have studied Java for a while are still very unfamiliar with the keyword transient and have rarely used it, but the keyword transient plays an indispensable role in Java! If I want to talk about it, I think the most likely place to appear is when it comes to object streams (also called serialized streams) in IO streams!
I believe that many people will not care about this keyword until they encounter it. I remember that the first time bloggers encountered the transient keyword was when reading the JDK source code. In the process of learning Java, the reason why the transient keyword is rare is actually inseparable from its function: the main function of the transient keyword is to prevent certain member attribute variables modified by the transient keyword from being serialized. In fact, it is precisely for this reason that serialization operations are rarely used in the learning process, usually in actual development! As for serialization, I believe that many novices have been confused or have no specific concept. This is not a problem. The following blogger will clearly let you remember what serialization is, ensuring that you will never forget it in this life (it seems a bit Exaggerated, a bit pretentious, I feel like I’m going to be beaten)
1. What is serialization?
Speaking of serialization, another concept that comes with it is deserialization. Don’t panic, little white children’s shoes. Remembering serialization is equivalent to remembering deserialization, because deserialization Serialization is the reverse of serialization, so the blogger recommends just remembering the concept of serialization to avoid confusing yourself.
(Recommended video: java video tutorial)
Serialization of professional terminology definitions :
Java provides a mechanism for object serialization. An object can be represented by a byte sequence that contains information such as the object's data, the object's type, and the attributes stored in the object. After the byte sequence is written to the file, it is equivalent to persisting the information of an object in the file. Conversely, the byte sequence can be read back from the file, the object reconstructed, and deserialized. The object's data, the object's type, and the data information stored in the object can all be used to create objects in memory.
Serialization: Byte——> Object
In fact, what I summarized is the above conclusion. If you don’t understand, refer directly to the definition of professional terms, and remember it after you understand it. Just remember my words. If you can’t remember, please beat me to death.
Diagram to understand serialization:
2. Why serialization?
The concept of serialization was mentioned in the previous section. After knowing the concept, we must know why we need to serialize.
Before I talk about the reasons why serialization is necessary, let me give you a chestnut as a blogger:
Just like when you go to the street to buy groceries, the general operation is to package them in plastic bags until you go home. When it's time to cook, take out the dishes. And this series of operations is like serialization and deserialization!
Serialization of objects in Java refers to converting objects into byte sequences. These byte sequences contain the data and information of the object. A serialized object can be written to In databases or files, it can also be used for network transmission. Generally, when we use cache (not enough memory space may be stored locally on the hard disk) or remotely call rpc (network transmission), we often need to make our entity classes implement the Serializable interface. , the purpose is to make it serializable.
Chestnuts modified with the transient keyword during the development process:
If a user has some passwords and other information, for the sake of security, they do not want to be transmitted during network operations, these information correspond to You can add the transient keyword to the variable. In other words, the life cycle of this field only exists in the caller's memory and will not be written to disk for persistence.
Examples that do not require the transient keyword modification during the development process:
1. Field values in the class can be derived based on other fields.
2. Depending on the specific business requirements, which fields do not want to be serialized;
I wonder if you have ever thought about why they should not be serialized? In fact, it is mainly to save storage space. Optimize the program!
PS: I remember when I was looking at the HashMap source code, I found that a field was modified with transient. I think it makes sense. There is really no need to serialize the modCount field because it is meaningless. ModCount is mainly Used to determine whether the HashMap has been modified (modCount will be incremented during put and remove operations). For this kind of variable, it can be any value at the beginning, of course 0 (new, deserialized, or cloned). It is always 0 when it comes out), there is no need to persist its value.
Of course, the ultimate purpose after serialization is to deserialize and restore it to the original Java object. Otherwise, what would you do after serialization? Just like buying groceries, wrapping them in plastic bags is for the convenience of getting home safely. Remove the plastic bag, so the serialized byte sequence can be restored to a Java object. This process is deserialization.
3. The use of serialization and transient
1. The class of the object that needs to be serialized must implement the serialization interface: Java.lang.Serializable interface ( A flag interface without any abstract methods), most classes in Java implement this interface, such as: String, Integer class, etc. Classes that do not implement this interface will not serialize or deserialize any state and will throw NotSerializableException exception.
2. The bottom layer will judge that if the current object is an instance of Serializable, serialization is allowed. The Java object instanceof Serializable is used to judge.
3. Use the object stream ObjectOutputStream in Java to complete serialization and ObjectInputStream stream deserialization
==ObjectOutputStream: serialization operation through the writeObject() method==
==ObjectInputStream: Deserialization operation through readObject() method==
4. All properties of this class must be serializable. If there is an attribute that does not need to be serializable, the attribute must be marked as transient and modified using the transient keyword.
Because of the bytes, it must involve stream operations, that is, the object stream is also called the serialized stream ObjectOutputstream. Let’s analyze the serialization in various situations. Action code!
Here, I really strongly recommend readers who read the Yichun blog, please try to knock it, remember to take it with you at a glance or copy it and run it, especially Xiaobai children's shoes, believe me! You will definitely gain something different. !
3.1. Serialization without implementing Serializable interface
package TransientTest; import java.io.*; class UserInfo { //================================注意这里没有实现Serializable接口 private String name; private transient String password; public UserInfo(String name, String psw) { this.name = name; this.password = psw; } @Override public String toString() { return "UserInfo{" + "name='" + name + '\'' + ", password='" + password + '\'' + '}'; } } public class TransientDemo { public static void main(String[] args) { UserInfo userInfo = new UserInfo("老王", "123"); System.out.println("序列化之前信息:" + userInfo); try { ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt")); output.writeObject(new UserInfo("老王", "123")); output.close(); } catch (IOException e) { e.printStackTrace(); } } }
Running results
3.2. Serialization with Serializable interface implemented
When we add the Serializable interface and run it again, we will find that the content of the userinfo.txt file that appears in the project is like this:
In fact, this is not the point. The point is that the serialization operation was successful!
3.3. Ordinary serialization situation
package TransientTest; import java.io.*; class UserInfo implements Serializable { //第一步实现Serializable接口 private String name; private String password; //都是普通属性============================== public UserInfo(String name, String psw) { this.name = name; this.password = psw; } @Override public String toString() { return "UserInfo{" + "name='" + name + '\'' + ", password='" + password + '\'' + '}'; } } public class TransientDemo { public static void main(String[] args) throws ClassNotFoundException { UserInfo userInfo = new UserInfo("程序员老王", "123"); System.out.println("序列化之前信息:" + userInfo); try { ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步开始序列化操作 output.writeObject(new UserInfo("程序员老王", "123")); output.close(); } catch (IOException e) { e.printStackTrace(); } try { ObjectInputStream input = new ObjectInputStream(new FileInputStream("userinfo.txt")); //第三步开始反序列化操作 Object o = input.readObject(); //ObjectInputStream的readObject方法会抛出ClassNotFoundException System.out.println("序列化之后信息:" + o); } catch (IOException e) { e.printStackTrace(); } } }
Running result:
序列化之前信息:UserInfo{name='程序员老王', password='123'} 序列化之后信息:UserInfo{name='程序员老王', password='123'}
3.4. Transient serialization situation
package TransientTest; import java.io.*; class UserInfo implements Serializable { //第一步实现Serializable接口 private String name; private transient String password; //特别注意:属性由transient关键字修饰=========== public UserInfo(String name, String psw) { this.name = name; this.password = psw; } @Override public String toString() { return "UserInfo{" + "name='" + name + '\'' + ", password='" + password + '\'' + '}'; } } public class TransientDemo { public static void main(String[] args) throws ClassNotFoundException { UserInfo userInfo = new UserInfo("程序员老王", "123"); System.out.println("序列化之前信息:" + userInfo); try { ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步开始序列化操作 output.writeObject(new UserInfo("程序员老王", "123")); output.close(); } catch (IOException e) { e.printStackTrace(); } try { ObjectInputStream input = new ObjectInputStream(new FileInputStream("userinfo.txt")); //第三步开始反序列化操作 Object o = input.readObject(); //ObjectInputStream的readObject方法会抛出ClassNotFoundException System.out.println("序列化之后信息:" + o); } catch (IOException e) { e.printStackTrace(); } } }
Running result:
序列化之前信息:UserInfo{name='程序员老王', password='123'} 序列化之后信息:UserInfo{name='程序员老王', password='null'}
Pay special attention to the results. The attribute value added with transient modification is the default value null! If the attribute modified by transient is of type int, then its value must be 0 after being serialized. Of course, you can try it. What does this mean? It means that attributes marked as transient will not be saved when the object is serialized (or the variable will not be persisted)
3.5. Static serialization situation
package TransientTest; import java.io.*; class UserInfo implements Serializable { //第一步实现Serializable接口 private String name; private static String password; //特别注意:属性由static关键字修饰============== public UserInfo(String name, String psw) { this.name = name; this.password = psw; } @Override public String toString() { return "UserInfo{" + "name='" + name + '\'' + ", password='" + password + '\'' + '}'; } } public class TransientDemo { public static void main(String[] args) throws ClassNotFoundException { UserInfo userInfo = new UserInfo("程序员老王", "123"); System.out.println("序列化之前信息:" + userInfo); try { ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream("userinfo.txt")); //第二步开始序列化操作 output.writeObject(new UserInfo("程序员老王", "123")); output.close(); } catch (IOException e) { e.printStackTrace(); } try { ObjectInputStream input = new ObjectInputStream(new FileInputStream("userinfo.txt")); //第三步开始反序列化操作 Object o = input.readObject(); //ObjectInputStream的readObject方法会抛出ClassNotFoundException System.out.println("序列化之后信息:" + o); } catch (IOException e) { e.printStackTrace(); } } }
Running results:
序列化之前信息:UserInfo{name='程序员老王', password='123'} 序列化之后信息:UserInfo{name='程序员老王', password='123'}
At this time, you will mistakenly think that the static modification has also been serialized. In fact, it is not the case. In fact, it is easy to get confused here! Obviously taking out null (default value) can show that it will not be serialized. It is obvious that it has not become the default value. Why do you still say that static will not be serialized?
In fact, the value of the static variable name in the class after deserialization is actually the value of the corresponding static variable in the current JVM. This value is in the JVM and is not derived from deserialization. In other words, variables modified by static do not participate in serialization! But we can’t say it without proof, yes, then let’s compare the two programs and we will understand!
The first program: This is a name attribute program that has not been modified by static:
package Thread; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; class UserInfo implements Serializable { private String name; private transient String psw; public UserInfo(String name, String psw) { this.name = name; this.psw = psw; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPsw() { return psw; } public void setPsw(String psw) { this.psw = psw; } public String toString() { return "name=" + name + ", psw=" + psw; } } public class TestTransient { public static void main(String[] args) { UserInfo userInfo = new UserInfo("程序员老过", "456"); System.out.println(userInfo); try { // 序列化,被设置为transient的属性没有被序列化 ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt")); o.writeObject(userInfo); o.close(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } try { //在反序列化之前改变name的值 =================================注意这里的代码 userInfo.setName("程序员老改"); // 重新读取内容 ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt")); UserInfo readUserInfo = (UserInfo) in .readObject(); //读取后psw的内容为null System.out.println(readUserInfo.toString()); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }
Running results:
name=程序员老过, psw=456name=程序员老过, psw=null
Running results from the program As can be seen from the figure, trying to change the value of name before deserialization was unsuccessful!
The second program: This is a statically modified name attribute program:
package Thread; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; class UserInfo implements Serializable { private static final long serialVersionUID = 996890129747019948 L; private static String name; private transient String psw; public UserInfo(String name, String psw) { this.name = name; this.psw = psw; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getPsw() { return psw; } public void setPsw(String psw) { this.psw = psw; } public String toString() { return "name=" + name + ", psw=" + psw; } } public class TestTransient { public static void main(String[] args) { UserInfo userInfo = new UserInfo("程序员老过", "456"); System.out.println(userInfo); try { // 序列化,被设置为transient的属性没有被序列化 ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("UserInfo.txt")); o.writeObject(userInfo); o.close(); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } try { //在反序列化之前改变name的值 userInfo.setName("程序员老改"); // 重新读取内容 ObjectInputStream in = new ObjectInputStream(new FileInputStream("UserInfo.txt")); UserInfo readUserInfo = (UserInfo) in .readObject(); //读取后psw的内容为null System.out.println(readUserInfo.toString()); } catch (Exception e) { // TODO: handle exception e.printStackTrace(); } } }
Running results:
name=程序员老过, psw=456name=程序员老改, psw=null
From the program running results It can be seen that trying to change the value of name before deserialization is done by programmers, and the result is successful! Is it very clear now if we compare the two programs?
The member attributes modified by the static keyword are loaded into memory better than non-static member attributes. At the same time, static is also better than objects entering memory. Member variables modified by static cannot be serialized, and all objects are serialized. A static variable is not part of the object's state, so it does not participate in serialization. So it is useless to declare static variables as transient variables. Therefore, the value of the static variable name in the class after deserialization is actually the value of the corresponding static variable in the current JVM. This value is in the JVM and is not derived from deserialization.
3.6. Final serialization situation
For the final keyword, the final variable will directly participate in serialization through the value. As for the code program, I will not post it anymore. You can try it. Check the final modification!
The main thing to note is that final and transient can modify the same variable at the same time, and the result is the same. It has no impact on transient. I mainly mention it here. I hope you will not be confused when you encounter these situations in development in the future. water!
4. The role of serialVersionUID in java classes
Since the transient keyword has been mentioned, serialization has to be mentioned. Since serialization has been mentioned, serialVersionUID has to be mentioned. What is it? Woolen cloth? Basically, this serialVersionUID will exist if there is serialization.
#serialVersionUID applies to Java's serialization mechanism. Simply put, Java's serialization mechanism verifies version consistency by judging the serialVersionUID of the class. When deserializing, the JVM will compare the serialVersionUID in the passed byte stream with the serialVersionUID of the corresponding local entity class. If they are the same, they are considered consistent and can be deserialized. Otherwise, a serialized version will appear. Inconsistent exceptions, namely InvalidCastException, can sometimes be written or not during development. It is recommended that it be written.
5. Summary of transient keyword
1. If the variable is modified by transient, the variable will not be serialized
2. The transient keyword only Variables can be modified, but methods and classes cannot be modified.
3. Variables modified by the static keyword do not participate in serialization. A static variable cannot be serialized regardless of whether it is modified by transient.
4. The final variable value participates in serialization, and final transient modifies the variable at the same time. Final will not affect transient and will not participate in serialization either.
The second point to note is: local variables are Cannot be modified by the transient keyword. If the variable is a user-defined class variable, the class needs to implement the Serializable interface
The third point to note is: the value of the static variable in the class after deserialization is actually the corresponding static variable in the current JVM The value is in the JVM and is not derived from deserialization.
Conclusion: Modified by the transient keyword, it will not be serialized. The advantage is that it can save storage space. Optimize the program! What follows is that the fields modified by transient will be recalculated and initialized!
This article comes from php Chinese website, java tutorial column, welcome to learn!
The above is the detailed content of Detailed explanation of transient keyword in java. For more information, please follow other related articles on the PHP Chinese website!