文档章节

Java反射总结

ZooKeeper
 ZooKeeper
发布于 2013/11/27 07:21
字数 1431
阅读 1166
收藏 29

Java 反射总结

类装载器工作机制 

类装载器就是寻找类的节码文件并构造出类在JVM 内部表示对象的组件。在Java 中, 
类装载器把一个类装入JVM 中,要经过以下步骤: 
1.装载:查找和导入Class 文件; 
通过一个类的全限定名来获取定义此类的二进制字节流.然后将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构.最后在Java堆中生成一个代表这个类的java.lang.class对像,作为方法区的数据入口. 

2.链接:执行校验、准备和解析步骤,其中解析步骤是可以选择的: 
a)校验:检查载入Class 文件数据的正确性; 
b)准备:给类的静态变量分配存储空间; 
c)解析:将符号引用转成直接引用; 

3.初始化:对类的静态变量、静态代码块执行初始化工作。 

类装载工作由ClassLoader 及其子类负责,ClassLoader 是一个重要的Java 运行时系统组件,它负责在运行时查找和装入Class 字节码文件。JVM 在运行时会产生三个 
ClassLoader: 
BootstrapClassLoader 
Extension ClassLoader(扩展类装载器) 
Application ClassLoader(系统类装载器)。 

其中,BootstrapClassLoader不是ClassLoader 的子类,它使用C++编写,因此我们在Java 中看不到它,BootstrapClassLoader负责装载JRE 的核心类库,如JRE 目标下的rt.jar、charsets.jar 等。 

Extension ClassLoader 和Application ClassLoader 都是ClassLoader 的子类。其中Extension ClassLoader 负责装载 JRE 扩展目录ext 中的JAR 类包;Application 负责装载Classpath 路径下的类包。 

getParent()
返回该类加载器的父类加载器。
loadClass(String name)
加载名称为 name 的类,返回的结果是 java.lang.Class 类的实例。
findClass(String name) 
查找名称为 name 的类,返回的结果是 java.lang.Class 类的实例。
findLoadedClass(String name) 
查找名称为 name 的已经被加载过的类,返回的结果是 java.lang.Class 类的实例。
defineClass(String name, byte[] b, int off, int len)
把字节数组 b 中的内容转换成 Java 类,返回的结果是 java.lang.Class 类的实例。这个方法被声明为 final 的。
resolveClass(Class<?> c)
链接指定的 Java 类。


public class ClassLoaderTest {  
public static void main(String[] args) {  
ClassLoader loader = Thread.currentThread().getContextClassLoader();  
System.out.println("current loader:"+loader);  
System.out.println("parent loader:"+loader.getParent());  
System.out.println("grandparent loader:"+loader.getParent(). getParent());  
}  
}



current loader:sun.misc.Launcher$AppClassLoader@131f71a  
parent loader:sun.misc.Launcher$ExtClassLoader@15601ea  
//①根装载器在Java中访问不到,所以返回null  
grandparent loader:null



通过以上的输出信息,我们知道当前的ClassLoader 是AppClassLoader,父ClassLoader是ExtClassLoader,祖父ClassLoader 是根类装载器,因为在Java 中无法获得它的句柄,所以仅返回null。 


JVM 装载类时使用“全盘负责委托机制”,“全盘负责”是指当一个ClassLoader 装载一个类的时,除非显式地使用另一个ClassLoader,该类所依赖及引用的类也由这个ClassLoader 载入;“委托机制”是指先委托父装载器寻找目标类,只有在找不到的情况下才从自己的类路径中查找并装载目标类。这一点是从安全角度考虑的,试想如果有人编写了一个恶意的基础(如java.lang.String)并装载到JVM 中将会引起多么可怕的后果。但是由于有了“全盘负责委托机制”,java.lang.String 永远是由根装载器来装载的,这样就避免了上述事件的发生。

获取当前线程的ClassLoader:

ClassLoader loader = Thread.currentThread().getContextClassLoader(); 
Class.getClassLoader() ;
实例化Class类对象的三种方式:
Class.forName("Reflect.Demo"); 
new Demo().getClass(); 
Demo.class;
Class.forName(className)实际上是调用Class.forName(className, true, this.getClass().getClassLoader())。注意第二个参数,是指Class被loading后是不是必须被初始化。

通过Class实例化其他类的对象
Class<?>  demo=Class.forName("Reflect.Person"); 
Constructor<?> cons[]=demo.getConstructors(); 
Object object = cons[0].newInstance(args);
通过Class实例化接口 
Class<?> intes[]=demo.getInterfaces();
取得其他类中的父类
Class<?> superClass=demo.getSuperclass();

调用其他类中的方法
demo = Class.forName("Reflect.Demo"); 
Method method=demo.getMethod("toString"); 
method.invoke(demo.newInstance()); 


Method[] methods = demo.getDeclaredMethods();
通过反射操作属性: 
Field field = demo.getDeclaredField("sex"); 
field.setAccessible(true); 
field.set(obj, "男"); 


Field[] fields = Demo.class.getDeclaredFields(); //类中任何可见性的属性不包括基类 
fields = Demo.class.getFields();  //只能获得public属性包括基类的
使用数组

Class string = Class.forName("java.lang.String");  
Object object= Array.newInstance(string, 10);  
Array.set(object, 5, "this is a test");  
 String s = (String) Array.get(arr, 5);

=============================应用==========================
JDK动态代理:
与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler 接口提供了生成动态代理类的能力。


public class MyHandler implements InvocationHandler {   
    private Object target;   
       
    public Object bind(Object target) {   
        this.target = target;    
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),   
                target.getClass().getInterfaces(), this);   
    }    
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {   
        System.out.println("事物开始");    
        Object result = method.invoke(target, args);   
        System.out.println("事物结束");   
        return result;   
    }     
   
}
Cglib动态代理 
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 

public class MyCglib implements MethodInterceptor {   
    private Object target;   
    
    public Object getInstance(Object target) {   
        this.target = target;   
        Enhancer enhancer = new Enhancer();   
        enhancer.setSuperclass(this.target.getClass());   
        // 回调方法   
        enhancer.setCallback(this);   
        // 创建代理对象   
        return enhancer.create();   
    }   
    @Override   
    // 回调方法   
    public Object intercept(Object obj, Method method, Object[] args,   
            MethodProxy proxy) throws Throwable {   
        System.out.println("事物开始");   
        proxy.invokeSuper(obj, args);   
        System.out.println("事物结束");   
        return null;   
    }   
}




© 著作权归作者所有

共有 人打赏支持
ZooKeeper
粉丝 54
博文 28
码字总数 13920
作品 0
杭州
程序员
私信 提问
加载中

评论(2)

ZooKeeper
ZooKeeper

引用来自“Cwind001”的评论

博主总结得不错,请问通过反射调用类的方法与直接调用在性能上是否有较大的差异呢

因为需要动态编译,所以会消耗较多的资源.所以使用时也要注意,
最好运行一次,可以多次使用. 比如Spring,Hibernate也大量使用了反射.
为了提高开发和维护上的效率,牺牲一点点是可以接受的.
Cwind001
Cwind001
博主总结得不错,请问通过反射调用类的方法与直接调用在性能上是否有较大的差异呢
最最最常见的Java面试题总结——第二周

String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的? String和StringBuffer、StringBuilder的区别 可变性   String类中使用字符数组:保存字符串,所以String对象是...

Amsour丶
08/13
0
0
Java中的反射|SquirrelNote

前言 本篇简介: 反射概述 反射具体功能实现 Android中的反射应用 一、反射(Reflection)概述 1.定义 是指在运行状态中,对于任意一个类,都能知道这个类的所有属性和方法;并且对于任何一个...

跳动的松鼠
2017/11/28
0
0
云妹总结了一些最最最常见的Java面试题供大家参考

云妹导读:String和StringBuffer、StringBuilder的区别是什么?String为什么是不可变的? String和StringBuffer、StringBuilder的区别 可变性 String类中使用字符数组:private final cha...

阿里云科技快讯
08/17
0
0
老司机带你深入浅出Java反射

反射,它就像是一种魔法,引入运行时自省能力,赋予了 Java 语言令人意外的活力,通过运行时操作元数据或对象,Java 可以灵活地操作运行时才能确定的信息 这里笔者就深入浅出总结下Java反射,...

小刀爱编程
11/07
0
0
Java基础之反射(非常重要)

反射是框架设计的灵魂 (使用的前提条件:必须先得到代表的字节码的Class,Class类用于表示.class文件(字节码)) 一、反射的概述 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道...

Java-老刘
05/15
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Java 动态代理的实现

在Java中可以实现动态代理的方式有很多种:JDK方式、ASM字节码操控框架、开源的分析、编辑和创建Java字节码的类库Javassist、基于ASM框架实现的CGLIB JDK方式:通过Java反射的方式生成动态代...

我爱春天的毛毛雨
5分钟前
1
0
css 总结2

1、背景有关 (1)background-origin:border-box、padding-box、content-box //默认是padding-box(2)background-image: url(img_flwr.gif), url(paper.gif);(3)background-posi......

tianyawhl
6分钟前
1
0
java 每秒钟只允许十个线程同时并发

package com.qimh.thread.concurrent;import java.util.Date;import java.util.concurrent.ExecutorService;import java.util.concurrent.Executors;import java.util.concurren......

qimh
21分钟前
3
0
学习Hadoop大数据基础框架

什么是大数据?进入本世纪以来,尤其是2010年之后,随着互联网特别是移动互联网的发展,数据的增长呈爆炸趋势,已经很难估计全世界的电子设备中存储的数据到底有多少,描述数据系统的数据量的...

本宫没空2
23分钟前
2
0
redis

1,安装 sudo apt-get install redis-server 2,登录本地的 redis-cli 3,修改 .bashrc文件,连接其他线下数据库 vi .bashrc在最后增加alias redisa="redis-cli -h 10.15.100.134 -p 666...

鹏灬
28分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部