最近在看单例模式的实现,看到有一种利用JAVA静态内部类的特性来实现,对于内部类我还真是不了解,遂了解了一下,代码贴上。
/**
* 内部类分为:成员内部类、局部内部类、匿名内部类和静态内部类。
*/
public class Demo { /*
* 1.成员内部类:成员内部类是最普通的内部类,
* 它的定义为位于另一个类的内部。
*/
class Inside1 {
public void say() {
System.out.println("Inside1 say...");
}
} /*
* 2.局部内部类:局部内部类是定义在一个方法或者一个作用域里面的类,
* 它和成员内部类的区别在于局部内部类的访问仅限于方法内或者该作用域内。
* 局部内部类就像局部变量一样,是不能有public、protected、private以及static修饰符的。
*/
public Demo fun1() {
class Woman extends Demo{
int age = 0;
}
return new Woman();
} /*
* 3.匿名内部类:匿名内部类在编译的时候由系统自动起名为Outter$1.class。
* 一般来说,匿名内部类用于继承其他类或是实现接口,并不需要增加额外的方法,只是对继承方法的实现或是重写
*/
public void fun2(){
new JFrame().addKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {}
public void keyReleased(KeyEvent e) {}
public void keyPressed(KeyEvent e) {}
});
} /*
* 4.静态内部类也是定义在另一个类里面的类,只不过在类的前面多了一个关键字static。
* 静态内部类是<b>不需要依赖于外部类</b>的,这点和类的静态成员属性有点类似,
* 并且它不能使用外部类的非static成员变量或者方法,这点很好理解,
* 因为在没有外部类的对象的情况下,可以创建静态内部类的对象,
* 如果允许访问外部类的非static成员就会产生矛盾,因为外部类的非static成员必须依附于具体的对象。
*/
static class Inside3{ } }
上面是内部类的声明,下面再Main类中去调用,看看有什么值得注意的:
public class Main { public static void main(String[] args) {
Demo demo = new Demo(); // 得到一个类的成员内部类,必须先获取外部类的对象实例
Inside1 inside1 = demo.new Inside1();
} }
注释也写清楚了,成员内部类就好像成员变量一样,首先得到类的信息必须先获取外部类的对象实例,然后再通过new来创建内部类的实例。
注意这个地方有个注意的地方,正如我们所知道的,成员变量会在类对象创建的时候都会进行初始化,那么成员内部类在外部类对象创建的时候有没有被加载?--这里引出另一个问题,如何查看一个是否加载?一种方法是在类中写static代码块,但是类加载的时候也可以不执行static代码块的,请看Class.forName()的重载方法,这里利用JDK提供的jVisualvm工具,能以可视化的方法,看到JVM内的情况,看测试代码:
public class Demo {
class Inside1 {
public void say() {
System.out.println("Inside1 say...");
}
}
}
先将Demo类写一个成员内部类,然后再Main类中创建外部类的对象,用JVisualVM查看Inside1类是否被加载。
public class Main { public static void main(String[] args) {
Demo demo = new Demo(); //为了能让此程序停住方便调试
new Scanner(System.in).nextLine();
} }
查看类是否Demo$Inside1类是否被加载:
可以看到,Demo开头的类,之家在了Demo类自己,也就是说当外部类生成实例对象的时候,外部类中内部类并不参与初始化。那么静态内部类呢?
下面将Demo中Inside内部类编程static静态的,然后再加载外部类或者创建外部类的实例,Main方法不变,看看什么情况:
public class Demo { static class Inside1 {
public void say() {
System.out.println("Inside1 say...");
}
} }
踏哒~
还是只有一个外部类Demo,所以说不管内部类是静态的还是非静态的,都不会因为外部类的类加载或者对象创建而去加载、初始化,一般是这样的,也有可能不是:
public class Demo { public Demo say() {
class Inside1 extends Demo{
}
return new Inside1();
} }
main方法还是不变,请看JVM类加载情况:
Inside1被加载了,至于为啥,我还不知道,希望有知道的可以指点一下。