当使用不同的类加载器时,也会使单例失效,如下:
单例为:
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的乒乓狂魔
分享到:
相关推荐
配置文件+类加载器(单例模式)操作 数据库
Singleton模式可以相当的复杂,比头五种模式加起来还复杂,譬如涉及到DCL双锁检测(double checked locking)的讨论、涉及到多个类加载器(ClassLoader)协同时、涉及到跨JVM(集群、远程EJB等)时、涉及到单例对象...
您可以在检查器中为预加载场景中的单例对象配置字段 入门 。 在Unity中打开项目。 通过扩展泛型来创建自己的Singleton类 类。 将您的单例类附加到_Preload场景中的GameManager游戏对象。 编辑检查器中的变量 ...
由于引导类加载器涉及到虚拟机本地实现细节,开发者无法直接获取到启动类加载器的引用, 所以 不允许直接通过引用进行操作。 2. 拓展类加载器(Extension classLoader): 扩展类加载器是...
这假设您将包管理器与模块捆绑器(如或一起使用来使用。 什么是单例钩子 单例钩子在功能方面与 React Context 非常相似。 每个单例钩子都有一个主体,您可以将其视为 Context Provider 主体。 Hook 有一个返回值,...
记录器-记录Godot引擎的单例 Logger类是GDScript单例,它为使用开发的项目提供了记录API。 用法 将logger.gd文件复制到您的项目文件夹中,并在项目设置中将其定义为自动加载的单例(例如,名称为Logger ): ...
class-autoloader.php :自动加载器+类映射器( 加载php类class-reg.php :注册(最主要的部分)-执行类初始化,分组并提供全局命名空间访问作为最终单例。 class-scripts-loader.php :脚本加载器-将所有资产...
9.1.2 将类加载器作为命名空间 9.1.3 编写你自己的类加载器 9.2 字节码校验 9.3 安全管理器与访问权限 9.3.1 Java 平台安全性 9.3.2 安全策略文件 9.3.3 定制权限 9.3.4 实现权限类 9.4 用户认证 9.4.1 JAAS 登录...
model.loader:包含资源加载器用于读取配置文件等信息,使用了单例设计模式 model.manager:包含元素管理器、工厂等,用于控制游戏各元素 model.vo:各种实体类,包括玩家、NPC、炸弹、方块等等 pro:配置文件目录,...
例如可以设计一个单例类, 负责所有数据表的映射 常见的五种单例模式实现方法: 主要: 饿汉式(线程安全, 调用效率高, 但是不能延时加载) 懒汉式(线程安全, 调用效率不高, 但是可以延时加载) 其他: 双重检测锁式(由于 ...
Java虚拟机(JVM):包括垃圾回收机制、内存管理、类加载机制等与JVM相关的知识。 设计模式:涉及常见的设计模式,如单例模式、工厂模式、观察者模式等。 Java框架和技术:包括Spring、Hibernate、My
Efesto.js 是一个 JavaScript 框架,它为您提供模式、实用程序、路由、dinamyc 加载器、带驱动程序的数据管理器、视图系统的使用... 这是为了使用 MVVM 架构测试数据流而进行的实验。 它提供: 设计模式实现,如...
model.loader:包含资源加载器用于读取配置文件等信息,使用了单例设计模式 model.manager:包含元素管理器、工厂等,用于控制游戏各元素 model.vo:各种实体类,包括玩家、NPC、炸弹、方块等等 pro:配置文件目录,...
- 获取类的构造器(Constructor) - 获取注解 - 通过反射调用方法 - 反射的应用场景 - Spring 的 IOC 容器 - 反射 + 抽象工厂模式 - JDBC 加载数据库驱动类 - 反射的优势及缺陷 - 增加程序的灵活性 - 破坏...
6.3.2 单例(Singleton)类 176 6.4 final修饰符 177 6.4.1 final变量 177 6.4.2 final方法 181 6.4.3 final类 182 6.4.4 不可变类 182 6.4.5 缓存实例的不可变类 186 6.5 抽象类 188 6.5.1 抽象方法和抽象...
BALoadingAnimationConfig 类方法更改单例,用作所有 BALoadingAnimations 的默认配置。 使用 BALoadingAnimationConfig 类方法来设置加载动画的样式。 或者... 如果您希望它与您自己的默认值不同,请创建您自己...
静态初始化程序是由类加载器执行的,是在允许任何代码访问该类之前加载类的一部分。 由于Spring必须实例化该类(这肯定需要加载该类),然后才能在该实例上调用setter,因此静态初始化程序块已经运行。
java8 集合源码分析 2020年深圳java打工仔找...java几个类加载器? 类加载方式? 动态代理和静态代理的区别? jdk哪个接口实现动态代理? 自定义注解? 怎么写? spring 的事务管理机制是什么形式的?怎么理解spring的事务管
类加载机制 双亲委派 OSGI 算法 搜索 二分 排序 选择 冒泡 插入 快速 归并 堆 桶 基数 常用算法 贪婪 回溯 剪枝 动态规划 数据挖掘算法 KMP算法 GZZ算法 HASH分桶 关联规则算法 APRORIVE...
而不是针对实现编程1.6.2 @protocol与抽象基类1.6.3 对象组合与类继承1.7 本书用到的对象和类1.7.1 类图1.7.2 对象图1.8 本书如何安排模式的讲解1.9 总结第2章 案例分析:设计一个应用程序2.1 想法的概念化2.2 界面...