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 虚拟机的体系结构由多个子系统组成,包括类加载器子系统、执行引擎、数据区等。类加载器子系统负责加载程序中的类型(类和接口),并赋予唯一的名字。执行引擎负责执行被加载类中包含的指令。数据区中保存了...
MiniJavaVM—个Java虚拟机的设计和实现 在本篇文章中,我们将详细介绍 MiniJavaVM 的设计和实现,包括其总体架构、功能、运行环境和开发工具,以及具体的实现步骤。 第一章绪论 Java 虚拟机(Java Virtual ...
《深入Java虚拟机》通常包含了JVM的详细剖析,涵盖了诸如类加载机制、字节码执行、内存管理、垃圾收集、性能优化等多个关键领域。书中可能详细解释了JVM如何将字节码转换为机器码,以及如何进行动态编译以提升运行...
在Java虚拟机第二版中,我们可以深入探讨以下几个关键知识点: 1. **字节码与类加载机制**:Java程序编译后生成的是.class文件,里面包含的是字节码。JVM通过类加载器将这些字节码加载到内存中,进行验证、准备、...
1. **启动**:当一个包含`public static void main(String[] args)`方法的类被加载时,Java虚拟机就会启动。`main()`方法是程序的入口点,Java虚拟机通过调用这个方法来开始执行程序。 - **主方法**:`main()`...
《Java虚拟机规范》是Java技术核心文档之一,它详细定义了Java虚拟机(JVM)的内部工作原理和执行模型。在给出的文件信息中,包含了这部规范的标题、描述和部分内容摘要。下面将详细解释其中的知识点。 标题《Java...
Java的成功在于其能够编写一次,到处运行(Write Once, Run Anywhere)的特性,这得益于Java虚拟机(JVM)。Java虚拟机允许Java程序在任何安装了Java平台的系统上运行,而无需针对特定操作系统进行重新编译。 Java...
- **布尔型**:只有true和false两个值。 - **引用类型**:包括对象和数组类型,通过引用指向堆中的对象实例或数组元素。 #### 三、运行时数据区 - **程序计数器(PC寄存器)**:每线程一个,存储当前线程所执行的...
Java程序的执行涉及到两个主要步骤:首先是编译阶段,其次是解释执行阶段。 1. **编译阶段**:Java源代码(.java)文件首先通过Java编译器(javac)被编译成字节码文件(.class),这些字节码是一种中间代码,并非直接可...
- **复制算法**:将内存空间分成两个相等的部分,每次只使用其中一个部分,将存活的对象复制到另一个空闲的部分。 - **分代收集**:基于对象的生存时间将内存划分为不同的区域(年轻代、老年代),不同区域使用不同...
这两个都是针对移动设备优化的Java虚拟机,确保应用程序能够在有限的硬件资源上高效运行。 **Java虚拟机(JVM)** Java虚拟机是Java程序执行的平台,它提供了“一次编写,到处运行”的特性。在桌面系统中,我们...
这两部分规范分别定义了Java编程语言的语法、语义以及Java虚拟机(JVM)的行为,为开发者提供了准确的指导,确保代码的正确性和高效性。本篇文章将详细探讨Java语言规范与Java虚拟机规范在Java 8和Java 9版本中的...
《深入JAVA虚拟机 不那么完美的第二版》这本书虽然在印刷上可能存在一些小瑕疵,但这并不影响我们从中汲取宝贵的Java虚拟机(JVM)知识。Java虚拟机是Java平台的核心组成部分,它负责执行Java程序,提供了跨平台的...
《实战Java虚拟机》这本书是Java开发者深入理解JVM(Java Virtual Machine)的重要参考资料。Java虚拟机是Java语言的核心组成部分,它负责解析和执行Java代码,实现跨平台的“一次编写,到处运行”。通过深入学习JVM...
Java虚拟机由三个主要组件组成:类加载器、运行时数据区和执行引擎。类加载器负责加载Java类文件并将其转换为Java虚拟机可以理解的格式;运行时数据区提供了一块内存空间,用于存储Java对象和类的实例变量;执行引擎...
Java技术由四个主要部分构成:Java编程语言、Java类文件格式、Java虚拟机和Java应用程序接口(Java API)。开发者用Java语言编写源代码(.java文件),经过编译生成字节码(.class文件)。字节码在运行时被加载到JVM...
在安卓2.2和2.3这两个版本的操作系统上,Java虚拟机(Java Virtual Machine,简称JVM)扮演着至关重要的角色,它是Android系统运行基于Java语言的应用程序的基础。Java虚拟机允许Android设备运行编译后的Dalvik ...
为了完成您的请求,我需要更多的文档内容,以便从中提取出关于Java虚拟机并发编程的具体知识点。 不过,我可以根据标题和描述给出的知识点范围,描述出Java虚拟机(JVM)和并发编程相关的知识点,以满足您提出的...