2022年9月22日 08:50 周四代码
#
public class Son extends Father{
private int i=test();
private static int j=method();
static {
System.out.print("(6)");
}
Son(){
System.out.print("(7)");
}
{
System.out.print("(8)");
}
public int test(){
System.out.print("(9)");
return 1;
}
public static int method(){
System.out.print("(10)");
return 1;
}
public static void main(String[] args) {
Son s1=new Son();
System.out.println();
Son s2=new Son();
}
}
public class Father {
private int i=test();
private static int j=method();
static {
System.out.print("(1)");
}
Father(){
System.out.print("(2)");
}
{
System.out.print("(3)");
}
public int test() {
System.out.print("(4)");
return 1;
}
public static int method() {
System.out.print("(5)");
return 1;
}
}
输出:
...
2022年9月21日 14:22 周三特点
#
- 该类只有一个实例
- 该类内部自行创建该实例
- 能向外部提供这个实例
几大方法
#
饿汉式
#
随着类的加载进行初始化,不管是否需要都会直接创建实例对象
public class Singleton1 {
public static final Singleton1 INSTANCE=new Singleton1();
private Singleton1() {
}
}
枚举
#
枚举类表示该类型的对象是有限的几个
public enum Singleton2 {
INSTANCE
}
使用静态代码块
#
随着类的加载进行初始化
public class Singleton2 {
public static final Singleton2 INSTANCE;
static {
INSTANCE = new Singleton2();
}
private Singleton2() {
}
}
如图,当初始化实例时需要进行复杂取值操作时,可以取代第一种方法

懒汉式
#
延迟创建对象
public class Singleton4 {
//为了防止重排序,需要添加volatile关键字
private static volatile Singleton4 INSTANCE;
private Singleton4() {
}
/**
* double check
* @return
*/
public static Singleton4 getInstance() {
//2 先判断一次,对于后面的操作(此时已经创建了对象)能减少加锁次数
if (INSTANCE == null) {
//如果这里不加锁会导致线程安全问题,可能刚进了判断语句之后,执行权被剥夺了又创建好了对象,
//所以判断及创建对象必须是原子操作
synchronized (Singleton4.class) {
if (INSTANCE == null) {
//用来模拟多线程被剥夺执行权
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//如果这个地方不加volatile,会出现的问题是,指令重排 1,2,3是正常的,
//会重排成1,3,2 然后别的线程去拿的时候,判断为非空,但是实际上运行的时候,发现里面的数据是空的
//1 memory = allocate();//分配对象空间
//2 instance(memory); //初始化对象
//3 instance = memory; //设置instance指向刚刚分配的位置
INSTANCE = new Singleton4();
}
}
}
return INSTANCE;
}
}
使用静态内部类
#
public class Singleton6 {
private Singleton6(){
}
private static class Inner{
private static final Singleton6 INSTANCE=new Singleton6();
}
public static Singleton6 getInstance(){
return Inner.INSTANCE;
}
}
- 只有当内部类被加载和初始化的时候,才会创建INSTANCE实例对象
- 静态内部类不会自动随着外部类的加载和初始化而初始化,他需要单独去加载和初始化
- 又由于他是在内部类加载和初始化时,创建的,属于类加载器处理的,所以是线程安全的
2022年9月21日 10:04 周三题目
#
int i=1;
i=i++;
int j=i++;
int k = i+ ++i * i++;
System.out.println("i="+i);
System.out.println("j="+j);
System.out.println("k="+k);
讲解
#
对于操作数栈和局部变量表的理解
#
对于下面的代码
反编译之后,查看字节码
0 bipush 10
2 istore_1
3 bipush 9
5 istore_2
6 iload_1
7 istore_2
8 return
如下图,这三行代码,是依次把10,9先放到局部变量表的1,2位置。
之后呢,再把局部变量表中1位置的值,放入操作数栈中
最后,将操作数栈弹出一个数(10),将数值赋给局部变量表中的位置2
如上图,当方法为静态方法时,局部变量表0位置存储的是实参第1个数
(当方法为非静态方法时,局部变量表0位置存储的是this引用)
对于下面这段代码
int i=10;
int j=20;
i=i++;
j=++j;
System.out.println(i);
System.out.println(j);
编译后的字节码
...