`
talentluke
  • 浏览: 594922 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

Java 虚拟机是如何判定两个 Java 类是相同

 
阅读更多

Java 虚拟机不仅要看类的全名是否相同,还要看加载此类的类加载器是否一样。只有两者都相同的情况,才认为两个类是相同的。

 

对于 Java 虚拟机来说,如果两个类不同,试图对这两个类的对象进行相互赋值,会抛出运行时异常 ClassCastException

 

//文件Sample.java

package com.luke;

public class Sample
{
    private Sample instance;

    public void setSample(Object instance) {
        this.instance = (Sample) instance;
    }
   
    public void out(String msg)
    {
        System.out.println(msg);
    }

}

//文件Test.java

package com.luke;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;


class MyClassLoader extends ClassLoader
{
    public Class loadClassMy(String path, String name, boolean resolve) throws ClassNotFoundException
    {
        Class klass = null;
        try
        {
            klass = findLoadedClass(name); //检查该类是否已经被装载。
            if (klass != null)
            {
                System.out.println("该类已经加载了");
                return klass;  
            }
           
            byte[] bs = getClassBytes(path, name);//从一个特定的信息源寻找并读取该类的字节。
            if (bs != null && bs.length > 0)
            {
                klass = defineClass(name, bs, 0, bs.length);  
            }
            if (klass == null)
            { //如果读取字节失败,则试图从JDK的系统API中寻找该类。
                klass = findSystemClass(name);
            }
            if (resolve && klass != null)
            {
                resolveClass(klass);  
            }
        }
        catch (IOException e)
        {
            throw new ClassNotFoundException(e.toString());
        }  
        System.out.println("klass == " + klass);
        return klass;
    }  
    private byte[] getClassBytes(String path, String className) throws IOException
    {
        //String path = System.getProperty("java.class.path") + File.separator;
        path += className.replace('.', File.separatorChar) + ".class";
        System.out.println(path);
        FileInputStream fis = null;
        try
        {
            fis = new FileInputStream(path);
        }
        catch (FileNotFoundException e)
        {
            System.out.println(e);
            return null;   //如果查找失败,则放弃查找。捕捉这个异常主要是为了过滤JDK的系统API。
        }
        byte[] bs = new byte[fis.available()];
        fis.read(bs);
        return bs;
    }
}

public class Test
{

    /**
     * @description
     * @param
     * @return                void
     * @author                luke
     * @date                  2013-5-23
     * @version
     */

    public static void main(String[] args)
    {
        // TODO Auto-generated method stub
        
        //System.out.println(System.getProperty("java.class.path") + File.separatorChar);
        
        
            try
            {
                MyClassLoader loader = new MyClassLoader();
                MyClassLoader loader1 = new MyClassLoader();
                

//--------------测试1
                /**
                 * 1.sun.misc.Launcher$AppClassLoader@190d11################sun.misc.Launcher$AppClassLoader@190d11
                 *   sun.misc.Launcher$AppClassLoader@190d11****************sun.misc.Launcher$AppClassLoader@190d11
                 */
                Class c  = loader.loadClass("com.luke.Sample");   
                Class c1  = loader1.loadClass("com.luke.Sample");
               
                /*Class c = Sample.class;
                Class c1 = Class.forName("com.luke.Sample");*/
               
                System.out.println(c.getClassLoader() + "################" + c1.getClassLoader());
               
                /**

                *Test.class与Sample.class都在classpath路径下;
                 * 因为Test的加载器是系统加载器即sun.misc.Launcher$AppClassLoader@190d11,
                 * 根据加载器代理委托机制,c和c1的加载器也是sun.misc.Launcher$AppClassLoader@190d11,
                 * 类的全名又相同, 所以类相同, 可以强制转换,Test类也能看见Sample类.
                 */
                Sample o = (Sample)c.newInstance();
                Sample o1 = (Sample)c1.newInstance();
              
                System.out.println(o.getClass().getClassLoader() + "****************" + o1.getClass().getClassLoader());
                               
                o.out("hello world!");               
               
               
                Method setSampleMethod = c.getMethod("setSample", java.lang.Object.class);
                setSampleMethod.invoke(o, o1);
               
                Method m = c.getMethod("out", java.lang.String.class);
                m.invoke(o, "你好");
               
                //--------------测试1





//----------------------------测试2
                /**
                 * 2.com.luke.MyClassLoader@10b30a7################com.luke.MyClassLoader@10b30a7
                 *   com.luke.MyClassLoader@10b30a7****************com.luke.MyClassLoader@10b30a7
                 */
               
                Class c  = loader.loadClassMy("D:\\workspace\\SSHDemo\\Web\\WEB-INF\\classes\\", "com.luke.Sample", false);   
                Class c1  = loader.loadClassMy("D:\\workspace\\SSHDemo\\Web\\WEB-INF\\classes\\", "com.luke.Sample", false);                             
               
                System.out.println(c.getClassLoader() + "################" + c1.getClassLoader());
               
                /**

                 *Test.class在classpath路径下,但Sample.class在D:\workspace\SSHDemo\Web\WEB-INF\classes\com\luke\下;
                 * 因为Test的加载器是系统加载器即sun.misc.Launcher$AppClassLoader@190d11,
                 * 根据加载器代理委托机制,c和c1的加载器都是自定义加载器com.luke.MyClassLoader@10b30a7,
                 * 虽然类的全名相同,Test与右边的c与c1的加载器不同, c与c1的加载器的父加载器是系统加载器,父加载器加载的类不能看见子加载器加载的类, 下面的实例不可以转换, 会报异常ClassCastException.
                 */
                /*Sample o = (Sample)c.newInstance();
                Sample o1 = (Sample)c1.newInstance();               
                ((Sample)o).out("hello world!");*/
              
               
                Object o = c.newInstance();
                Object o1 = c1.newInstance();               
               
                System.out.println(o.getClass().getClassLoader() + "****************" + o1.getClass().getClassLoader());
               
                /**
                 * c和c1的加载器都是自定义加载器即com.luke.MyClassLoader@10b30a7,
                 * 类的全名又相同, 所以类相同, o与o1类型相同, 可以赋值.
                 */
                Method setSampleMethod = c.getMethod("setSample", java.lang.Object.class);
                setSampleMethod.invoke(o, o1);
               
                Method m = c.getMethod("out", java.lang.String.class);
                m.invoke(o, "你好");
               
              //----------------------------测试2

 

 


                //----------------------------测试3
                /**
                 * 2.com.luke.MyClassLoader@10b30a7################com.luke.MyClassLoader@1b67f74
                 *   com.luke.MyClassLoader@10b30a7****************com.luke.MyClassLoader@1b67f74
                 */
            /*    Class c  = loader.loadClassMy("D:\\workspace\\Demo\\bin\\", "com.luke.Sample", false);    
                Class c1  = loader1.loadClassMy("D:\\workspace\\SSHDemo\\Web\\WEB-INF\\classes\\", "com.luke.Sample", false);    */
            
                Class c  = loader.loadClassMy("D:\\workspace\\SSHDemo\\Web\\WEB-INF\\classes\\", "com.luke.Sample", false);    
                Class c1  = loader1.loadClassMy("D:\\workspace\\SSHDemo\\Web\\WEB-INF\\classes\\", "com.luke.Sample", false);                              
                
                System.out.println(c.getClassLoader() + "################" + c1.getClassLoader());
                
                /**
                 * 因为Test的加载器是系统加载器即sun.misc.Launcher$AppClassLoader@190d11,
                 * 根据加载器代理委托机制,c的加载器是com.luke.MyClassLoader@10b30a7,
                 * c1的加载器是com.luke.MyClassLoader@1b67f74,
                 * 虽然类的全名相同,  c与c1的加载器的父加载器是系统加载器,父加载器加载的类不能看见子加载器加载的类, 下面的实例不可以转换, 会报异常ClassCastException.
                 */
                /*Sample o = (Sample)c.newInstance();
                Sample o1 = (Sample)c1.newInstance();                
                ((Sample)o).out("hello world!");*/
               
                
                Object o = c.newInstance();
                Object o1 = c1.newInstance();                
                
                System.out.println(o.getClass().getClassLoader() + "****************" + o1.getClass().getClassLoader());
                
                /**
                 * c的加载器是com.luke.MyClassLoader@10b30a7,
                 * c1的加载器是com.luke.MyClassLoader@1b67f74,
                 * 虽然类的全名相同, 但是c和c1的加载器不同,所以类不相同, o与o1类型不同, 不可以赋值, 会报异常ClassCastException.
                 */
                /*Method setSampleMethod = c.getMethod("setSample", java.lang.Object.class);
                setSampleMethod.invoke(o, o1); */
                
                Method m = c.getMethod("out", java.lang.String.class);
                m.invoke(o, "你好");
                
              //----------------------------测试3
            }
            catch (ClassNotFoundException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            catch (InstantiationException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            catch (IllegalAccessException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            catch (SecurityException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            catch (IllegalArgumentException e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            catch (Exception e)
            {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
           
    }

}

分享到:
评论

相关推荐

    MiniJavaVM—个Java虚拟机的设计和实现

    MiniJavaVM—个Java虚拟机的设计和实现 在本篇文章中,我们将详细介绍 MiniJavaVM 的设计和实现,包括其总体架构、功能、运行环境和开发工具,以及具体的实现步骤。 第一章绪论 Java 虚拟机(Java Virtual ...

    Java虚拟机规范中文版

    这时候又在国内著名Java社区ItEye中结识了另外两名译者吴璞渊和冶秀刚,我们在随后的两个多月的时间里共同完成了其余章节的翻译和校对。  《Java虚拟机规范》并非某一款虚拟机实现的说明书,它是一份保证各个公司...

    深入Java虚拟机(原书第2版)

    本书是近年来国内出版的唯一一本与Java虚拟机相关的专著,也是唯一一本同时从核心理论和实际运用这两个角度去探讨Java虚拟机的著作,不仅理论分析得透彻,而且书中包含的典型案例和最佳实践也极具现实指导意义。

    javajvm虚拟机原理PPT课件.pptx

    每次启动一个Java程序,都会创建一个Java虚拟机实例,该实例将管理Java程序的生命周期。Java虚拟机实例的生命周期结束时,该程序也将退出。 Java虚拟机体系结构 Java虚拟机的体系结构主要由四个部分组成:子系统、...

    java虚拟机知识点整理

    自己看书整理的 java虚拟机精品知识点 java内存区域与内存溢出处理 虚拟机栈和本地方法栈区别 对象定位访问 垃圾收集器GC管理 虚拟机GC垃圾回收收集算法(内存回收方法论) 虚拟机GC垃圾回收收集器(内存回收具体实现...

    深入了解java虚拟机

    本书是近年来国内出版的唯一一本与Java虚拟机相关的专著,也是唯一一本同时从核心理论和实际运用这两个角度去探讨Java虚拟机的著作,不仅理论分析得透彻,而且书中包含的典型案例和最佳实践也极具现实指导意义

    JAVA虚拟机内存分配与回收机制[文].pdf

    JAVA虚拟机内存分配与回收机制 JAVA虚拟机的内存分配与回收机制是JAVA语言的核心机制之一。该机制将内存划分为两种:栈内存和堆内存。 栈内存是用于存放基本类型的变量和对象的引用变量。在函数中定义的变量和对象...

    android 2.3.4 java虚拟机

    下载安装R.E....最后要将两个文件的权限改成和其他文件一样,如图所示。 重启就可以使用了。 注意:R.E.管理器 需要最高权限 R.E.管理器 需要挂载为读写才能复制文件到系统文件夹,和更改文件权限。

    protege4.0带java虚拟机的(压缩文件02,一共两个)

    由于附件不能大于20M,所以分两个上传,都下载后解压即可

    Java支持库2.0#0版

    “Java虚拟机”和“Java本地接口”是本支持库中最重要的两个数据类型。由“Java虚拟机”负责真实Java虚拟机的生命周期管理,而“Java本地接口”则提供Java类库的访问接口。使用时,可直接通过“Java本地接口”的各类...

    Java语言规范和JVM虚拟机规范.zip

    Java语言规范和JVM虚拟机规范.zip,Oracle官方文档,包括Java语法的定义等内容。Java语言规范包含JDK678三个版本,JVM虚拟机规范包含78两个版本。

    java虚拟机中多线程总结

    在本篇内容中小编给大家分享的是关于java虚拟机中多线程的知识点总结内容,需要的朋友们参考学习下。

    Java支持库2.0#0版(静态版)

    “Java虚拟机”和“Java本地接口”是本支持库中最重要的两个数据类型。由“Java虚拟机”负责真实Java虚拟机的生命周期管理,而“Java本地接口”则提供Java类库的访问接口。使用时,可直接通过“Java本地接口”的各类...

    为Java虚拟机编译Scala(Michel Schinz)Compiling Scala for the Java Virtual Machine (Michel Schinz)

    着重于Scala的两个重要概念的编译:mixin继承和运行时类型。 编译技术是在Java虚拟机的上下文中提出的,但可以轻松地适应其他类似环境。

    安卓2.3 java虚拟机(全套及软件)

    使用步骤: 1.用R.E.管理器rootexplorer将下载的libjbedvm....最后要将两个文件的权限改成和其他文件一样,如图(设置权限)。 重启就可以使用了。 有的手机可能会需要虚拟按键。这里也提供给大家。 swkey306汉化版.apk

    Java复习题(附答案)

    Java复习题,附答案。选择题中红色选项为答案项。对于考试比较具有代表性。

    JAVA_API1.6文档(中文)

    java.rmi.registry 提供 RMI 注册表的一个类和两个接口。 java.rmi.server 提供支持服务器端 RMI 的类和接口。 java.security 为安全框架提供类和接口。 java.security.acl 此包中的类和接口已经被 java.security...

    马士兵JAVA笔记(全).docx

    JAVA使用Unicode编码,每个字符占两个字节,可以用十六进制编码形式表示。 整数型可以分为byte、short、int、long四种,分别占1、2、4、8个字节。浮点型可以分为float和double两种,分别占4、8个字节。需要注意的是...

Global site tag (gtag.js) - Google Analytics