序列化和反序列化
Java在运行时,如果需要保存对象的状态(即下次程序运行时,能够还原对象当前的状态),就需要使用到序列化操作。本质是吧对象保存为一个文件存到磁盘上,下次运行时从磁盘上读取文件,恢复对象。
网络程序:如果把一个对象从一台机器(虚拟机)发送到另外一台机器(虚拟机),这种情况也需要把对象序列化为二进制内容,然后再通过网络发送给另外一台机器,对方收到二进制内容,在反序列化为对象。
ObjectOutputStream 序列化
把正在运行的对象保存为文件;
要被序列化的对象的类要实现Serializable接口;
- Student
package com.hqyj;
import java.io.Serializable;
public class Student implements Serializable {
private String name;
private int age;
public Student() {
}
public Student(String name, int age) {
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;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
- 利用ObjectOutputStream的writeObject方法做序列化
package com.hqyj;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializeDemo {
public static void main(String[] args) {
/*Student student = new Student();
student.setName("张三");
student.setAge(18);*/
Student student = new Student("张三", 18);
ObjectOutputStream oos = null;
FileOutputStream fos = null;
try {
fos = new FileOutputStream("E:/student.data");
oos = new ObjectOutputStream(fos);
oos.writeObject(student);//序列化student对象
oos.flush();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}finally {
if(oos != null){
try {
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fos != null){
try {
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
ObjectInputStream 反序列化
- 调用readObject()反序列化,该方法返回的是Object,所以要强制类型转换;
- 读取的序列化的文件一定要是正确的序列化,并且要强制类型转换。
package com.hqyj;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
public class DeSerializeDemo {
public static void main(String[] args) {
FileInputStream fis = null;
ObjectInputStream ois = null;
try {
fis = new FileInputStream("E:/student.data");//之前序列化的文件名
ois = new ObjectInputStream(fis);
//读取序列化的文件,还原为原来的对象(对象的属性都还在)
Student student = (Student) ois.readObject();
System.out.println(student);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}finally {
if (ois != null){
try {
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (fis != null){
try {
fis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
复习
- 构造方法在什么时候使用?有参和无参的区别在哪里?
- 构造方法在创建对象(实例化)的时候会被调用(也就是使用new Xxx());
- 子类创建对象时会先调用父类的构造方法,然后再调用子类的构造方法,没有指定调用的构造方法时,会自动调用父类的无参构造方法。
- new的关键字使用的时候,类名后面的小括号里面有几个参数就会调用对应参数数量的构造方法。调用有参构造方法的目的是创建对象的同时给属性赋值。
常量池中存的是一种对象吗
- 常量池中存的也是对象,主要针对String类型,如果用字面量赋值的String变量,就会在常量池中创建一个对象;下一次再用相同的字符串给变量赋值的时候,就共用常量池中的一个对象;
- 基本类型赋值不会创建对象。
instanceof的作用是判断一个对象是否是某个类型。
关于方法的调用
- 方法是用来执行某一个特定功能的一段代码,方法可以重复使用,使main里面的代码尽量的简洁;
- 方法是类的一种组成部分。
方法的定义:
public int fun1(int i, String s){
//方法体,方法类的代码
return 0;
}
方法的调用:
int j = fun1(5, “abc”);
-
重写和重载的区别
-
可变长参数
定义方法时,参数类型后面跟三个点,这个参数就叫可变长参数,调用该方法可以传多个参数,可变长参数只能是最后一个参数。
-
方法里面的变量都是局部变量,方法里面的引用类型的变量只保存对象的地址,实际对象存在堆里面;
方法被调用的时候在栈里面会有一段内存(方法栈帧)保存局部变量,方法调用时入栈,方法调用结束后出栈,出栈后释放栈帧的内存,局部变量不可在访问。
如果方法里面调用另一个方法(如s调用b),a方法暂停运行,先执行b方法,等b方法执行结束后,在执行a方法。
try语句块中出现return语句,finally仍然会执行;
即便是在try语句块里面出现Error,Finally也会执行。
抽象 abstract
-
抽象可以修饰类,方法;
-
抽象方法,就是这个方法没有方法体(没有代码),抽象方法的目的是为了统一方法的定义,具体的实现交给子类去实现。一般来说抽象方法在每个子类中的实现都不一样。如果不规定方法名,每个子类就可能写出不同的方法名,不方便向上造型之后的统一调用方法;
-
一个类中只要有一个方法是抽象方法,这个类就必须定义为抽象类。抽象类中可以没有抽象方法;
-
如果抽象类中所有的方法都是抽象方法,这个抽象方法就可以定义为接口(interface),interface的子类就用implements关键字实现接口,可以实现对公接口,接口可以相互继承;
-
接口里面的方法如果不写访问修饰符,默认就是public,如果不写访问修饰符,默认就是public static final(常量)。
Static
static可以是修饰符,方法,属性,代码块;
static是属于类的,不属于对象;
- static在类加载的时候执行,不是创建对象时执行;
- static是所以对象共享的,不属于对象独有;
- static的访问可以直接用类名访问,static的方法只能访问static的属性或方法;
- 序列化时不会序列化类的静态成员。
练习
-
给出一个数组{5, 7, 20, 18, 6},找出数组中最大的元素。
-
public class Biggest { public static void main(String[] args) { int[] arr = {5, 7, 20, 18, 6}; int max = 0; for (int i = 1; i < arr.length; i++) { max = arr[max] > arr[i] ? max : i; } System.out.println(arr[max]); } }
-
双色球号码生成:
6个红球,红球范围1~32,随机生成,不能有重复;
1个蓝球,蓝球范围1~7
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
public class TwoColorBall {
public static void main(String[] args) {
Random random = new Random();
List<Integer> list = new ArrayList<>();
System.out.print("红球:");
for (int i = 0; i < 6; i++) {
int n = random.nextInt(32) + 1;
if (list.contains(n)){//判断是否重复,重复返回true,不重复返回false
i--;
}else{
list.add(n);
System.out.print(n + "\t");
}
}
System.out.println();
int m = random.nextInt(7) + 1;
System.out.println("蓝球:" + m);
}
}