一、什么是反射:
在计算机科学领域,反射是指一类应用,它们能够自描述和自控制。也就是说,这类应用通过采用某种机制来实现对自己行为的描述(self-representation)和监测(examination),并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义。
二、反射机制的功能:
1.在运行时判断任意一个对象所属的类
2.在运行时构造任意一个类的对象
3.在运行时判断任意一个类所具有的成员变量和方法(通过反射甚至可以调用private方法)
4.在运行时调用任意一个对象的方法(*****注意:前提都是在运行时,而不是在编译时)
Java 反射相关的API简介:(位于java。lang。reflect包中)
--Class类:代表一个类
--Filed类:代表类的成员变量
--Method类:代表类的方法
--Constructor类:代表类的构造方法
--Array类:提供了动态创建数组,以及访问数组的元素的静态方法。该类中的所有方法都是静态方法
Reflection 是 Java 被视为动态(或准动态)语言的关键它允许运行中的 Java 程序对自身进行检查,或者说“自审”,并能直接操作程序的内部属性和方法
三、什么情况下用到反射:
1. 比如此方法是private的,你不能直接调用,反射可以;
2. 比如你只知道此方法名的规则,运行时才知道具体方法,你无法直接调用。
例如setter方法,框架在运行时才知道某类有“name”属性,根据setter规则构造方法名“setName”,这时只能通过反射来调用;
就像我们的编程之中有动态和静态之分,反射的作用就是动态的获取一个类的属性和方法。例如我们定义了一个接口,实现这个接口的类有20个,程序里用到了这个实现类的地方有好多地方,如果我们不使用配置文件手写的话,代码的改动量是不是很大呢,因为每个地方都要改而且不容易定位,如果我们在编写之前先将接口与实现类的写在配置文件里,下次只需改配置文件,利用反射(java API已经封装好了,你直接用就可以用 Class.newInstance())就可完成。
因为学习的还比较浅显,什么情况的反射没有找到很好的解释,上面也是我看到和想到的一些情况,欢迎补充。
下面是关于反射类测试的一些java代码:
这个类是用来测试的,它继承了Object类,有一个接口是ActionListener,两个属性int和Integer,两个构造方法和两个方法。
public class A extends Object implements ActionListener{ private int a=3; public Integer b=new Integer(4); public A(){} public A(int id ,String name){} public int abc(int id,String name){return 0;} public void actionPerformed(ActionEvent e) { } }
那么我们要拿A类做什么呢?我们把A类作为一个反射类,利用反射类的方法去取A中的属性和方法。
public class B { public static void main(String args[]) { A r = new A(); Class temp = r.getClass(); System.out.println("反射类中所有公有属性"); Field[] fb = temp.getFields(); for (int j = 0; j < fb.length; j++) { Class c1 = fb[j].getType(); System.out.println("属性:" + c1); } System.out.println("反射类中的所有属性"); Field[] fa = temp.getDeclaredFields(); for (int j = 0; j < fa.length; j++) { Class c1 = fa[j].getType(); System.out.println("fa:" + c1); } System.out.println("反射类中私有属性的值"); try { Field f = temp.getDeclaredField("a"); f.setAccessible(true); Integer i = (Integer) f.get(r); System.out.println(i); } catch (SecurityException e) { e.printStackTrace(); } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (IllegalArgumentException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } } }
这里用到了两个方法,getFields()、getDeclaredFields(),它们分别是用来获取反射类中所有公有属性和反射类中所有的属性的方法。另外还有getField(String)和getDeclaredField(String)方法都是用来过去反射类中指定的属性的方法,要注意的是getField方法只能取到反射类中公有的属性,而getDeclaredField方法都能取到私有属性。 这里还用到了Field 类的setAccessible方法,它是用来设置是否有权限访问反射类中的私有属性的,只有设置为true时才可以访问,默认为false。另外 Field类还有set(Object AttributeName,Object value)方法,可以改变指定属性的值。
下面的代码是如何获取反射类的构造方法和方法:
public class C { public static void main(String[] args){ A r=new A(); printConstructors(r); } public static void printConstructors(A r){ Class c=r.getClass(); //获取指定的类名 String className=c.getName(); //获取指定构造器 Constructor[] theConstructors=c.getConstructors(); for(int i=0;i<theConstructors.length;i++){ //获取指定构造方法的参数的集合 Class[] parameterTypes=theConstructors[i].getParameterTypes(); System.out.print(className+"("); for(int j=0;j<parameterTypes.length;j++){ System.out.print(parameterTypes[j].getName()+" "); } System.out.println(")"); } } }
public class D { public static void main(String[] args){ A p=new A(); printMethods(p); } public static void printMethods(Object o){ Class c=o.getClass(); String className=c.getName(); Method[] m=c.getMethods(); for(int i=0;i<m.length;i++){ //输出方法返回类型 System.out.print(m[i].getReturnType().getName()); //输出方法名 System.out.print(" "+m[i].getName()+"("); //获取方法的参数 Class[] parameterTypes=m[i].getParameterTypes(); for(int j=0;j<parameterTypes.length;j++){ System.out.print(parameterTypes[j].getName()); if(parameterTypes.length>j+1){ System.out.print(","); } } System.out.println(")"); } } }
既然我们能获取反射类的属性、构造方法、父类、接口和方法,可这些东西能帮我们做些什么呢?我们可以利用反射类生成实体对象。
想生成对象的实体,在反射动态机制中有两种方法,一个针对无变量的构造方法,一个针对带参数的构造方法,,如果想调用无参数的构造函数直接调用Class类中的newInstance(),而如果想调用有参数的构造函数,则需要调用Constructor类中newInstance()方法,首先准备一个Class[]作为Constructor的参数类型。然后调用该Class对象的getConstructor()方法获得一个专属的Constructor的对象,最后再准备一个Object[]作为Constructor对象昂的newInstance()方法的实参。 在这里需要说明的是 只有两个类拥有newInstance()方法,分别是Class类和Constructor类,Class类中的newInstance()方法是不带参数的,而Constructro类中的newInstance()方法是带参数的需要提供必要的参数。
public static void main(String[] args) throws InstantiationException, IllegalAccessException, IllegalArgumentException, SecurityException, InvocationTargetException, NoSuchMethodException { Customer2 customer = new Customer2(); Class cls = customer.getClass(); // 获得Class所代表的对象的所有类型的构造函数Constructor的数组 Constructor ctor[] = cls.getDeclaredConstructors(); for (int i = 0; i < ctor.length; i++) { // 获得对应的构造函数参数列表的Class类型的数组 Class cx[] = ctor[i].getParameterTypes(); if (cx.length == 0) { // 无参的构造函数可以通过Class实例直接调用Class类的newInstance()方法 Object obj = cls.newInstance(); // 同样也可以象以下这样构造,调用Constructor类的newInstance()方法 // Customer2 // obj=(Customer2)cls.getConstructor(cx).newInstance(new // Object[]{}); System.out.println(obj); } else if (cx.length == 2) { // 此时只能调用Constructor类的newInstance()方法,注意:利用反射调用的是私有private的构造方法 Customer2 obj = (Customer2) cls.getConstructor(cx).newInstance( new Object[] { new Long(123), "MWJ" }); System.out.println(obj); } else if (cx.length == 3) { // 此时只能调用Constructor类的newInstance()方法,注意:利用反射调用的是公有public的构造方法 Customer2 obj = (Customer2) cls.getConstructor(cx).newInstance( new Object[] { new Long(133), "MWJ", new Integer(20) }); System.out.println(obj); } } } } class Customer2 { private Long id; private String name; private int age; /** * 无参数的构造函数 * */ public Customer2() { } /** * public修饰的有参数的构造函数,3个参数 * * @param id * @param name * @param age */ public Customer2(Long id, String name, int age) { this.id = id; this.name = name; this.age = age; } /** * public修饰的构造函数,2个参数 * * @param id * @param name */ public Customer2(Long id, String name) { this.id = id; this.name = name; this.age = age; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString() { return ("id==" + this.getId() + " Name==" + this.getName() + " Age:" + this .getAge()); } }
程序执行结果如下:
id==123 Name==MWJ Age:0
id==133 Name==MWJ Age:20
id==null Name==null Age:0