类加载器与单例

当使用不同的类加载器时,也会使单例失效,如下: 
单例为:
 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public final class Singleton{
     
     private static final Singleton instance= new Singleton();
     
     private Singleton(){
                 System.out.println( "执行构造函数" );
         System.out.println( "类加载器=" + this .getClass().getClassLoader());
     }
     
     public static Singleton getInstance(){
         return instance;
     }
 
}

自定义的类加载器为:  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
public class MyClassLoader extends ClassLoader{
     
     private String name;
     private String classPath;
     
     public MyClassLoader(String name){
         super ( null );
         this .name = name;
     }
     
     @Override
     protected Class<?> findClass(String name) throws ClassNotFoundException {
         byte [] b=getClassBytes(name);
         return this .defineClass(name, b, 0 ,b.length);
     }
 
     private byte [] getClassBytes(String name) {
         String classFullPath=classPath+ "/" +name.replace( "." , "/" )+ ".class" ;
         byte [] data= null ;
         try {
             FileInputStream fileInputStream= new FileInputStream(classFullPath);
             ByteArrayOutputStream out= new ByteArrayOutputStream();
             IOUtils.copy(fileInputStream,out);
             data=out.toByteArray();
         } catch (Exception e) {
             e.printStackTrace();
         }
         return data;
     }
     
     public String getName() {
         return name;
     }
 
     public void setName(String name) {
         this .name = name;
     }
 
     public String getClassPath() {
         return classPath;
     }
 
     public void setClassPath(String classPath) {
         this .classPath = classPath;
     }
 
}

测试案例如下:  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public static void testClassLoader() throws Exception{
         Singleton singleton=Singleton.getInstance();
         
         MyClassLoader myClassLoader= new MyClassLoader( "myClassLoader" );
         myClassLoader.setClassPath( "D:/important" );
         Class singletonClass=myClassLoader.findClass( "com.lg.design.singleton.hungry.Singleton" );
         System.out.println( "singletonClass.getClassLoader() : " +singletonClass.getClassLoader());
         
         System.out.println( "Singleton.class==singletonClass : " +(Singleton. class ==singletonClass));
         System.out.println( "Singleton.class.equals(singletonClass) : " +(Singleton. class .equals(singletonClass)));
         
         Constructor constructor1=Singleton. class .getDeclaredConstructor();
         Constructor constructor2=Singleton. class .getDeclaredConstructor();
         Constructor constructor3=singletonClass.getDeclaredConstructor();
         System.out.println( "constructor1==constructor2 : " +(constructor1==constructor2));
         System.out.println( "constructor1.equals(constructor2) : " +constructor1.equals(constructor2));
         System.out.println( "constructor1==constructor : " +(constructor1==constructor3));
         System.out.println( "constructor1.equals(constructor3) : " +constructor1.equals(constructor3));
         
         constructor1.setAccessible( true );
         Object singleton1=constructor1.newInstance();
         constructor3.setAccessible( true );
         Object singleton3=constructor3.newInstance();
         
         System.out.println( "singleton : " +singleton);
         System.out.println( "singleton1 : " +singleton1);
         System.out.println( "singleton3 : " +singleton3);
         System.out.println( "singleton1==singleton3 : " +(singleton1==singleton3));
     }

输出结果为:  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
执行构造函数
类加载器=sun.misc.Launcher$AppClassLoader @417470d0
singletonClass.getClassLoader() : com.lg.design.singleton.hungry.MyClassLoader @470d1f30
Singleton. class ==singletonClass : false
Singleton. class .equals(singletonClass) : false
constructor1==constructor2 : false
constructor1.equals(constructor2) : true
constructor1==constructor : false
constructor1.equals(constructor3) : false
执行构造函数
类加载器=sun.misc.Launcher$AppClassLoader @417470d0
singleton : com.lg.design.singleton.hungry.Singleton @77e3cabd
singleton1 : com.lg.design.singleton.hungry.Singleton @c137bc9
singleton3 : com.lg.design.singleton.hungry.Singleton @5323cf50
singleton1==singleton3 : false

咱们慢慢来看这些信息。 
1 Singleton.class与singletonClass 
前者是系统类加载器加载器的,后者是我们自定义的类加载器加载的,虽然他们的字节码相同,但由不同的类加载器加载后就是不同的类了,所以两者的==和eaquals都为false。 
2 constructor1、constructor2、constructor3 
constructor1、constructor2都是通过调用Singleton.class.getDeclaredConstructor()得来的,但是两者并不是同一个对象,他们的==为false,equals为true。看getDeclaredConstructor源码就可以理解:
 
?
1
2
3
4
5
6
7
8
9
10
11
12
13
private Constructor<T> getConstructor0(Class<?>[] parameterTypes,
                                         int which) throws NoSuchMethodException
     {
         Constructor<T>[] constructors = privateGetDeclaredConstructors((which == Member.PUBLIC));
         for (Constructor<T> constructor : constructors) {
             if (arrayContentsEq(parameterTypes,
                                 constructor.getParameterTypes())) {
                 //这里在获取构造器的时候就是用的复制
                 return getReflectionFactory().copyConstructor(constructor);
             }
         }
         throw new NoSuchMethodException(getName() + ".<init>" + argumentTypesToString(parameterTypes));
     }

再看构造器的eequals方法  
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public boolean equals(Object obj) {
         if (obj != null && obj instanceof Constructor) {
             Constructor<?> other = (Constructor<?>)obj;
             if (getDeclaringClass() == other.getDeclaringClass()) {
                 /* Avoid unnecessary cloning */
                 Class<?>[] params1 = parameterTypes;
                 Class<?>[] params2 = other.parameterTypes;
                 if (params1.length == params2.length) {
                     for ( int i = 0 ; i < params1.length; i++) {
                         if (params1[i] != params2[i])
                             return false ;
                     }
                     return true ;
                 }
             }
         }
         return false ;
     }

先通过比较是否是同一个类的构造器,然后再比较他们的参数是否一致,所以constructor1和constructor2的equals方法为true。对于constructor3和constructor1、constructor2,他们所属的类就是不一样的,即getDeclaringClass() == other.getDeclaringClass()为false。 

3 singleton1和singleton3 
singleton1是由constructor1构造器通过反射生成的对象,constructor3是通过constructor3构造器通过反射生成的对象,这些对象肯定都不是同一个对象。我有个疑问就是:通过constructor1.newInstance()会去执行Singleton的无参构造函数,打印出 

?
1
2
执行构造函数
类加载器=sun.misc.Launcher$AppClassLoader @417470d0

然而执行constructor3.newInstance()却并没有打印出无参构造函数中的信息,这背后的原理希望你们能帮我解答。 
有关类加载器的内容,请见后续文章 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值