Java——反射机制

来源:互联网 发布:打条码软件 编辑:程序博客网 时间:2024/05/16 09:49

反射概念:

Java反射是Java被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运行时透过Reflection APIs取得任何一个已知名称的class的内部信息,包括其modifiers(诸如public, static 等)、superclass(例如Object)、实现之interfaces(例如Cloneable),也包括fields和methods的所有信息,并可于运行时改变fields内容或唤起methods。

Java反射机制容许程序在运行时加载、探知、使用编译期间完全未知的classes。

换言之,Java可以加载一个运行时才得知名称的class,获得其完整结构。

反射是Java中一种强大的工具,能够使我们很方便的创建灵活的代码,这些代码可以再运行时装配,无需在组件之间进行源代码链接。但是反射使用不当会成本很高!


JAVA反射机制提供了什么功能

提供了如下功能:

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判段任意一个类所具有的成员变量和方法
  • 在运行时调用任一个对象的方法
  • 在运行时创建新类对象
  • 在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。

反射机制的作用:

  • 反编译:.class–>.java
  • 通过反射机制访问java对象的属性,方法,构造方法等;

Java中JDK提供的Reflection API

Java反射相关的API在包java.lang.reflect中。

Member接口 该接口可以获取有关类成员(域或者方法)后者构造函数的信息。

AccessibleObject类 该类是域(field)对象、方法(method)对象、构造函数(constructor)对象的基础类。它提供了将反射的对象标记为在使用时取消默认

Java 语言访问控制检查的能力。 Array类 该类提供动态地生成和访问JAVA数组的方法。

Constructor类 提供一个类的构造函数的信息以及访问类的构造函数的接口。 Field类 提供一个类的域的信息以及访问类的域的接口。

Method类 提供一个类的方法的信息以及访问类的方法的接口。

Modifier类 提供了 static方法和常量,对类和成员访问修饰符进行解码。

Proxy类 提供动态地生成代理类和类实例的静态方法。


动态创建代理类

代理模式:代理模式的作用=为其他对象提供一种代理以控制对这个对象的访问。

代理模式的角色:

  • 抽象角色:声明真实对象和代理对象的共同接口
  • 代理角色:代理角色内部包含有真实对象的引用,从而可以操作真实对象。
  • 真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

动态代理:

  • java.lang.reflect.Proxy
    Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类
  • InvocationHandler
    是代理实例的调用处理程序 实现的接口,每个代理实例都具有一个关联的调用处理程序。对代理实例调用方法时,将对方法调用进行编码并将其指派到它的调用处理程序的 invoke 方法。

动态Proxy是这样的一种类:

它是在运行生成的类,在生成时你必须提供一组Interface给它,然后该class就宣称它实现了这些interface。你可以把该class的实例当作这些interface中的任何一个来用。当然,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。
在使用动态代理类时,我们必须实现InvocationHandler接口


实例练习:

import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.List;public class InvokeTest {    /**     * 利用反射机制实现调用方法     * @param obj     * @param methodName     * @throws NoSuchMethodException     * @throws SecurityException     * @throws IllegalAccessException     * @throws IllegalArgumentException     * @throws InvocationTargetException     */    public static void test(String methodName) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {        InvokeTest test=new InvokeTest();        //对象类型        Class<?> cls=test.getClass();        //利用反射机制获取该类型下的方法        Method method=cls.getMethod(methodName, int.class,String.class);        //执行该方法        method.invoke(test, 10,"20");//      test.method(10,20)    }    /**     * ...代表:一组相同类型的数据(不约束个数)     * 一个方法里最多只能有一个...类型     * ...类型必须出现在参数列表的最后位置     * @param a     */    public static void e(int... a) {        for(int i=0;i<a.length;i++) {            System.out.println(a[i]);        }    }    //反射机制    //调用方法    //不知道方法名或属性名    //通过传递参数来实现调用    public static void main(String[] args) {        //...省略参数类型        e(1,2,3,4,5);        //反射机制        try {            test("d");        } catch (NoSuchMethodException e) {            // TODO Auto-generated catch block            //没有该方法            e.printStackTrace();        } catch (SecurityException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IllegalAccessException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (IllegalArgumentException e) {            // TODO Auto-generated catch block            e.printStackTrace();        } catch (InvocationTargetException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }    }    public void a() {        System.out.println("aaaaaaaaaa");    }    public void b(int b) {        System.out.println("b="+b);    }    public void c(int a,int b) {        System.out.println("sum="+(a+b));    }    public void d(int a,String b) {        System.out.println(a+b);    }

具体功能的实现

反射机制获取类有三种方法,我们来获取Employee类型。

//第一种方式:  Classc1 = Class.forName("Employee");  //第二种方式:  //java中每个类型都有class 属性.  Classc2 = Employee.class;  //第三种方式:  //java语言中任何一个java对象都有getClass 方法  Employeee = new Employee();  Classc3 = e.getClass(); //c3是运行时类 (e的运行时类是Employee)  

创建对象:获取类以后我们来创建它的对象,利用newInstance:

Class c =Class.forName("Employee");  //创建此Class 对象所表示的类的一个新实例  Objecto = c.newInstance(); //调用了Employee的无参数构造方法.  

获取属性:分为所有的属性和指定的属性:
a,先看获取所有的属性的写法:

//获取整个类              Class c = Class.forName("java.lang.Integer");                //获取所有的属性?              Field[] fs = c.getDeclaredFields();                     //定义可变长的字符串,用来存储属性              StringBuffer sb = new StringBuffer();              //通过追加的方法,将每个属性拼接到此字符串中              //最外边的public定义              sb.append(Modifier.toString(c.getModifiers()) + " class " + c.getSimpleName() +"{\n");              //里边的每一个属性              for(Field field:fs){                  sb.append("\t");//空格                  sb.append(Modifier.toString(field.getModifiers())+" ");//获得属性的修饰符,例如public,static等等                  sb.append(field.getType().getSimpleName() + " ");//属性的类型的名字                  sb.append(field.getName()+";\n");//属性的名字+回车              }              sb.append("}");              System.out.println(sb);  

b,获取特定的属性,对比着传统的方法来学习:

public static void main(String[] args) throws Exception{  <span style="white-space:pre">  </span>//以前的方式:      /*     User u = new User();     u.age = 12; //set     System.out.println(u.age); //get     */      //获取类      Class c = Class.forName("User");      //获取id属性      Field idF = c.getDeclaredField("id");      //实例化这个类赋给o      Object o = c.newInstance();      //打破封装      idF.setAccessible(true); //使用反射机制可以打破封装性,导致了java对象的属性不安全。      //给o对象的id属性赋值"110"      idF.set(o, "110"); //set      //get      System.out.println(idF.get(o));  }  

参考博客:

博客1:

http://blog.csdn.net/liujiahan629629/article/details/18013523

博客2:

http://blog.csdn.net/yongjian1092/article/details/7364451