一个据说第一次接触都会做错的Java面试题和类加载器的介绍

来源:互联网 发布:nginx epoll 编辑:程序博客网 时间:2024/03/29 02:40

首先什么话都不说,先把这个很变态的面试题放上来,大家有情趣自己分析一下,然后再运行一下看看结果,据说第

一次遇到这个题目的Java程序员都是会做错的。

[java] view plain copy
 print?
  1. package com.bird.classLoad;  
  2.   
  3. public class Test1 {  
  4.       
  5.     @SuppressWarnings("static-access")  
  6.     public static void main(String[] args) {  
  7.         Singleton s = Singleton.getSingleton();  
  8.         System.out.println("counter1 = "+ s.counter1);  
  9.         System.out.println("counter2 = "+s.counter2);  
  10.     }  
  11. }  
  12.   
  13.   
  14. class Singleton{  
  15.       
  16.     private static Singleton singleton = new Singleton();  
  17.       
  18.     public static int counter1;  
  19.       
  20.     public static int counter2 = 0;  
  21.       
  22.     public Singleton(){  
  23.         counter1++;  
  24.         counter2++;  
  25.     }  
  26.       
  27.     public static Singleton getSingleton(){  
  28.         return singleton;  
  29.     }  
  30.       
  31.       
  32. }  

如果你没有分析出来结果是1,0那么请您继续往下看。

首先介绍一下JVM对一个类的字节码class文件是如果装载到内存中然后被虚拟机执行的。

1.加载:查找并加载类的二进制数据
2.连接
2.1:确保被加载类的正确性
2.2:为类的静态变量分配内存,并将其初始化为默认值
2.3:把类中的符号引用转换为直接引用
3.初始化:为类的静态变量赋予正确的初始值


请注意,在连接的时候,为类的静态变量分配内存,初始化为默认值,然后才把类中的符号转换为指定的引用。

当然了,JVM只有在主动调用类的时候才回去加载一个类,主动调用一共有六种方式

Java虚拟机主动使用一个类的六种情况
1.创建类的实例
2.访问某个类或接口的静态变量,或者对该静态变量赋值
3.调用类的静态方法
4.反射
5.初始化一个类的子类
6.Java虚拟机启动时被标明为启动类的类
除了以上六种情况,其他都为被动使用,都不会执行类的初始化


然后对于类加载器

有两种类型的类加载器
1.根类加载器(使用C++编写,程序员无法在Java代码中获得该类)
2.扩展类加载器
3.系统类加载器


用户自定义类加载器
ClassLoader的子类


比如

[java] view plain copy
 print?
  1. package com.bird.classLoad;  
  2.   
  3. public class Test2 {  
  4.       
  5.     public static void main(String[] args) throws Exception {  
  6.         Class clazz = Class.forName("java.lang.String");  
  7.         System.out.println(clazz.getClassLoader());  
  8.           
  9.         Class clazz2 = Class.forName("com.bird.classLoad.A");  
  10.         System.out.println(clazz2.getClassLoader());  
  11.     }  
  12. }  
  13.   
  14. class A{}  
运行结果

[java] view plain copy
 print?
  1. null  
  2. sun.misc.Launcher$AppClassLoader@addbf1  

说明String类是JDK自带的,是使用默认根加载器加载的,它是使用C++编写的,所以才会返回null,SUN不允许直接

访问这个根加载器的。

然后对于自己写的类,当然是通过内部类application加载器加载的,虽然都能使用,但是底层加载方式各不相同。


最后我们来分析程序

首先执行Singleton s = Singleton.getSingleton();

主动调用 Singleton,这之后初始化Singleton类,为static变量初始化内存空间然后赋予默认值。所以,singleton为

null,counter1为0,counter2为0.

然后赋予引用值。singleton调用构造函数,这时候counter1等于1,counter2等于1.

然后顺次执行,counter1没有被赋值,counter2被赋值为0.

这次就返回这个对象了,所以最终结果为,1,0

总结一下,这道题真坑爹。

0 0
原创粉丝点击