Java资料整理JDK8Java学习笔记

JAVA反射机制

2017-04-30  本文已影响128人  卡路fly

反射机制:

允许程序在运行时取得任何一个已知名称的class的内部信息,容许程序在运行时加载、探知、使用编译期间未知的class。加载一个运行时才得知名称的Class,获得其完整结构。

  1. 获取到Java中要反射类的字节码
    获取字节码方式:(实例化Class类对象的方法)
  1. 将字节码中的方法,变量,构造函数等映射成相应的<code> Method</code>、<code> Filed</code> 、<code> Constructor</code> 等类,这些类提供了丰富的方法可以被我们所使用。

Object类是Java反射机制的源头,即可以通过对象反射求出类的名称。
Class类使java允许通过一个对象来找到其所在类的信息。


反射借助的类


反射的功能


反射机制的深入——取得类的结构

通过反射得到一个类的完整结构,需要使用<code>java.lang.reflect</code>中的几个类
  1. 通过反射调用类的方法
public Method getMethod(String name,Class<?> ... parameterTypes) 
                            throws NoSuchMehtodException,SercurityException
public Object invoke(Object obj,Object...args) 
                     throws IllegalAccessException,
                           IllegalArgumentException,
                           InvocationTargetException
无参 有参
  1. 通过反射调用类setter及getter
    setter及getter方法是一个标准的属性访问方法,如果一个类的属性被封装,必须通过setter及getter设置取得,此方法的操作之所以这样规定,主要由于反射机制可以给予支持。
package org.lxh.demo15.invokedemo ;
import java.lang.reflect.Method ;
public class InvokeSetGetDemo{
    public static void main(String args[]){
        Class<?> c1 = null ;
        Object obj = null ;
        try{
            c1 = Class.forName("org.lxh.demo15.Person") ;   // 实例化Class对象
        }catch(Exception e){}
        try{
            obj = c1.newInstance() ;
        }catch(Exception e){}
        setter(obj,"name","Emma",String.class) ;    // 调用setter方法
        setter(obj,"age",21,int.class) ;    // 调用setter方法
        System.out.print("姓名:") ;
        getter(obj,"name") ;
        System.out.print("年龄:") ;
        getter(obj,"age");
    }
    /**
        Object obj:要操作的对象
        String att:要操作的属性
        Object value:要设置的属性内容
        Class<?> type:要设置的属性类型
    */
    public static void setter(Object obj,String att,Object value,Class<?> type){
        try{
            Method met = obj.getClass().getMethod("set"+initStr(att),type) ;    // 得到setter方法
            met.invoke(obj,value) ; // 设置setter的内容
        }catch(Exception e){
            e.printStackTrace() ;
        }
    }
    public static void getter(Object obj,String att){
        try{
            Method met = obj.getClass().getMethod("get"+initStr(att)) ; // 得到setter方法
            System.out.println(met.invoke(obj)) ;   // 调用getter取得内容
        }catch(Exception e){
            e.printStackTrace() ;
        }
    }
    public static String initStr(String old){   // 将单词的首字母大写
        String str = old.substring(0,1).toUpperCase() + old.substring(1) ;
        return str ;
    }
}
  1. 通过反射调用属性
    得到公共属性:
public Field getField(String name) 
                    throws NoSuchFieldException,SecurityException

得到本类属性

public Field getDeclaredField(String name) 
                    throws NoSuchFieldException,SecurityException

取得属性内容

public Object get(Object obj) 
                    throws IllegalArgumentException,IllegalAccessException

设置属性内容

public Object set(Object obj,Object value) 
                    throws IllegalArgumentException,IllegalAccessException

访问私有属性必须让这个属性可见(设置为true)

public void setAccessible(boolean flag) 
                    throws SecurityException
  1. 通过反射操作数组
    Class类中存在以下一个方法
public Class<?> getComponentType() 

得到数组下标内容:get(Objcet array,int index);
修改内容:set(Objcet array,int index,Object value);
开辟新数组:newInstance(Class<?> componentType,int ... dimensions)

取得数组信息并修改内容:
修改的过程就是一个创建的过程,创建一个新的,然后把原有内容拷贝到新数组中。

package org.lxh.demo15.invokedemo ;
import java.lang.reflect.Array ;
public class ChangeArrayDemo{
    public static void main(String args[]) throws Exception{
        int temp[] = {1,2,3} ;// 声明一整型数组
        int newTemp[] = (int []) arrayInc(temp,5) ; // 重新开辟空间5
        print(newTemp) ;
        System.out.println("\n-------------------------") ;
        String t[] = {"lxh","mldn","mldnjava"} ;
        String nt[] = (String [])arrayInc(t,8) ;
        print(nt) ;
    }
    public static Object arrayInc(Object obj,int len){
        Class<?> c = obj.getClass() ;
        Class<?> arr = c.getComponentType() ;   // 得到数组的
        Object newO = Array.newInstance(arr,len) ;  // 开辟新的大小
        int co = Array.getLength(obj) ;
        System.arraycopy(obj,0,newO,0,co) ; // 拷贝内容
        return newO ;
    }
    public static void print(Object obj){   // 数组输出
        Class<?> c = obj.getClass() ;
        if(!c.isArray()){   // 判断是否是数组
            return;
        }
        Class<?> arr = c.getComponentType() ;
        System.out.println(arr.getName()+"数组的长度是:" + Array.getLength(obj)) ;     // 输出数组信息
        for(int i=0;i<Array.getLength(obj);i++){
            System.out.print(Array.get(obj,i) + "、") ;  // 通过Array输出
        }
    }
}

反射机制的应用

通过Modifier.toString()还原修饰符

        Class<?> c1 = null ;        // 声明Class对象
        try{
            c1 = Class.forName("org.lxh.demo15.Person") ;   // 实例化对象
        }catch(ClassNotFoundException e){
            e.printStackTrace() ;
        }
        Constructor<?> con[] = c1.getConstructors() ;   // 取得一个类中的全部构造
        for(int i=0;i<con.length;i++){
            Class<?> p[] = con[i].getParameterTypes() ;     // 得到构造方法中的全部参数
            System.out.print("构造方法:" ) ;     // 输出构造,直接打印
            int mo = con[i].getModifiers() ; // 得到所要的访问权限
            System.out.print(Modifier.toString(mo) + " ") ; // 得到修饰符
            System.out.print(con[i].getName()) ;    // 取得构造方法的名字
            System.out.print("(") ;
            for(int j=0;j<p.length;j++){
                System.out.print(p[j].getName() + " arg" + i) ;
                if(j<p.length-1){
                    // 判断此是否是最后一个参数
                    System.out.print(",");  // 输出“,”
                }
            }
            System.out.println("){}") ;
        }

编译方式

动态编译最大限度发挥了Java的灵活性,体现了多态的应用,有以降低类之间的藕合性


反射机制优缺点


动态代理

代理设计:一个操作的接口有两个子类,一个是真实主题的实现类,另一个是代理类。代理实现类要完成比真实主题实现类更多的内容,本身还需要处理一些与具体业务有关的程序代码。

静态代理

import java.lang.reflect.InvocationHandler ;
import java.lang.reflect.Proxy ;
import java.lang.reflect.Method ;
interface Subject{
    public String say(String name,int age) ;    // 定义抽象方法say
}
class RealSubject implements Subject{   // 实现接口
    public String say(String name,int age){
        return "姓名:" + name + ",年龄:" + age ;
    }
};
class MyInvocationHandler implements InvocationHandler{
    private Object obj ;
    public Object bind(Object obj){
        this.obj = obj ;    // 真实主题类
        return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this) ;
    }
    public Object invoke(Object proxy,Method method,Object[] args) throws Throwable{
        Object temp = method.invoke(this.obj,args) ;    // 调用方法
        return temp ;
    }
};
public class DynaProxyDemo{
    public static void main(String args[]){
        Subject sub = (Subject)new MyInvocationHandler().bind(new RealSubject()) ;
        String info = sub.say("Emma",21) ;
        System.out.println(info) ;
    }
};

InvocationHandler接口
刻意将InvocationHandler接口的子类想象成一个代理的最终操作类,替换掉ProxySubject.

public interface InvocationHandler{
          public Object invoke(Object proxy,Method method,Object[] args)  throws Throwable
}

Proxy类
专门完成代理的操作类,可以通过此类为一个或多个接口动态地生成实现类,提供了如下操作方法

public static Objcet newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException

ArrayList的动态代理类

final List<String> list = new ArrayList<String>();
        List<String> proxyInstance = (List<String>) Proxy.newProxyInstance(list.getClass().getClassLoader(),
                list.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        return method.invoke(list, args);
                    }
                });
        proxyInstance.add("你好");
        System.out.println(list);

动静态代理的区别&使用场景


上一篇下一篇

猜你喜欢

热点阅读