我是张哲,一位在互联网上不愿透露姓名的小学员,接下来大家看到的所有内容都是我背写的知识点,这里的知识点和你所学习到的不同,我中和了我的一些书籍和网上刷的面试笔记,相信这里能让你接触到更深入的知识点,我会慢慢的把我对某个知识点的理解写进去。
常见的几种数据存储:变量、数组、对象、集合、文件、数据库
我们想文件中存储的是数据,可是文件中能不能存储对象呢??对象的属性,属性值,方法这些??
于是就是有了对象流,ObjectInputStream、ObjectOutputStream,对象流是一种高级流,所以在实例化对象的时候需要一个低级流当做参数
static class Person{
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public static void main(String[] args) {
try {
FileOutputStream writer=new FileOutputStream("C:\\Users\\张哲\\Desktop/申请.txt");
ObjectOutputStream out=new ObjectOutputStream(writer);
Person p=new Person("张哲",18);
out.writeObject(p);
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//运行的结果是个运行时异常:java.io.NotSerializableException
//它的意思是Person类没有实现序列化接口所以我们
序列化:将一个对象拆解成很多的字节碎片的过程。
反序列化:将一些字节碎片重组成一个对象的过程。
所以我们刚刚出现了异常:java.io.NotSerializableException,是因为我们用对象流将一个对象序列化到文件中,但是我们不去实现序列化接口怎么去序列化呢?这个就是原因了。
下面来看看序列化接口的源码:
public interface Serializable {
}
//噗噗,是不是很搞笑,啥属性,啥方法也没有。
//像这样的接口我们叫它:示意性接口
//就是个标识的意思,你要想实现某些功能还必须实现某个接口,尽管它里面没有什么抽象方法
static class Person implements Serializable{
private String name;
private int age;
public Person(){
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public static void main(String[] args) {
try {
FileOutputStream writer=new FileOutputStream("C:\\Users\\张哲\\Desktop/申请.txt");
ObjectOutputStream out=new ObjectOutputStream(writer);
Person p=new Person("张哲",18);
out.writeObject(p);
out.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
//最终正常运行结束
打开对应的文件后内容为:
{sr java.io.NotSerializableException(Vx 鐔5 xr
java.io.ObjectStreamExceptiond娩k? xr java.io.IOExceptionl€sde%皤 xr
java.lang.Exception旋>;? xr java.lang.Throwable掌5’9w杆 L causet
Ljava/lang/Throwable;L detailMessaget Ljava/lang/String;[
stackTracet [Ljava/lang/StackTraceElement;L suppressedExceptionst
Ljava/util/List;xpq ~ t org.tt.zz.main.LambdaDemoKaTeX parse error: Expected 'EOF', got '&' at position 86: …TraceElementa 艢&̲6輩 I lineNumbe…UnmodifiableList?%1奠? L listq ~ xr
,java.util.Collections$UnmodifiableCollectionB €薧? L ct
Ljava/util/Collection;xpsr java.util.ArrayListx佉櫱a? I sizexp w
xq ~ x
哈哈,我知道你看不懂,我也看不懂。。。[坏笑]
不过没关系,这就是个序列化的过程,把对象的信息打碎了存入我们的文件中来,这样也起到了一定的加密安全。
FileOutputStream writer=new FileOutputStream("C:\\Users\\张哲\\Desktop/申请.txt");
ObjectOutputStream out=new ObjectOutputStream(writer);
Person p=new Person("张哲",18);
out.writeObject(p);
out.flush();
FileInputStream reader=new FileInputStream("C:\\Users\\张哲\\Desktop/申请.txt");
ObjectInputStream in=new ObjectInputStream(reader);
Person p1=(Person)in.readObject();
System.out.println(p1.getName()+p1.getAge());
看这样就是个序列化和反序列化的过程,除此之外我们先能不能一次性存储多个对象呢?
//下面来看看我 try 中的代码块
FileOutputStream writer=new FileOutputStream("C:\\Users\\张哲\\Desktop/申请.txt");
ObjectOutputStream out=new ObjectOutputStream(writer);
Person p1=new Person("张三",18);
Person p2=new Person("李四",50);
Person p3=new Person("王五",26);
out.writeObject(p1);
out.writeObject(p2);
out.writeObject(p3);
out.flush();
//他也是可以正常运行的,取出的时候用推荐用数组,这里不再过多说明
这个问题我把它分成两种情况
一:文件中的类模板属性少于Java程序中的属性
二:文件中的类模板属性多于Java程序中的属性
这个问题不是没有,我们可能会根据各种需求,增加属性和删掉属性。比如:
//序列化时程序的属性
private String name;
private int age;
//反序列化时程序的属性
private String name;
private int age;
private int count;
//前后发生了运行时异常
java.io.InvalidClassException
原因是缺少一个序列化版本号,有了它才能更好的做序列化和反序列化之间的”兼容“操作,保证对象的构建和拆解是统一的。
//序列化版本号:
private final static long serialVersionUID = 2472549717346527430L;
//序列化版本号的值可以手动设置,是一个long类型
//再来试试加了序列化版本号之后的效果:
//序列化时的程序的属性
private String name;
private int age;
private final static long serialVersionUID = 2472549717346527430L;
//反序列化时程序的属性
private String name;
private int age;
private int count;
private final static long serialVersionUID = 2472549717346527430L;
//最终的结果是程序正常运行
//反序列化时多的那个属性会初始化默认值
这里特别说明:序列化版本号一致的情况下:如果序列化的属性比反序列化的少,则反序列化时多出来的属性初始化默认值,如果序列化属性比反序列化时多,程序会自动去掉多的部分。
transient和static修饰的属性在序列化时不会被写入文件。