前言:
本章……很重要,过程中需要思考:如何使单例模式遇到多线程是安全的、正确的!代码也比较多、代码……这个要不要写?写的话、占篇幅有点大
正文:
公用代码:
public class MyThread extends Thread {
public void run(){
System.out.println(MyObject2.getInstance().hashCode());
}
}
public class Run {
public static void main(String[] args) {
MyThread t1 = new MyThread();
MyThread t2 = new MyThread();
t1.start();
t2.start();
}
}
6.1立即加载/"饿汉模式"
立即加载:使用类的时候已经将对象创建完毕(如直接new实例化);调用方法的时候,实例已经创建
该部分主要synchronized和对null的判断解决多线程安全问题,在哪加锁在哪判空很重要,大段代码略过辣
6.2静态内部类实现单例【内部类】
/**
* 序列化:
* 父类序列化,内部类也要序列化;
* 静态变量不能被序列化,得到的值一直是最新的值(共享)
* https://blog.csdn.net/u010335298/article/details/51916582
* Created by majinxing on 2018/7/30.
*/
public class MyObject2 {
//内部类方式 世界上独此一份 也不错,静态内部类才可以被序列化
//遇到序列化对象,还是不行
/**
* java对象序列化要求对象all成员都实现序列化接口
* so内部类实现序列化而外部封装类没有实现
* so对内部序列化:报错,解决:序列化其父类
* 内部类,local内部类,匿名内部类
* 实例持有外部封装类实例的隐式引用
* 可直接访问外部封装类的实例变量和方法
* 静态嵌套类不能
*/
private static class MyObjectHandler{
private static MyObject2 myObject = new MyObject2();
}
private MyObject2(){};
public static MyObject2 getInstance(){
return MyObjectHandler.myObject;
}
}
2、非静态内部类隐含了一个指向外部类的引用,因此可访问外部类实例的成员
public class InnerClass {
private int attrib;
private static int staticAttrib;
public class Inner1{
private int a1;
public int method1(){
return attrib;
}
}
public static class StaticInner2{
private int sa1;
public int method2(){
return staticAttrib;
}
}
public int method(){
int a = new Inner1().a1;
a += new StaticInner2().sa1;
return a;
}
private int foo;
private int age;
public class Inner{
private int foo;
public int method(){
//非静态内部类隐含了一个指向外部类引用,
//可通过 外部类名.this 来在内部类中访问这个引用
//内 外部 成员重名 通外部类引用访问外部 成员 不重可省引用
return foo+InnerClass.this.foo+age;
}
}
}
java序列化失败的解决
1、修改外部类,外部类实现Serializable接口
2、修改内部类为静态,不会再引用外部类,
6.3序列化与反序列化的单例模式
MyObject
/**
* 一个类实现了 Serializable接口,就可把它往内存地写再从内存里读出而"组装"成一个跟原来一模一样的对象
* 遇到单例:从内存中读出而组装的 对象破坏了单例规则,反序列化 新对象克隆出来了=》readResolve 横空出世!
* Created by Administrator on 2018/7/31.
*/
public class MyObject3 implements Serializable {
private static final long serialVersionUID = 888L;
private static class MyObjectHandler {
private static final MyObject3 myObject = new MyObject3();
}
private MyObject3() {
}
public static MyObject3 getInstance() {
return MyObjectHandler.myObject;
}
/**
* 反序列化时直接返回此方法指定的对象,而不需要单独再创建新的对象
* 当JVM从内存中反序列化地"组装"一个新对象时,会自动调用这readResolve返回我们指定好的对象
* https://www.jb51.net/article/120538.htm
*/
protected Object readResolve() throws ObjectStreamException {
System.out.println("调 readReslove");
return MyObjectHandler.myObject;
}
}
业务类:
/**
* 最后结合的例子不错
* https://blog.csdn.net/lyb1832567496/article/details/52712218
* Created by majinxing on 2018/7/31.
*/
public class SaveAndRead {
public static void main(String[] args) {
try {
MyObject3 myObject = MyObject3.getInstance();
//OutputStream(输出流):输出流是用来写出数据的
//将数据写入到文件(myObjectFile.txt)中
FileOutputStream fosRef = new FileOutputStream(new File(
"myObjectFile.txt"));
ObjectOutputStream oosRef = new ObjectOutputStream(fosRef);
oosRef.writeObject(myObject);
oosRef.close();
fosRef.close();
System.out.println(myObject.hashCode());
} catch (
FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
try {
//从文件系统中某个文件中获得输入字节
//打开一个到实际文件的连接来创建一个 FileInputStream
FileInputStream fisRef = new FileInputStream(new File(
"myObjectFile.txt"));
ObjectInputStream iosRef = new ObjectInputStream(fisRef);
MyObject3 myObject = (MyObject3) iosRef.readObject();
iosRef.close();
fisRef.close();
System.out.println(myObject.hashCode());
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
不是同一个对象,但是、上面的代码块打开,便是同一个对象了,这是为什么呐?看偶滴这一篇 几件关于自定义序列化的小事;
下一篇吧,这篇虽然没说什么,但是已经够长的了~