Java程序的工作机制:Java对象都以单独的class文件存在,java虚拟机将其载入并执行其虚拟机指令。
Java虚拟机查找这些java对象:
java虚拟机根据class path来查找java对象,而虚拟机的class path又分为三层:
bootstrap:sun.boot.class.path
extension: java.ext.dirs
application: java.class.path
三个class path各有对应的classloader。由上而下形成父子关系
当程序中调用new指令,或者ClassLoader.load方法时。其顺序如下:
1. 首先查看application的classloader中是否已有对应的class缓存,如果有则返回,并根据class分配内存。如果没有,接下一步。
2. 首先查看extension的classloader中是否已有对应的class缓存,如果有则返回,并根据class分配内存。如果没有,接下一步。
3. 首先查看bootstrap的classloader中是否已有对应的class缓存,如果有则返回,并根据class分配内存。如果没有,接下一步。
4. 由bootstrap的classloader在其class path中试图加载该class,如果有,则将该class放入cache中,并返回。如果没有,接下一步。
5. 由extension的classloader在其class path中试图加载该class,如果有,则将该class放入cache中,并返回。如果没有,接下一步。
6. 由application的classloader在其class path中试图加载该class,如果有,则将该class放入cache中,并返回。如果没有,则抛出ClassNotFound的exception。
Java虚拟机加载这些java对象:
每个java虚拟机都在其启动时产生一个唯一的class heap,并把所有的class instance都分配在其中。其中每个类实例的信息又分两部分,fields域和methods域。每个类实例各自拥有fields,但同一个类的不同实例共享methods
反射
JVM对反射的处理
简单例子代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.io.IOException;
public class Main {
public static void main(String[] args){
TempImpl t1 = new TempImpl("temp1");
try {
Method t1Talk = t1.getClass().getMethod("Talk", new Class[0]) ;
t1Talk.invoke(t1, null);
} catch (NoSuchMethodException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (IllegalAccessException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (InvocationTargetException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
复杂例子代码:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.io.IOException;
public class Main {
public static void main(String[] args){
TempImpl t1 = new TempImpl("temp1");
TempImpl t2 = new TempImpl("temp2");
Temp2 temp2 = new Temp2();
try {
Method t1Talk = t1.getClass().getMethod("Talk", new Class[0]) ;
Method t2Talk = t2.getClass().getMethod("Talk", new Class[0]) ;
t1Talk.invoke(t2, null);
t2Talk.invoke(t1, null);
if(t1Talk.equals(t2Talk)){
System.out.println("equals");
}
else{
System.out.println("not equals");
}
if(t1Talk==t2Talk){
System.out.println("ref equals");
}
else{
System.out.println("ref not equals");
}
t2Talk.invoke(temp2, null);
} catch (NoSuchMethodException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (IllegalAccessException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (InvocationTargetException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
try {
System.in.read();
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
分析:java虚拟机把每个methods当作一个执行单元。该执行单元带有两种签名:类签名和属性签名(public,static等)。 反射的第一步,验证签名的合法性。验证通过后,顺序执行该method中的指令,当需要访问类实例的fields和传入参数时,由虚拟机注入。
动态代理
Sun对动态代理的说明:
一个简单例子代码:
动态代理的内部实现——代码生成:
研究JDK源代码,发现在Proxy的sun实现中调用了sun.misc.ProxyGenerator类的generateProxyClass( proxyName, interfaces)方法,其返回值为byte[]和class文件的内存类型一致。于是做如下试验:
public class ProxyClassFile{
public static void main(String[] args){
String proxyName = "TempProxy";
TempImpl t = new TempImpl("proxy");
Class[] interfaces =t.getClass().getInterfaces();
byte[] proxyClassFile = ProxyGenerator.generateProxyClass(
proxyName, interfaces);
File f = new File("classes/TempProxy.class");
try {
FileOutputStream fos = new FileOutputStream(f);
fos.write(proxyClassFile);
fos.flush();
fos.close();
} catch (FileNotFoundException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
} catch (IOException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
}
}
运行该类,到class文件夹下,利用反编译技术,发现原来其采用了代码生产技术:
public interface Temp{
public void Talk();
public void Run();
}
import java.lang.reflect.*;
public final class TempProxy extends Proxy
implements Temp{
private static Method m4;
private static Method m2;
private static Method m0;
private static Method m3;
private static Method m1;
public TempProxy(InvocationHandler invocationhandler) {
super(invocationhandler);
}
public final void Run() {
try {
h.invoke(this, m4, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString(){
try{
return (String)h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
return "";
}
public final int hashCode() {
try {
return ((Integer)h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable){
throw new UndeclaredThrowableException(throwable);
}
return 123;
}
public final void Talk(){
try{
h.invoke(this, m3, null);
return;
}
catch(Error _ex) { }
catch(Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final boolean equals(Object obj) {
try {
return ((Boolean)h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
return false;
}
static{
try{
m4 = Class.forName("Temp").getMethod("Run", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m3 = Class.forName("Temp").getMethod("Talk", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] {
Class.forName("java.lang.Object")
});
}
catch(NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
技术交流群:30704235
欢迎大家共同交流
分享到:
相关推荐
然而,由于Java的动态特性,如动态代理、动态字节码生成等,JIT编译器仍然是必要的,因为它能更好地适应运行时的变化。 综上所述,对于准备2024年Java面试的工程师来说,全面理解Java基础、JVM的工作原理、JDK和JRE...
本电子书合集是针对计算机专业基础理论中的编程语言部分,特别是聚焦于Java语言的深入学习,涵盖了多个方面的知识,包括JVM原理、反射机制、多线程等内容。以下是这些书籍涉及的一些关键知识点: 1. **Java编程语言...
- **代码质量**:编写高效、简洁的代码是基础,避免过度使用反射、动态代理等高级特性,因为它们可能带来额外的性能开销。 - **数据结构和算法**:选择合适的数据结构和算法可以极大提升程序效率,例如,使用...
通过这些源代码,开发者可以学习到Java内存管理、线程调度、网络编程、I/O操作、安全管理、类加载机制、反射机制等多个关键领域的实现细节。同时,了解JVM的内部工作原理,有助于优化代码性能,解决复杂问题,以及...
### Java发展史与Java 9、10新特性详解 #### Java发展史 Java自1995年由Sun Microsystems发布以来,历经多个版本的发展和完善,成为当今最受欢迎的编程语言之一。下面简要回顾Java的发展历程及其重要里程碑: - *...
1. 高性能:相对于其他动态代理库(如Java的反射API或JDK动态代理),CGLIB的代理效率更高。 2. 易于使用:Spring框架已经封装了CGLIB的使用,开发者通常不需要直接与CGLIB库交互。 `spring-objenesis-repack-2.5.1...
在这一阶段,可以通过反射机制获取类的`Class`对象,访问其成员变量和方法。 #### 六、卸载阶段(Unloading) 类的卸载通常发生在应用程序退出或系统资源紧张时。JVM通过垃圾回收机制自动释放不再使用的类资源。类...
它包含了Java代理服务器和通信机制,使得开发者可以远程控制和监控应用的运行状态。 2. **java.prefs**: Java首选项API(Preferences API)位于这个模块中,提供了一种跨平台的方式来存储用户和系统偏好设置。它...
10. **jdk.dynalink**:动态链接库,提供了一种方式来在运行时动态绑定方法调用,通常用于实现动态语言的功能或者高效的反射机制。 通过研究这些源码,开发者可以提升对Java平台的理解,学习如何优化代码,解决性能...
这两种 VM 都支持字节码级别的 Hook,例如,我们可以使用 Art 或 Dalvik 的代理类机制(Proxy Classes)或者利用 JVMTI(Java Virtual Machine Tool Interface)进行 Hook。在 Art 中,我们可以使用 MethodHandle 和...
VMTranslator可能使用了一些关键的Java技术,例如反射(Reflection)、动态代理(Dynamic Proxy)、注解处理器(Annotation Processor)等。反射允许程序在运行时检查和修改自身的结构和行为,动态代理可以创建接口...
动态代理允许在运行时创建代理类和接口的实例,提供了一种灵活的方式来实现回调或者事件监听等功能。 ### 7. 反射(Reflection) 反射API在JDK 1.6中也得到了加强,可以更方便地在运行时检查类、接口、字段和方法...
3. 动态代理用于在运行时创建一个实现一组给定接口的新类,常用于AOP(面向切面编程)或回调处理。 4. 动态代理可通过实现InvocationHandler接口和使用Proxy类来实现。 五、对象拷贝 1. 克隆用于复制对象,创建一个...
6. **反射**:理解反射机制,可以动态地获取类的信息并操控对象,广泛应用于插件化、序列化、动态代理等场景。 7. **异常处理**:理解异常的分类、捕获和抛出机制,以及Checked异常和Unchecked异常的区别,有助于...