类加载器与单例
程序员文章站
2022-04-03 16:03:34
...
当使用不同的类加载器时,也会使单例失效,如下:
单例为:
自定义的类加载器为:
测试案例如下:
输出结果为:
咱们慢慢来看这些信息。
1 Singleton.class与singletonClass
前者是系统类加载器加载器的,后者是我们自定义的类加载器加载的,虽然他们的字节码相同,但由不同的类加载器加载后就是不同的类了,所以两者的==和eaquals都为false。
2 constructor1、constructor2、constructor3
constructor1、constructor2都是通过调用Singleton.class.getDeclaredConstructor()得来的,但是两者并不是同一个对象,他们的==为false,equals为true。看getDeclaredConstructor源码就可以理解:
再看构造器的eequals方法
先通过比较是否是同一个类的构造器,然后再比较他们的参数是否一致,所以constructor1和constructor2的equals方法为true。对于constructor3和constructor1、constructor2,他们所属的类就是不一样的,即getDeclaringClass() == other.getDeclaringClass()为false。
3 singleton1和singleton3
singleton1是由constructor1构造器通过反射生成的对象,constructor3是通过constructor3构造器通过反射生成的对象,这些对象肯定都不是同一个对象。我有个疑问就是:通过constructor1.newInstance()会去执行Singleton的无参构造函数,打印出
然而执行constructor3.newInstance()却并没有打印出无参构造函数中的信息,这背后的原理希望你们能帮我解答。
有关类加载器的内容,请见后续文章
若想转载请注明出处: http://lgbolgger.iteye.com/blog/2161094
作者:iteye的乒乓狂魔
单例为:
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; } }
自定义的类加载器为:
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; } }
测试案例如下:
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)); }
输出结果为:
执行构造函数 类加载器=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源码就可以理解:
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方法
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的无参构造函数,打印出
执行构造函数 类加载器=sun.misc.Launcher$AppClassLoader@417470d0
然而执行constructor3.newInstance()却并没有打印出无参构造函数中的信息,这背后的原理希望你们能帮我解答。
有关类加载器的内容,请见后续文章
若想转载请注明出处: http://lgbolgger.iteye.com/blog/2161094
作者:iteye的乒乓狂魔
上一篇: java类加载顺序和垃圾回收