序列化与反序列化
public class Book {
String name;
double price;
public Book(String name, double price) {
this.name = name;
this.price = price;
}
// 输出对象时,自动调用的方法,将对象转换成字符串输出
// 对象没法输出,格式化对象,形成可以输出的字符串
public String toString() {
return "书名《"+name+"》,单价:"+price+"元";
}
}
public static void main(String[] args) {
Book book1 = new Book("凡人修仙传",43.5);
Book book2 = new Book("斗破苍穹",38.5);
System.out.println(book1); //输出对象,会打印出对象的hashcode编码(内存地址的一种表现方式)
System.out.println(book2);
}
此时运行程序的话,会输出两本书的数据,运行成功后,代码删除,电脑重启,那么,这两本书的数据,还存在吗 ?
答案不在,代码删除,就不能再生成,电脑重启,内存清空,数据也会丢失!
想办法,将两本书的数据保留下来!!!
将对象转换成字符串(字节序列) ,然后保存在计算机的硬盘的某个文件(txt)中,这样,电脑重启与否,硬盘上的文件是不会自动消失的。这样,就实现了“永久保存”的状态。
将对象转换成字节序列的过程(通俗点理解:一头牛,冰箱放不进去,大卸八块后,零散的才能放在冰箱里),就叫做“序列化”;反之叫做“反序列化”
为什么学习序列化:对象是存留内存中的,无法长期保存,只能保存在硬盘上才能永久保存!想要保存到硬盘上,就要转换成字节序列。这就是“序列化”
序列化代码:
-
将被序列化的类实现一个接口Serializable
-
将序列化的对象通过io流保存到硬盘文件中
public class Book implements Serializable { 省略... } public static void main(String[] args) throws IOException { Book book = new Book("凡人修仙传",43.5); System.out.println(book); //输出对象,会打印出对象的hashcode编码(内存地址的一种表现方式) //创建文件的流 FileOutputStream fis = new FileOutputStream("F:/book.txt"); //输出数据的流 ObjectOutputStream oos = new ObjectOutputStream(fis); //将book对象输入到book.txt文件中 oos.writeObject(book); //释放资源 oos.close(); fis.close(); }
运行结果如下:
反序列化代码:
public static void main(String[] args) throws Exception {
FileInputStream fis = new FileInputStream("F:/book.txt");
ObjectInputStream ois = new ObjectInputStream( fis );
//将序列化的文件,读取成一个对象
Book book = (Book)ois.readObject();
System.out.println(book);
ois.close();
fis.close();
}
Q: 一个类在实现序列化接口的时候,生成的版本id是干什么的?
private static final long serialVersionUID = 1L;
解决: 同学, 有一种情况,序列化时,用的JDK1.5,而反序列化时,用的是JDK1.6,
统一版本,就依靠这个ID!
集合容器
- 之前学习的知识点中,能够装很多数据的结构,只有数组,但是数组往往不能满足我们日常开发的各种需求。java提供了“集合框架”这种体系,里面提供了很多种容器,就像我们的生活中存在很多种不同包,装行李的,装电脑的,装钱的,妆化妆品的等等
- java提供的这么多不同的容器,答题分为三个种类
- List
- Set
- Map
List接口
- List 接口存储一组不唯一,有序(插入顺序)的对象。(可以储存重复的数据,而且有下标,所以是有序的)
- List可以理解为“动态的数组”
- List本质上就是数组,只不过比数组更高级一些,高级提现在动态上,
- 普通的数组,一旦创建,长度不可修改。(木质的衣柜,制作后,内容无法改变)
- List的长度,是跟随元素的个数而变化(元素少了,收缩。元素多了,膨胀,更像一个有弹性的气球)
1、实现类ArrayList
动态数组的储存方式
特色:访问元素的效率高,删除和添加的效率低
public class Test1_ArrayList {
public static void main(String[] args) {
ArrayList list = new ArrayList(); // 一个集合(狗笼子)
Dog d1 = new Dog("大G", "哈士奇");
Dog d2 = new Dog("赛文", "拉布拉多");
Dog d3 = new Dog("捷豹", "德国黑背");
System.out.println("共有" + list.size() + "条狗");
list.add(d1); // 将狗放在笼子里
list.add(d2);
list.add(d3);
System.out.println("共有" + list.size() + "条狗");
//删除元素
list.remove(1);
for(int i = 0 ;i < list.size(); i++) {
Dog d = (Dog)list.get(i);
System.out.println(d);
}
}
}
class Dog {
String name;// 昵称
String brand;// 品种
public Dog(String name, String brand) {
this.name = name;
this.brand = brand;
}
public String toString() {
return name+",是一条"+brand;
}
}
2、实现类LinkedList
双向链表的存储方式
特色:删除和添加的效率高,访问元素的效率低
public static void main(String[] args) {
LinkedList list = new LinkedList();
Dog d1 = new Dog("1大G", "哈士奇");
Dog d2 = new Dog("2赛文", "拉布拉多");
Dog d3 = new Dog("3捷豹", "德国黑背");
list.add(d1);
list.addFirst(d2); //将d2添加到集合的第一个位置上
list.addFirst(d3);
//321
//将元素添加到集合中时,会自动发生一个 向上转型(数据类型提升为Object)的过程
for(Object x : list) {
//所以,往出拿元素时,需要把object向下转回dog
Dog d = (Dog) x;
System.out.println(d);
}
}
foreach循环
遍历数组或集合,可以考虑使用for循环的增强版,叫做foreach循环
语法:
for( 1 2 : 3 ){
}
1:数据类型(数组中元素的类型或者集合中元素的类型)
2:迭代变量(每一个元素的对象名称,随便起名)
3:要遍历的集合或数组
int arr[] = {3,1,2,4,7,6,5};
for(int a : arr) {
System.out.println(a);
}
3、实现类Vector
动态数组的储存方式
特色:访问元素的效率高,删除和添加的效率低
Vector和Arralist,98%是一模一样的。只有两点区别
-
Vector重视线程安全,所以效率较低。而ArrayList重视效率,所以线程不安全;
-
Vector按照倍数增长。而ArrayList按50%增长!
public static void main(String[] args) { Vector list = new Vector(); Dog d1 = new Dog("大G", "哈士奇"); Dog d2 = new Dog("赛文", "拉布拉多"); Dog d3 = new Dog("捷豹", "德国黑背"); list.addElement(d1); list.addElement(d2); list.addElement(d3); // 获得集合中所有的元素 Enumeration en = list.elements(); while (en.hasMoreElements()) {// 如果存在元素,就循环 Object o = en.nextElement(); Dog d = (Dog) o; System.out.println(d); } }