1,transient(临时)关键字
java中提供了很方便的序列化,只要实现Serializable接口(或Extenalizable),那么就可以被序列化,我们可以不必关系具体序列化的过程,只要这个类实现了Serilizable接口,这个类的所有属性和方法都会自动序列化,这样就可以将输出到文件,网络中,对象持久化到硬盘上。
但是,有时候对象的某些属性我们不想被序列化,必须出于安全考虑,对象包含的不想被序列化的敏感信息(如密码),那么这些信息就可以加上该关键字
例:
import java.io.*;
public class login {
public static void main(String args[]) {
UserInfo info = new UserInfo();
info.setUsername("zhangssan");
info.setPassword("123456");
System.out.println("序列化前:");
System.out.println("username: " + info.getUsername());
System.out.println("password: " + info.getPassword());
//向UserInfo对象存入到info.txt
try {
ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("D:/info.txt"));
os.writeObject(info);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
//从文件中读取UserInfo的对象数据
try {
ObjectInputStream is = new ObjectInputStream(new FileInputStream("D:/info.txt"));
UserInfo inputInfo = (UserInfo) is.readObject();
is.close();
System.out.println("\n 序列化读取文件后:");
System.out.println("username: " + inputInfo.getUsername());
System.out.println("password: " + inputInfo.getPassword());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class UserInfo implements Serializable {
private String username;
private transient String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
输出结果:
序列化前:
username: zhangssan
password: 123456
序列化读取文件后:
username: zhangssan
password: null
password字段为null,说明该字段并没有被序列化
2,Externalizable接口
我们同样可以通过实现Externalizable接口来实现序列化的控制,实现Externalizable接口后,所以东西都将默认不被序列化,需要在writeExternal方法和ReadExternal方法中进行手工指定所要序列化或反序列化的变量,这与是否被transient修饰无关。
例:
import java.io.*;
public class LogonTest implements Externalizable{
private String username;
private transient String password;
public LogonTest(){}//必须提供无参构造函数,否则会抱错
public LogonTest (String name, String pwd) {
username = name;
password = pwd;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
//out.writeObject(username);
out.writeObject(password);
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
//username = (String)in.readObject();
password = (String)in.readObject();
}
public String toString() {
return ("username="+username+", password="+password);
}
public static void main(String[] args) {
LogonTest logonTest = new LogonTest("zhangsan", "123456");
System.out.println("logonTest value:\n "+logonTest);
try {
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Logon.out"));
o.writeObject(logonTest);
o.close();
System.out.println("-----------------------");
// Now get them back;
ObjectInputStream in = new ObjectInputStream(new FileInputStream("Logon.out"));
logonTest = (LogonTest)in.readObject();
in.close();
System.out.println("logonTest value:\n " + logonTest);
} catch (Exception e) {
e.printStackTrace();
}
}
}
输出结果:
logonTest value:
username=zhangsan, password=123456
-----------------------
logonTest value:
username=null, password=123456
LogonTest中方法writeExternal和readExternal里只加了passwod,虽然password有transient,但仍然被序列化,而username并没有作处理,也就没有被序列化。
所以实现接口Externalizable后序列化跟writeExternal和readExternal方法有关,与关键字transient无关
注意:这里实现Externalizable接口时,必须有无参构造函数,否则会抱错。这是因为在反序列化时,会调用无参构造函数。
例如:注释掉上边无参构造函数,则再运行时,就会报 no valid constructor
logonTest value:
username=zhangsan, password=123456
-----------------------
java.io.InvalidClassException: LogonTest; no valid constructor
at java.io.ObjectStreamClass$ExceptionInfo.newInvalidClassException(ObjectStreamClass.java:150)
at java.io.ObjectStreamClass.checkDeserialize(ObjectStreamClass.java:768)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1775)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371)
at LogonTest.main(LogonTest.java:42)
3,静态变量默认不会被序列化,但可以手动序列化
例:
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Random;
import java.util.Vector;
abstract class Shape implements Serializable {
public static final String
RED = "red", BLUE ="blue", GREEN ="green";
abstract public void setColor(String newColor);
abstract public String getColor();
public String toString() {
return getClass().toString() +
" color[" + getColor() +
"] \n";
}
}
class Circle extends Shape {
private static String color = RED;
@Override
public void setColor(String newColor) {
color = newColor;
}
@Override
public String getColor() {
return color;
}
}
class Square extends Shape {
private static String color=RED;
@Override
public void setColor(String newColor) {
color = newColor;
}
@Override
public String getColor() {
return color;
}
}
class Line extends Shape {
private static String color = RED;
public static void serializaStaticState(ObjectOutputStream os) throws IOException {
os.writeObject(color);
}
public static void deserializaStaticState(ObjectInputStream is) throws IOException, ClassNotFoundException {
color = (String) is.readObject();
}
@Override
public void setColor(String newColor) {
color = newColor;
}
@Override
public String getColor() {
return color;
}
}
public class StaticTestSerinal {
public static void main(String[] args) throws Exception {
Vector shapes;
if (args.length == 0) {
shapes = new Vector();
// Add handles to the class objects;
Circle circle = new Circle();
Square square = new Square();
Line line = new Line();
circle.setColor("BLACK");
square.setColor("BLACK");
line.setColor("BLACK");
shapes.add(circle);
shapes.add(square);
shapes.add(line);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("statisState.out"));
/**标记1**/ Line.serializaStaticState(out); //调用writeObject手动将静态变量输出到输出流中
out.writeObject(shapes);
} else {
ObjectInputStream in = new ObjectInputStream(new FileInputStream(args[0]));
/**标记2**/ Line.deserializaStaticState(in);//调用readObject手动将静态变量输入到输入流中
shapes = (Vector) in.readObject();
}
// Display the shaps
System.out.println(shapes);
}
}
不提供命令行参数时输出结果:
[class Circle color[BLACK]
, class Square color[BLACK]
, class Line color[BLACK]
]
加上命令行参数参数输出:
[class Circle color[red]
, class Square color[red]
, class Line color[BLACK]
]
通过结果会发现,Circle和Square都没有序列化静态变量,但是因为Line里边手动调用readObject和writeObject将静态变量输入输出,所以静态变量就会被序列化。
可以注释掉上边带吗中的标记1和标记2,测试会发现此时静态变量并没有被序列化。
网友评论