序列化:将对象按照流的方式存储到文本文件中或者再网络中传输 对象---->流数据
序列化流 (ObjectOutputStream)
Serializable:接口 没有构造方法,没有字段,也没有方法
接口---->标记接口
自定义类要实现序列化功能,必须实现接口Serializable接口
类实现了serializable也意味着他是标记类
假设之前操作针对Peroson操作序列的时候,产生一个标记 Preson.class--->固定ID 100
name -100
age -100
已经序列化完毕了,然后又修改了Person类里面的一些东西,加入了toString()
Person.class---固定id -- 200
org.westos_01.Person; local class incompatible:
stream classdesc serialVersionUID = -428218385429329797,
local class serialVersionUID = -5865763454468005049
因为手动修改了这些类的属性/成员变量,将序列化版本Id改变了
InvalidClassException:一般情况:该类的序列版本号与从流中读取的类描述符的版本号不匹配
实际开发中,不想多次对当前这些序列化,如果这样做,非常麻烦?
如何解决呢?
让当前实现类序列化功能的这个类产生一个固定ID,注意看程序有黄色警告线,直接就点它来固定Id
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
public Object setProperty(String key, String value) :给属性列表中添加键和值,并且强制都使用String
public Set<String> stringPropertyNames():遍历的功能
public void store(Writer writer,String comments):把集合中的数据保存文本文件中(属性集合)
public void load(Reader reader):将文本文件中的数据加载到属性集合中
举例:
分析:
1)读取文件的内容,将文件内容加载属性集合类中
2)遍历属性集合,获取所有的键的集合
3)遍历的键的时候,可以判断是否有"lisi"这样一个键
4)有的话,就更改
反序列化:将文本文件中的流对象或者网络传输中的流对象还原成对象 流数据--->对象 反序列化流(ObjectInputStream)
public class ObjectDemo {
public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
// write() ;
read();
}
//反序列化
private static void read() throws FileNotFoundException, IOException, ClassNotFoundException {
//创建反序列化流对象
//public ObjectInputStream(InputStream in)
ObjectInputStream in = new ObjectInputStream(new FileInputStream("oos.txt")) ;
//读
//public final Object readObject():从 ObjectInputStream 读取对象。
Object obj = in.readObject() ;
in.close();
System.out.println(obj);//Person [name=高圆圆, age=27]
}
//序列化
private static void write() throws FileNotFoundException, IOException {
//创建一个序列化流对象
//public ObjectOutputStream(OutputStream out)
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("oos.txt")) ;
//创建一个Person类对象
Person p = new Person("高圆圆", 27) ;
//public final void writeObject(Object obj)
oos.writeObject(p);
//关闭资源
oos.close();
}
}
java.io.NotSerializableException :当前类未实现序列化功能的异常
Serializable:接口 没有构造方法,没有字段,也没有方法
接口---->标记接口
自定义类要实现序列化功能,必须实现接口Serializable接口
类实现了serializable也意味着他是标记类
假设之前操作针对Peroson操作序列的时候,产生一个标记 Preson.class--->固定ID 100
name -100
age -100
已经序列化完毕了,然后又修改了Person类里面的一些东西,加入了toString()
Person.class---固定id -- 200
org.westos_01.Person; local class incompatible:
stream classdesc serialVersionUID = -428218385429329797,
local class serialVersionUID = -5865763454468005049
因为手动修改了这些类的属性/成员变量,将序列化版本Id改变了
InvalidClassException:一般情况:该类的序列版本号与从流中读取的类描述符的版本号不匹配
实际开发中,不想多次对当前这些序列化,如果这样做,非常麻烦?
如何解决呢?
让当前实现类序列化功能的这个类产生一个固定ID,注意看程序有黄色警告线,直接就点它来固定Id
比如:当前的这个类中有很多属性(性别,地址,学号...),某些属性不想被序列化,如何解决这样一个问题
transient int age ;用transient来修饰这个类的属性,就不会被序列化
public class Person implements Serializable{
//产生随机的固定Id
private static final long serialVersionUID = 3929786557947102117L;
private String name ;
// private int age ;
// public int age ;
transient int age ;//这样这个类的属性就不会被序列化
public Person() {
super();
}
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;
}
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + "]";
}
}
Properties:表示了一个持久的属性集(简称:属性集合类) extends Hashtable<K,V> Map集合的
可保存在流中或从流中加载。属性列表中每个键及其对应值都是一个字符串。
public Properties():无参构造
public class PropertiesDemo {
public static void main(String[] args) {
//它继承Hashtable
//创建一个属性集合类对象
Properties prop = new Properties() ;
System.out.println(prop);
System.out.println("---------------------");
//给属性集合类中的属性列表添加元素
prop.put("高圆圆", "赵又廷") ;
prop.put("文章", "马伊琍") ;
prop.put("黄晓明", "baby") ;
System.out.println(prop);
//遍历属性集合类
Set<Object> keySet = prop.keySet() ;
for(Object key :keySet) {
Object value = prop.get(key) ;
System.out.println(key+"="+value);
}
}
}
属性集合类的特有功能:
public Object setProperty(String key, String value) :给属性列表中添加键和值,并且强制都使用String
public Set<String> stringPropertyNames():遍历的功能
public String getProperty(String key)用指定的键在此属性列表中搜索属性
public class PropertiesDemo2 {
public static void main(String[] args) {
//创建属性集合类对象
Properties prop = new Properties() ;
//添加元素
prop.setProperty("张三", "20") ;
prop.setProperty("李四", "22") ;
prop.setProperty("王五", "18") ;
//遍历
//获取所有的键的集合
Set<String> keyset = prop.stringPropertyNames() ;
for(String key:keyset) {
//通过键找值
String value = prop.getProperty(key) ;
System.out.println(key+"----"+value);
}
}
}
可保存在流中或从流中加载,只能使用属性集合类
public void store(Writer writer,String comments):把集合中的数据保存文本文件中(属性集合)
public void load(Reader reader):将文本文件中的数据加载到属性集合中
举例:
打游戏:游戏进度的保存和游戏加载
public class PropertiesDemo3 {
public static void main(String[] args) throws IOException {
// MyStore();
MyLoad();
}
//将文本文件中的数据加载属性集合类中
private static void MyLoad() throws IOException {
//创建属性集合类对象
Properties prop =new Properties() ;
//public void load(Reader reader):将文本文件中的数据加载到属性集合中
FileReader fr = new FileReader("prop.txt") ;
//加载
prop.load(fr);
fr.close();
System.out.println(prop);
}
//将属性集合中的数据保存到文本文件中
private static void MyStore() throws IOException {
//创建一个属性集合类对象
Properties prop = new Properties() ;
//添加元素
prop.setProperty("张三", "20") ;
prop.setProperty("文章", "29") ;
prop.setProperty("成龙", "55") ;
//public void store(Writer writer,String comments):把集合中的数据保存文本文件中(属性集合)
FileWriter fw = new FileWriter("name.txt") ;
//将数据保存到文本文件中
prop.store(fw, "names'content");
//释放资源
fw.close();
}
}
需求:我有一个文本文件(user.txt),我知道数据是键值对形式的,但是不知道内容是什么。请写一个程序判断是否有“lisi”这样的键存在,如果有就改变其实为”100
分析:
1)读取文件的内容,将文件内容加载属性集合类中
2)遍历属性集合,获取所有的键的集合
3)遍历的键的时候,可以判断是否有"lisi"这样一个键
4)有的话,就更改
5)需要将当前属性集合类中的保存文本文件中
public class PropertiesTest {
public static void main(String[] args) throws IOException {
//创建属性集合类对象
Properties prop = new Properties() ;
//读取文本文件内容加载到集合中
FileReader fr = new FileReader("user.txt") ;
prop.load(fr);
fr.close();
//遍历属性集合
//获取所有的键的集合
Set<String> keySet = prop.stringPropertyNames() ;
for(String key:keySet) {
//判断
if("lisi".equals(key)) {
//更改
prop.setProperty(key, "100") ;
}
}
//将属性集合中的数据保存文本文件中
FileWriter fw = new FileWriter("user.txt") ;
prop.store(fw, "content");
fw.close();
}
}
需求:
我有一个猜数字小游戏的程序,请写一个程序实现在测试类中只能用5次,超过5次提示:游戏试玩已结束,请付费。
public class PropertiesTest2 {
public static void main(String[] args) throws IOException {
//创建文件
/*File file = new File("content.txt") ;
if(file!=null) {
file.createNewFile() ;
}*/
//将文件的内容加载到属性集合中
Properties prop = new Properties() ;
//创建字符输入流
FileReader fr = new FileReader("count.txt") ;
prop.load(fr);
fr.close();
//现在有内容了,通过键获取当前对应的值(String)
String value = prop.getProperty("count") ;
//String--->int
int number = Integer.parseInt(value) ;
//判断
//超过5次提示:游戏试玩已结束,请付费。
if(number >5) {
System.out.println("游戏试玩接收,请您付费...");
System.exit(0);
}else {
number ++ ;
prop.setProperty("count", String.valueOf(number)) ;
FileWriter fw = new FileWriter("count.txt") ;
prop.store(fw, "game'content");
fw.close() ;
GetNumber.start();
}
}
}
public class GetNumber {
private GetNumber() {
}
//为了防止打断点的时候,黄色警告线会影响断点,所有加入强制解决
@SuppressWarnings("resource")
public static void start() {
//1-100随机数
int number = (int) (Math.random()*100+1) ;
//定义一个统计变量
int count = 0 ;
while(true) {
Scanner sc = new Scanner(System.in) ;
System.out.println("请输入要猜的数据:");
int guessNumber = sc.nextInt() ;
count ++ ;
if(guessNumber>number) {
System.out.println("你要猜的数据大了...");
}else if(guessNumber <number) {
System.out.println("你要猜的数据小了...");
}else {
System.out.println("恭喜您"+count+"次猜中了...");
break ;
}
}
}
}