java中的静态内部类与非静态内部类的联系
区别
1. 从使用上说:静态内部类中才能有静态属性和静态方法,非静态内部类中不能有静态属性和静态方法。
2. 从生命周期上说:静态内部随着外部类的加载而加载,不是伴随着外部类的对象产生而产生的。外部类的实例与静态内部类的实例没有任何关系的。而非静态内部类的实例是需要依赖外部类实例才能创建的。换句话说非静态内部类是附属在外部类实例基础之上的,需要先创建一个外部类的实例,通过外部类的实例才能实例化非静态内部类,而静态内部类是依附在外部类的。
这里需要注意的是:无论是静态内部类还是非静态内部类它们的加载时间是只有用到了内部类才会初始化加载,而不是外部类加载的时候。
验证静态内部类加载的时间与顺序
public class TestExecuteOrder {
public static int num=5;////第1次执行,并且只会执行一次
static {
Log.e("ssssss","outter class num:" + num);//第2次执行,并且只会执行一次
num=10;
}
public TestExecuteOrder() {
Log.e("sssssss","outter class contsructor num:" +num);//第3次执行,并且会执行多次
}
public static class StaticInnerClass {
public static long timeStamp=System.currentTimeMillis();//这里同样,只会执行一次
}
public class NormalInnerClass{
public int b=0;
}
public void getStaticInnerClassTime() {
//用到StaticInnerClass时才去加载静态内部类
Log.e("ssssss","getStaticInnerClassTimeStamp:" +StaticInnerClass.timeStamp);
}
public void test(){
TestExecuteOrder.StaticInnerClass staticInnerClass=new TestExecuteOrder.StaticInnerClass();//静态内部类实例化
TestExecuteOrder.NormalInnerClass normalInnerClass=new TestExecuteOrder().new NormalInnerClass();//非静态内部类实例化
}
1.上面代码示例中的test()方法演示了静态内部类与非静态内部类实例的创建方式
2.Log日志的输出结果依次为outter class num:5,outter class contsructor num:10,getStaticInnerClassNum2:1488956673146,outter class contsructor num:10,getStaticInnerClassNum2:1488956673146。
3.因此得出加载顺序为:静态属性—>静态代码块—->构造函数。其中静态属性与静态代码块在类加载的时候开始调用并且只会执行一次,而静态内部类只在调用getStaticInnerClassTime()方法的时候才进行加载并且只会加载一次。我们可以根据这个原理实现多线程安全的单例模式。
静态内部类实现线程安全的单例模式
public class Singleton {
private Singleton(){};//私有化构造函数,外部无法通过构造函数进行实例创建
/*
*懒汉式创建单例,调用getInstance时才开始创建
*/
public static Singleton getInstance(){
return SingletonHolder.instance;
}
private static class SingletonHolder{
private static Singleton instance=new Singleton();
}
}