Java的反射机制

 

 

    反射是Java中非常特别的机制,反射可以绕过泛型检查、破坏类的封装性,但使用反射的好处是巨大的:反射可以在程序运行时加载类并获取类中的所有信息,实现对程序的动态控制。

 

反射机制的核心 Class<T>类

 

获取class对象的3种方式:

Class cls = ClassName.class;        // 通过 类名 + .class
      cls = instance.getClass();    // 通过实例对象调用getClass()
      cls = Class.forName("java.lang.String")   // 通过类名的字符串形式获得

      

注意:

    内置了8+1个基本数据类型的字节码。

    同类型、同维数的数组共享一份字节码,父类是Object。数组的类型名:[L数组元素类型名。

 

常用方法:

static Class<?> forName(String className)   // 通过类名获取class对象
T newInstance()         // 使用默认的无参构造器创建一个新实例。 
String getName()        // 获取完整名称
String getSimpleName()
ClassLoader getClassLoader() // 获取加载此类的类加载器
  
Field getField(String name)         // 获得公共成员字段
Field getDeclaredField(String name) // 获得成员字段,可以是private的
Field[] getFields()                 // 获得所有员字段

// 根据参数列表获取public的构造方法
Constructor<T> getConstructor(Class<?>... parameterTypes)
Constructor<?>[] getDeclaredConstructors()  // 获取所有构造方法,包括private的

// 根据方法名和参数列表获取public方法
Method getMethod(String name, Class<?>... parameterTypes)   
Method[] getDeclaredMethods()       // 获取所有方法,包括private的

 

 

几个反射类

 

Field 代表了成员变量

Class getType() // 获取字段的类型

 

Method 代表方法

Class[] getParameterType()// 获取参数列表
Class getRuturnType()// 获取返回类型
Object invoke(Object o, Object...args)// 调用Method对象代表的方法,无论实际方法的返回类型是什么,invoke都作为Object类型返回

 

Constructor 代表了构造方法

Class[] getParameterType()// 获取参数列表

 

以上3个类都使用的且意义也相同的方法:

String getName()
int getModifiers()      // 获取修饰符,public修饰符 对应 整形的静态常量PUBLIC
boolean isAccessible()  // 判断是否可访问
void setAccessible(boolean flag)    // 设置访问限制

 

 

类加载器

    类加载器负责将class文件加载到JVM中,同时创建相应的Class对象。类加载器本身也是对象,也需要其他类加载器,除了BootStrap。

    JVM判断Java类是否相同,要看两点:1、类名是否相同;2、是否被同一个类加载器加载。只有类名相同并且被同一个类加载器加载才会被JVM认为是同一个类。

 

3个内置的类加载器:

        引导类加载器 BootStrap:根加载器,内嵌在虚拟机中,无需其他类加载器加载,加载范围:JRE/lib/rt.jar。

        扩展类加载器 ExtClassLoader:被BootStrap加载,加载范围:JRE/lib/ext/*.jar。

        系统类加载器 AppClassLoader:被ExtClassLoader加载,加载范围:ClassPath指定的目录或jar文件

        

类加载器的委托机制:

        某一加载器若有父加载器,则将加载任务委托给父加载器,直至将加载任务传递到根加载器;

        从根加载器开始,查找自己管辖范围的目录,若已存在需要加载的class文件则加载,否则将加载任务退回子加载器加载;

        若从根加载器到发起加载任务的加载器都找不到class文件,则报异常,发起者不会将加载任务委托给子加载器。

        

    JVM判断Java类是否相同,要看两点:1、类名是否相同;2、是否被同一个类加载器加载。只有类名相同和被同一个类加载器加载才会被JVM认为是同一个类。

        

    面试题:可不可以自己编写一个java.lang.System类?

        可以,但通常加载不到自己编写的System类,因为按类加载器的委托机制,加载任务传递至根加载器后,根加载器会发现系统默认的System类并加载。若想加载自己的System类可以编写自己的类加载器。

        

    自定义类加载器

        必须继承抽象类ClassLoader,覆盖findClass()

        

内省 IntroSpector

    内省是对类的内部事务进行处理的方式。为了高效地使用内省,对需要进行内省操作的类约定了一些规则,符合这些规则的类称为Bean类。Java提供了一套工具对Bean类进行操作,这套工具位于java.beans包中。

 

使用PropertyDescriptor类操作Bean类中的某个属性:

Person person = new Person();
String propertyName = "name";
Class classType = p.getClass();

PropertyDescriptor pd =                 // 获得属性描述器
    new PropertyDescriptor(propertyName, classType);

Method setProp = pd.getWriterMethod();  // 通过属性描述器获得对属性操作的方法
setProp.invoke(p, "Jack");              // 通过方法操作属性

Method getProp = pd.getReaderMethod();  // 通过属性描述器获得对属性操作的方法
Object retVal = getProp.invoke(p);      // 通过方法操作属性

 

 

通过BeanInfo类获得Bean类的多个属性:

BeanInfo bi =                           // 获取Bean类的信息(把Person类当做Bean类)
    IntroSpector.getBeanInfo(Person.class);
    
PropertyDescriptor[] pds =              // 同过BeanInfo类获取多个属性描述器
    bi.getPropertyDescriptors();
    
for (PropertyDescriptor pd : pds) {     // 遍历属性描述器
    // 操作属性
}

 

 

代理类 java.lang.reflect.Proxy

    代理是一种设计模式,它的原理是:创建一个与委托类有着相同接口的代理类,使用者并不直接访问委托类,而是通过访问代理类来实现对委托类的访问。我们通过改变代理类,可以在不修改委托类的情况为其添加不同功能。

    

Proxy类两个常用的静态方法:

Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)   // 获取代理类的字节码,需要提供类加载器和接口列表
Object newProxyInstance(
                ClassLoader loader, // 创建一个代理类的实例
                Class<?>[] interfaces, 
                InvocationHandler h)

 

InvocationHandler接口

    此接口定义了invoke()方法,通过覆盖此方法实现对委托类的功能增强。

Object invoke(Object proxy, Method method, Object[] args)  

 

一个小范例:

List list = new ArrayList();
List proxy = (List) Proxy.newProxyInstance(     // 创建List类的代理类实例
    List.getClass().getClassLoader(),
    List.getClass().getInerfaces(),
    new InvocationHandler() {                   // InvocationHandler的匿名内部类
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) {
            // 此处可编写增强功能的代码
            Object retVal = method.invoke(list, args);  // 调用委托类的方法
            // 此处可编写增强功能的代码
            return retVal;
        }
    });

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值