静态内部类实现的单例模式是线程安全的
一、静态内部类(静态嵌套类)vs非静态内部类(内部类)
静态内部类
*静态内部类只能访问外部类的静态方法和静态属性,如果是private也能访问,其他则不能访问,创建对象不依赖外部类
*静态内部类可以定义静态的属性和方法
非静态内部类
- 内部类可以访问其所在类的属性(包括所在类的私有属性),内部类创建自身对象需要先创建其所在类的对象
- 可以定义内部接口,且可以定义另外一个内部类实现这个内部接口
- 内部类不能定义static元素
- 内部类可以多嵌套
总结
静态内部类和外部类是相互独立的,创建实例或者创建什么类型的对象都不受限制
非静态内部类是外部类的一部分,创建实例必须先创建外部类的实例,可以访问外部类的所有属性
二、类的初始化及对象创建
类的加载、链接、初始化
1.class文件(二进制)通过类的加载器(引导类加载器、自定义加载器)加载(双亲委派机制)到内存中,并创建java.lang.Class对象(类是一类事物的抽象,Class是类的抽象,抽象的抽象)
2.链接:
①验证:验证字节码文件格式等是否正确
②准备:类的静态变量分配内存,并设置默认值
③解析:符号引用转换为直接引用
3.初始化
初始化阶段是执行类构造器
类实例化的时机
1.使用new关键字创建对象
2.使用Class类的newInstance方法(反射机制)
3.使用Constructor类的newInstance方法(反射机制)
4.使用Clone方法创建对象
5.使用(反)序列化机制创建对象
类实例化的过程
static final 变量编译阶段分配内存空间并赋值→父类的类构造器
三、静态内部类创建单例对象怎么保证线程安全
package com.bo.singleton;
/*静态内部类创建单例对象*/
public class StaticInnerTest {
public StaticInnerTest() {
System.out.println("静态内部类无参构造函数");
}
public static StaticInnerTest getInstance() {
return Inner.sit;
}
//方法不需要设置同步
public static class Inner{
private static final StaticInnerTest sit = new StaticInnerTest();
}
public static void main(String[] args) {
StaticInnerTest s1 = StaticInnerTest.getInstance();
StaticInnerTest s2 = StaticInnerTest.getInstance();
System.out.println(s1==s2);
}
}
静态内部类的特点:外部类加载时不需要加载静态内部类,不被加载则不占用内存,(延迟加载)当外部类调用getInstance方法时,才加载静态内部类,静态属性保证了全局唯一,静态变量初始化保证了线程安全,所以这里的方法没有加synchronized关键字(JVM保证了一个类的 初始化在多线程下被同步加锁)