类加载器与单例

当使用不同的类加载器时,也会使单例失效,如下: 
单例为: 

?


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()却并没有打印出无参构造函数中的信息,这背后的原理希望你们能帮我解答。 
有关类加载器的内容,请见后续文章 

时间: 2024-08-07 02:20:20

类加载器与单例的相关文章

学会放下包袱,热爱单例

原文链接  译者:曾维朝 企业应用程序与移动应用程序有着截然不同的要求.你启动一次企业应用程序,它会连续运行数月或数年.另一方面,大部分手机应用可能是被正在无聊排队或者坐公交车的用户启动的,它们经常连续运行不超过几分钟,这就意味着移动应用程序必须即时开启,而启动一个企业应用程序则需要足够长的时间. 对于企业应用,依赖注入和早期验证是非常重要的, Spring为此提供了极大的便利. 但是别欺骗自己,Spring是好,但它不是万金油.尤其在崇尚快速启动.低内存消耗.避免接口的移动开发领域. 企业应用

java的单例、static修饰符及static的继承

单例设计模型: static修饰符: ①:static静态只有一份(同一个虚拟机中) (节省资源),类代码被装载内存时,静态代码分配内存,并执行,并且常驻内存. 可参考:类加载顺序 ②:Static修饰成员变量,成为"类变量",属于整个类,类的共享变量.注:不能修饰局部变量.          static是一块为整个类共有一块存储区域,静态变量只有一份,值变化后,所有访问值变化生效.          java中用类名调用static变量和方法(对象调用也可以):类名.变量(方法名)

Java单例进化史

关于单例,从我学Java到现在只知道以下两点: 1.为了让一个类只能有一个实例,所以使用单例的设计模式. 2.有两种实现方法:①饿汉式 ②懒汉式 ①饿汉式简单,是线程安全的.但是在类加载时就创建了一个实例,但是这个单例类可能永远不会被使用,这就造成了浪费.而且类被加载器加载时就会实例化一次.这就有可能被实例化多次. public class Singleton { private static final Singleton INSTANCE = new Singleton(); private

浅谈JAVASE单例设计模式_java

简单的说设计模式,其实就是对问题行之有效的解决方式.其实它是一种思想. 1.单例设计模式.       解决的问题:就是可以保证一个类在内存中的对象唯一性.(单个实例)       使用单例设计模式需求:必须对于多个程序使用同一个配置信息对象时,就需要保证该对象的唯一性.       如何保证对象唯一性?                                                      解决步骤:       1.不允许其他程序用new创建该对象.            

深入解析Java中的Class Loader类加载器_java

类加载的过程类加载器的主要工作就是把类文件加载到JVM中.如下图所示,其过程分为三步: 1.加载:定位要加载的类文件,并将其字节流装载到JVM中: 2.链接:给要加载的类分配最基本的内存结构保存其信息,比如属性,方法以及引用的类.在该阶段,该类还处于不可用状态: (1)验证:对加载的字节流进行验证,比如格式上的,安全方面的: (2)内存分配:为该类准备内存空间来表示其属性,方法以及引用的类: (3)解析:加载该类所引用的其它类,比如父类,实现的接口等. 3.初始化:对类变量进行赋值. 类加载器的

深入探讨Java类加载器

类加载器是 Java 语言的一个创新,也是 Java 语言流行的重要原因之一. 它使得 Java 类可以被动态加载到 Java 虚拟机中并执行.类加载器从 JDK 1.0 就出现了,最初是为了满足 Java Applet 的需要而开发出来的.Java Applet 需要从远程下载 Java 类文件到浏览器中并执行.现在类加载器在 Web 容器和 OSGi 中得到了广泛的使用.一般来说,Java 应用的开发人员不需要直接同类加 载器进行交互.Java 虚拟机默认的行为就已经足够满足大多数情况的需求

java-Java 单例线程安全问题

问题描述 Java 单例线程安全问题 public class A { public final static A INSTANCE = new A(); private A(){} }这个类是不是线程安全的呢?单例能这样写吗? 解决方案 这种写法是线程安全的.但是在该类一开始被加载的时候INSTANCE = new A()就会被执行.具体参考陈皓的博客深入浅出单实例Singleton设计模式介绍得非常详细. 解决方案二: 如果单线程中初始化,多线程中应用就没问题. 解决方案三: 深入解析单例线

【秒懂设计模式】单例设计模式

 秒懂设计模式--单例设计模式 (三)单例设计模式 1.先解释一下,什么是单例模式呢? 在Java中是这样定义的:"一个类有且仅有一个实例,并且自行实例化向整个系统提供." 显然从单例模式的定义中,我们可以发现它有三个要点: ①某个类只能有一个实例: ②它必须自行创建这个实例: ③它必须自行向整个系统提供这个实例. 2.要满足这三个要点,应该如何实现呢?下面让我们来逐条分析: ①如何保证某个类只能有一个实例? 让我先来想一下,一个类的对象是如何创建的呢?答案是:一个类的对象的产生是由类

【java设计模式】之 单例(Singleton)模式

1. 单例模式的定义         单例模式(Singleton Pattern)是一个比较简单的模式,其原始定义如下:Ensure a class has only one instance, and provide a global point of access to it. 即确保只有一个实例,而且自行实例化并向整个系统提供这个实例.单例模式的通用类如下图所示:         Singleton类称为单例类,通过使用private的构造函数确保了在一个应用中只产生一个实例,并且是自行