一、对象序列化
(一)对象序列化流使用
1、概述
将对象从内存中写到文件中
对象序列化流:
ObjectOutputStream 对象输出流,他也是一个包装流,可以把一个普通字节输出流包装为能写对象能力的流
将java对象的原始数据类型和内容写入OutputStream
对象反序列化流:
ObjectInputStream读取对象,对象输入流,它也是一个包装流,可以把一个普通字节输入流,包装为能读取对象能力的流
package com.offcn.demo02;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
public class Demo01 {
public static void main(String[] args) throws Exception{
String s = "我爱学习java";
FileOutputStream fos = new FileOutputStream("Day22/b/4.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(s);
oos.close();
fos.close();
}
}
2、自定义对象序列化
案例:创建一个Student类,提供一些属性,再创建一个Student对象,把这个学生对象写出文件中
package com.offcn.demo02;
import java.io.Serializable;
public class Person implements Serializable {
private String name;
private int age;
public Person() {
}
public Person(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 "Person{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.offcn.demo02;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class Demo02 {
public static void main(String[] args) throws IOException {
Person p = new Person("tom",19);
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Day22/b/person.txt"));
oos.writeObject(p);
oos.close();
}
}
注意事项:
①一个对象要想被序列化,该对象所属的类必须实现Serializable接口
②Serializable是一个标记接口,实现该接口,不需要重写任何方法
3、对象反序列化流使用
对象反序列化介绍:
就是将持久化保存的对象,按照字节顺序进行读取
ObjectInputStream:
ObjectInputStream反序列化前先使用ObjectInputStream编写的原始数据和对象
package com.offcn.demo03;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class Demo01 {
public static void main(String[] args) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Day22/b/4.txt"));
Object o = ois.readObject();
System.out.println(o);
ois.close();
}
}
package com.offcn.demo03;
import com.offcn.demo02.Person;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
public class Demo02 {
public static void main(String[] args) throws Exception{
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Day22/b/person.txt"));
Person p = (Person)ois.readObject();
ois.close();
System.out.println(p.getName());
System.out.println(p.getAge());
System.out.println(p);
}
}
二、Properties类【必须掌握的知识点】
1、Properties
介绍:
表示一个持久的属性集
属性集:属性名称和属性值的对应关系,其实还是个双列集合
持久的:可以保存到流中,也可以从流中取出,可以很方便和文件进行交互
是一个Map体系的集合类,是Hashtable的子类
属性列表中的每个键及其对应的值都是一个字符串,因此不需要写泛型
2、Properties特有方法
package com.offcn.demo04;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class Demo01 {
public static void main(String[] args) throws IOException {
Properties p = new Properties();
p.setProperty("name","tom");
p.setProperty("age","18");
p.setProperty("gender","男");
System.out.println(p.getProperty("name"));
Set<String> strings = p.stringPropertyNames();
for (String string : strings) {
System.out.println(string+"----"+p.getProperty(string));
}
}
}
3、Properties和IO流相结合的方法
Properties操作的文件是有要求的,必须是.properties文件
package com.offcn.demo04;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Properties;
import java.util.Set;
public class Demo01 {
public static void main(String[] args) throws IOException {
Properties p = new Properties();
p.setProperty("name","tom");
p.setProperty("age","18");
p.setProperty("gender","男");
System.out.println(p.getProperty("name"));
Set<String> strings = p.stringPropertyNames();
for (String string : strings) {
System.out.println(string+"----"+p.getProperty(string));
}
p.store(new FileWriter("Day22/b/per.properties"),null);
}
}
注意事项:
①使用prop修改了属性值后,文件中的属性值不会发生变化,因为prop值修改了内存中的对象数据,没有同步到文件中,必须调用store方法之后,才能将变化同步到文件
②调用store方法时,一般需要指定更新属性的原因,即第二个参数comments,如果没有注释,可以传入null;如果有注释,必须是纯英文的。
三、线程相关概念
(一)进程和线程的区别
1、进程:
是指一个内存中运行的应用程序(已经在内存中运行的程序). 一个进程都有一个独立的
内存空间,一个电脑(手机)可以同时运行多个进程;进程也是程序的一次执行过程,是系统
运行程序的基本单位;
2、线程:
线程是进程中的一个执行单元(线程是依赖于进程的),负责当前进程中程序的执行,
一个进程中至少有一个线程(单线程程序)。一个进程中是可以有多个线程的,这个应用程序
也可以称之为多线程程序。
线程本身不具备申请操作系统资源能力,他必须依赖进程,才能使用操作系统的资源
(二)并行和并发
并行:指两个或多个事件在同一时间发生(同时发生,同时处理,执行者不是一个)
并发:指两个或多个事件在同一个时间段内发生(交替的发生 执行者是一个)
(三)java实现多线程的三种方式
1、继承Thead类
Thread就是一个线程类,里面定义所有和线程相关的功能,只有这个类才能开启的人物,才能被cpu单独去执行
方法:
实现步骤:
定义一个类MyThread继承Thread类
在MyThread类中重写run()方法,添加自己的任务
创建MyThread类的对象
启动线程
注意事项:千万不要使用线程对象调用run方法
package com.offcn.demo05;
public class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("我爱java...."+i);
System.out.println(getName());
}
}
}
package com.offcn.demo05;
public class Demo01 {
public static void main(String[] args) {
MyThread m = new MyThread();
m.start();
for (int i = 0; i <1000 ; i++) {
System.out.println("java使我快乐..."+i);
}
}
}
2、实现Runnable接口
里面只有一个抽象方法 一个抽象方法:run,用来定义线程中要执行的任务内容。这个Runnable仅仅就是一个任务而已,需要把任务绑定到线程中
方法:
解释:
Thread的构造方法创建对象的时候传入了Runnable接口的对象 ,Runnable接口对象重写run方法相当于
指定线程任务,创建线程的时候绑定了该线程对象要干的任务
Runnable的对象称之为:线程任务对象 不是线程对象 必须要交给Thread线程对象
通过Thread的构造方法, 就可以把任务对象Runnable,绑定到Thread对象中, 将来执行start方法,就会 自动执行 Runnable实现类对象中的run里面的内容.
注意:之所以提供第二种实现线程方式,是为了提供任务的复用性,解开了任务和线程之间的耦合性
实现步骤:
定义一个类MyRunnable实现Runnable接口
在MyRunnable类中重写run()方法
创建MyRunnable类的对象
创建Thread类的对象,把MyRunnable对象作为构造方法的参数
启动线程
package com.offcn.demo06;
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 1000; i++) {
System.out.println("我是一个任务.....");
}
}
}
package com.offcn.demo06;
public class Demo01 {
public static void main(String[] args) {
MyRunnable mr = new MyRunnable();
Thread t = new Thread(mr);
Thread t2 = new Thread(mr);
t2.start();
t.start();
for (int i = 0; i <1000 ; i++) {
System.out.println("我是主线程.....");
}
}
}
3、实现Callable接口
方法:
FutureTask实现了RunnableFuture接口,而RunnableFuture是Runnable接口子接口,所以FutureTask对
象就可以看做一个Runnable接口实现类对象使用, 可以通过Thread类的Thread(Runnable target)或
Thread(Runnable target String name)构造方法,把FutureTask对象绑定到线程对象中.
通过观察FutrueTask构造方法, 发现有一个构造中可以接受一个Callable类型的参数. Callable也是一个任务接口,里面用来定义线程中要执行任务,只不过Callable中任务在执行完成之后会给线程调用者一个反馈.因为Callable中的call会在任务执行完给提供反馈
实现步骤
定义一个类MyCallable实现Callable接口
在MyCallable类中重写call()方法 这就是线程任务方法.这个方法有返回值.
创建MyCallable类的对象
创建FutureTask的实现类FutureTask对象,把MyCallable对象作为构造方法的参数
创建Thread类的对象,把FutureTask对象作为构造方法的参数
启动线程
再调用get方法,就可以获取线程结束之后的结果。 call方法什么时候执行完,get才会执行.就可以拿到任务执行完后结果.
package com.offcn.demo07;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<String> {
@Override
public String call() throws Exception {
for (int i = 0; i <1000 ; i++) {
System.out.println("线程任务...."+i);
}
return "任务结束";
}
}
package com.offcn.demo07;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
public class Demo01 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyCallable mc = new MyCallable();
FutureTask<String> ft = new FutureTask<>(mc);
Thread t = new Thread(ft);
t.start();
for (int i = 0; i < 1000; i++) {
System.out.println("主线程...");
}
System.out.println(ft.get());
}
}
四、线程Thread类常用方法
(一)线程API之线程名称
package com.offcn.demo08;
import com.offcn.demo05.MyThread;
public class Demo01 {
public static void main(String[] args) {
MyThread mt1 = new MyThread();
System.out.println(mt1.getName());
MyThread mt2 = new MyThread();
System.out.println(mt2.getName());
Thread t = new Thread();
System.out.println(t.getName());
}
}