Java反射机制学习
什么是反射
在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
反射有什么用
1,在运行时判断任意一个对象所属的类;
2,在运行时构造任意一个类的对象;
3,在运行时判断任意一个类所具有的成员变量和方法;
4,在运行时调用任意一个对象的方法;
5,生成动态代理。
实现Java反射的类
1)Class:它表示正在运行的Java应用程序中的类和接口
2)Field:提供有关类或接口的属性信息,以及对它的动态访问权限
3)Constructor:提供关于类的单个构造方法的信息以及对它的访问权限
4)Method:提供关于类或接口中某个方法信息
注意:Class类是Java反射中最重要的一个功能类,所有获取对象的信息(包括:方法/属性/构造方法/访问权限)都需要它来实现
编写Java反射程序的步骤:
1)必须首先获取一个类的Class对象
例如:
Class c1 = Test.class;
Class c2 = Class.forName(“com.reflection.Test”);
Class c3 = new Test().getClass();
2)然后分别调用Class对象中的方法来获取一个类的属性/方法/构造方法的结构 注意:如果要能够正常的获取类中方法/属性/构造方法应该重点掌握如下的反射类
Field
Constructor
Method
在此给出一个总结性的例子:
package com.gbx; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.lang.reflect.Modifier; interface IBase{ void show(); } class Base{ } class Person extends Base implements IBase{ private int id; public String name; protected int[] ages; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Person() { super(); // TODO Auto-generated constructor stub } public Person(int id, String name, int[] ages) { super(); this.id = id; this.name = name; this.ages = ages; } @Override public void show() { System.out.println("人物信息为:" +id + " " + name + " " + ages); } } public class Test { /* * 动态获取指定类的各种信息 * 1,在运行时判断任意一个对象所属的类; * 2,在运行时构造任意一个类的对象; * 3,在运行时判断任意一个类所具有的成员变量和方法; * 4,在运行时调用任意一个对象的方法; */ public static void test1() throws ClassNotFoundException{ Class c1 = Class.forName("com.gbx.Person"); Class c2 = Person.class; Class c3 = new Person().getClass(); /* * 获取类所在包名, 通过输出可以看到, 这三种方式得到的Class是一样的 */ String packe1 = c1.getPackage().toString(); String packe2 = c2.getPackage().toString(); String packe3 = c3.getPackage().toString(); System.out.println(" packe1 = " + packe1 + "\n packe2 = " + packe2 + "\n packe3 = " + packe3); System.out.println("c1 == c2 : " + (c1 == c2) + "c2 == c3" + (c2 == c3)); /* * 获得类的访问修饰符 */ int mod = c1.getModifiers(); //可以输出看看 //System.out.println(Modifier.toString(0) + " : " + Modifier.toString(1) + " : " +Modifier.toString(2) + " : " + Modifier.toString(3) + ":" + Modifier.toString(4)); System.out.println(Modifier.toString(mod)); /* * 获取制定类的完全限定名字 */ String calssName = c1.getName(); System.out.println("calssName = " + calssName); /* * 获取指定类的父类 */ Class superCalss = c1.getSuperclass(); System.out.println("superClassName = " + superCalss.getName()); /* * 获取指定类的实现的接口 */ Class[] interfaces = c1.getInterfaces(); for (Class inf : interfaces) { System.out.println("interface name : " + inf.getName()); } //一下三部分的获取对于我们来说至关重要。。分别是:构造函数, 成员变量, 成员方法 /* * 获取指定类的构造函数 涉及的类:Constructor */ Constructor[] constructors = c1.getConstructors(); System.out.println("构造方法有:"); for (Constructor c : constructors) { //访问修饰符 mod = c.getModifiers(); String modfier = Modifier.toString(mod); //构造函数名字 String name = c.getName(); System.out.print(modfier + " " + name + "("); //参数列表 Class[] paramTypes = c.getParameterTypes(); for (int i = 0; i < paramTypes.length; ++i) { if (i > 0) { System.out.print(","); } if (paramTypes[i].isArray()) { System.out.print(paramTypes[i].getComponentType().getName() + " [] "); } else { System.out.print(paramTypes[i].getName()); } } System.out.println(")"); } /* * 获取指定类的成员变量 涉及到的类 Field */ Field[] fields = c1.getDeclaredFields(); System.out.println("声明的成员变量有:"); for (Field field : fields) { mod = field.getModifiers(); String modifier = Modifier.toString(mod); System.out.print(modifier + " "); Class type = field.getType(); if (type.isArray()) { System.out.print(type.getComponentType().getName() + " "); } else { System.out.print(type.getName() + " "); } String name = field.getName(); System.out.println(name); } /* * 获取指定类的成员方法 涉及的类Method */ Method[] methods = c1.getDeclaredMethods(); System.out.println("成员方法有:"); for (Method method :methods) { mod = method.getModifiers(); String modifer = Modifier.toString(mod); System.out.print(modifer + " "); Class returnType = method.getReturnType(); if (returnType.isArray()) { System.out.print(returnType.getComponentType().getName() + " "); } else { System.out.print(returnType.getName() + " "); } String name = method.getName(); System.out.print(name + " ( "); Class[] paramTypes = method.getParameterTypes(); for (int i = 0; i < paramTypes.length; ++i) { if (i > 0){ System.out.println(","); } if (paramTypes[i].isArray()) { System.out.print(paramTypes[i].getComponentType().getName()); } else { System.out.print(paramTypes[i].getName()); } } System.out.println(" )"); } } /* * 生成动态代理。 */ public static void test2() throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { Class c1 = Class.forName("com.gbx.Person"); Person p = (Person)c1.newInstance(); System.out.println("id = " + p.getId()); System.out.println("name = " + p.getName()); Method method = c1.getDeclaredMethod("setName", String.class); method.setAccessible(true); //通过这一步设置我们甚至可以访问private的成员 method.invoke(p, "小明"); System.out.println("id = " + p.getId()); System.out.println("name = " + p.getName()); } public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, SecurityException, IllegalArgumentException, InvocationTargetException { test1(); test2(); } } 输出: packe1 = package com.gbx packe2 = package com.gbx packe3 = package com.gbx c1 == c2 : truec2 == c3true calssName = com.gbx.Person superClassName = com.gbx.Base interface name : com.gbx.IBase 构造方法有: public com.gbx.Person(int,java.lang.String,int [] ) public com.gbx.Person() 声明的成员变量有: private int id public java.lang.String name protected int ages 成员方法有: public void setId ( int ) public void show ( ) public java.lang.String getName ( ) public int getId ( ) public void setName ( java.lang.String ) id = 0 name = null id = 0 name = 小明
反射调用参数维数组的方法:
public class DemoTest { /* * 利用反射对参数是数组的方法的调用。 * 由于JDK5之前没有可变参数, 我们如果实现参数任意的话,就需要使用object[]来实现 * JDK5出现之后我们有了可变参数的就很方便了,但是为了兼容之前的代码,我们的可变参数接受数组, * 然后将数组中的变量一个一个的放入对应的对应的变量。 * 如果方法参数是数组,例如public void show(String[] res) * method.invoke(1,2);第二个参数接受的是的可变参数,我们传入一个数组的话,他会将数组中的第一 * 个值作为res的。后边的继续作为下一个参数。所以不会找到 */ @Test public void test() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Class clazz = Class.forName("com.cn.gbx.Person"); Method method = clazz.getMethod("main",String[].class); method.invoke(null, new Object[]{new String[]{"a", "b"}});// 第一种解决方案 } @Test public void test2() throws ClassNotFoundException, NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { Person p = new Person(); Class<?> clazz = Class.forName("com.cn.gbx.Person"); Method method = clazz.getMethod("show", String[].class); method.invoke(p, (Object)new String[]{"aa","bb"}); //第二种解决方案 } } package com.cn.gbx; public class Person { public static void main(String[] args) { System.out.println("main invoke ..."); } public void show(String[] res) { System.out.println("string[] res"); for (String s : res) { System.out.println(s); } } }