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