`
talentluke
  • 浏览: 604462 次
  • 性别: 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();
            }
           
    }

}

分享到:
评论

相关推荐

    深入java虚拟机.pdf

    Java 虚拟机的体系结构由多个子系统组成,包括类加载器子系统、执行引擎、数据区等。类加载器子系统负责加载程序中的类型(类和接口),并赋予唯一的名字。执行引擎负责执行被加载类中包含的指令。数据区中保存了...

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

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

    java虚拟机的两本书

    《深入Java虚拟机》通常包含了JVM的详细剖析,涵盖了诸如类加载机制、字节码执行、内存管理、垃圾收集、性能优化等多个关键领域。书中可能详细解释了JVM如何将字节码转换为机器码,以及如何进行动态编译以提升运行...

    java虚拟机

    在Java虚拟机第二版中,我们可以深入探讨以下几个关键知识点: 1. **字节码与类加载机制**:Java程序编译后生成的是.class文件,里面包含的是字节码。JVM通过类加载器将这些字节码加载到内存中,进行验证、准备、...

    java虚拟机的详细原理

    1. **启动**:当一个包含`public static void main(String[] args)`方法的类被加载时,Java虚拟机就会启动。`main()`方法是程序的入口点,Java虚拟机通过调用这个方法来开始执行程序。 - **主方法**:`main()`...

    Java虚拟机规范(英文)

    《Java虚拟机规范》是Java技术核心文档之一,它详细定义了Java虚拟机(JVM)的内部工作原理和执行模型。在给出的文件信息中,包含了这部规范的标题、描述和部分内容摘要。下面将详细解释其中的知识点。 标题《Java...

    Java平台 Java虚拟机 Java 应用编程接口

    Java的成功在于其能够编写一次,到处运行(Write Once, Run Anywhere)的特性,这得益于Java虚拟机(JVM)。Java虚拟机允许Java程序在任何安装了Java平台的系统上运行,而无需针对特定操作系统进行重新编译。 Java...

    Java虚拟机规范SE8英文

    - **布尔型**:只有true和false两个值。 - **引用类型**:包括对象和数组类型,通过引用指向堆中的对象实例或数组元素。 #### 三、运行时数据区 - **程序计数器(PC寄存器)**:每线程一个,存储当前线程所执行的...

    Java运行原理与Java虚拟机.pdf

    Java程序的执行涉及到两个主要步骤:首先是编译阶段,其次是解释执行阶段。 1. **编译阶段**:Java源代码(.java)文件首先通过Java编译器(javac)被编译成字节码文件(.class),这些字节码是一种中间代码,并非直接可...

    java 虚拟机的研究

    - **复制算法**:将内存空间分成两个相等的部分,每次只使用其中一个部分,将存活的对象复制到另一个空闲的部分。 - **分代收集**:基于对象的生存时间将内存划分为不同的区域(年轻代、老年代),不同区域使用不同...

    Android的JAVA虚拟机和JAVA环境

    这两个都是针对移动设备优化的Java虚拟机,确保应用程序能够在有限的硬件资源上高效运行。 **Java虚拟机(JVM)** Java虚拟机是Java程序执行的平台,它提供了“一次编写,到处运行”的特性。在桌面系统中,我们...

    Java语言规范+Java虚拟机规范(Java8、Java9)

    这两部分规范分别定义了Java编程语言的语法、语义以及Java虚拟机(JVM)的行为,为开发者提供了准确的指导,确保代码的正确性和高效性。本篇文章将详细探讨Java语言规范与Java虚拟机规范在Java 8和Java 9版本中的...

    深入JAVA虚拟机 不那么完美的第二版.pdf.zip

    《深入JAVA虚拟机 不那么完美的第二版》这本书虽然在印刷上可能存在一些小瑕疵,但这并不影响我们从中汲取宝贵的Java虚拟机(JVM)知识。Java虚拟机是Java平台的核心组成部分,它负责执行Java程序,提供了跨平台的...

    实战java虚拟机

    《实战Java虚拟机》这本书是Java开发者深入理解JVM(Java Virtual Machine)的重要参考资料。Java虚拟机是Java语言的核心组成部分,它负责解析和执行Java代码,实现跨平台的“一次编写,到处运行”。通过深入学习JVM...

    java虚拟机(jvm)介绍以及相关参数设置与调优

    Java虚拟机由三个主要组件组成:类加载器、运行时数据区和执行引擎。类加载器负责加载Java类文件并将其转换为Java虚拟机可以理解的格式;运行时数据区提供了一块内存空间,用于存储Java对象和类的实例变量;执行引擎...

    Java虚拟机的深入研究

    Java技术由四个主要部分构成:Java编程语言、Java类文件格式、Java虚拟机和Java应用程序接口(Java API)。开发者用Java语言编写源代码(.java文件),经过编译生成字节码(.class文件)。字节码在运行时被加载到JVM...

    安卓2.2和2.3等可用的java虚拟机及使用方法

    在安卓2.2和2.3这两个版本的操作系统上,Java虚拟机(Java Virtual Machine,简称JVM)扮演着至关重要的角色,它是Android系统运行基于Java语言的应用程序的基础。Java虚拟机允许Android设备运行编译后的Dalvik ...

    Java虚拟机并发编程.pdf

    为了完成您的请求,我需要更多的文档内容,以便从中提取出关于Java虚拟机并发编程的具体知识点。 不过,我可以根据标题和描述给出的知识点范围,描述出Java虚拟机(JVM)和并发编程相关的知识点,以满足您提出的...

Global site tag (gtag.js) - Google Analytics