Java反射机制
Java反射机制
Java反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。
用一句话总结就是反射可以实现在运行时可以知道任意一个类的属性和方法。
这样做可以提高代码的灵活度。适度使用。过度使用会降低代码运行效率,增加资源开销。
Java 反射机制的优缺点
优点
可以实现动态创建对象和编译,体现出很大的灵活性,特别是在J2EE的开发中它的灵活性就表现的十分明显。比如,一个大型的软件,不可能一次就把把它设计的很完美,当这个程序编译后,发布了,当发现需要更新某些功能时,我们不可能要用户把以前的卸载,再重新安装新的版本,假如这样的话,这个软件肯定是没有多少人用的。采用静态的话,需要把整个程序重新编译一次才可以实现功能的更新,而采用反射机制的话,它就可以不用卸载,只需要在运行时才动态的创建和编译,就可以实现该功能。
缺点
对性能有影响。使用反射基本上是一种解释操作,我们可以告诉JVM,我们希望做什么并且它满足我们的要求。这类操作总是慢于只直接执行相同的操作。
Java 反射机制在一般的 Java 应用开发中很少使用,即便是 Java EE 阶段也很少使用。
理解Class类和类类型
想要了解反射首先理解一下Class类,它是反射实现的基础。
类是java.lang.Class类的实例对象,而Class是所有类的类(There is a class named Class)
Class类的每个实例用于表示JVM加载的一个类。并且在JVM内部每个被加载的类有且仅有一个Class的实例与之对应。
对于普通的对象,我们一般都会这样创建和表示:
1 Code code1 = new Code();
构造器是私有的,只有JVM可以创建Class的对象,因此不可以像普通类一样new一个Class对象,虽然我们不能new一个Class对象,但是却可以通过已有的类得到一个Class对象,共有三种方式,如下:
1 Class c1 = Code.class; 2 //这说明任何一个类都有一个隐含的静态成员变量class,这种方式是通过获取类的静态成员变量class得到的 3 4 Class c2 = code1.getClass(); 5 //code1是Code的一个对象,这种方式是通过一个类的对象的getClass()方法获得的 6 7 Class c3 = Class.forName("com.trigl.reflect.Code"); 8 //这种方法是Class类调用forName方法,通过一个类的全量限定名获得
这里,c1、c2、c3都是Class的对象,他们是完全一样的,而且有个学名,叫做Code的类类型(class type)。
Java反射相关操作
以通过这个Class干的事情:获取成员方法Method、获取成员变量Field、获取构造函数Constructor
常用API
String getName() //获取当前类的名。包名.类名
Constructor<?>[] getDeclaredConstructors() //获取当前类的所有构造方法
Method[] getDeclaredMethods() //获取当前类自己定义的所有方法
Method[] getDeclaredMethod("sayHello") //指定获取当前类定义某个方法。参数为想要获取方法的名字。
Method[] getMethods() //获取当前类和从父类继承所有的方法
Object newInstance() //获取当前类的无参构造方法,如果没有则抛出异常
invoke(Object o,Object[] arg) //Method类中的方法,用于调用方法。第一个参数为调用哪个实例的对应方法,第二个参数为调用该对应方法是传递的实际参数
public Field getDeclaredField(String name) // 获得该类某个变量
Field[] fields getDeclaredFields() //获得该类自身声明的所有变量,不包括其父类的变量
public Field getField(String name) // 获得该类自所有的public成员变量,包括其父类变量
获取成员方法信息
单独获取某一个方法是通过Class类的以下方法获得的:
1 public Method getDeclaredMethod(String name, Class<?>... parameterTypes) // 得到该类所有的方法,不包括父类的 2 public Method getMethod(String name, Class<?>... parameterTypes) // 得到该类所有的public方法,包括父类的
两个参数分别是方法名和方法参数类的类类型列表。
例如类A有如下一个方法:
public void fun(String name,int age) { System.out.println("我叫"+name+",今年"+age+"岁"); }
现在知道A有一个对象a,那么就可以通过:
Class c = Class.forName("com.tengj.reflect.Person"); //先生成class,Person为自定义类的全称 Object o = c.newInstance(); //newInstance可以初始化一个实例 Method method = c.getMethod("fun", String.class, int.class);//获取方法 method.invoke(o, "tengj", 10); //通过invoke调用该方法,参数第一个为实例对象,后面为具体参数值
获取成员变量信息
想一想成员变量中都包括什么:成员变量类型+成员变量名
类的成员变量也是一个对象,它是java.lang.reflect.Field
的一个对象,所以我们通过java.lang.reflect.Field
里面封装的方法来获取这些信息。
单独获取某个成员变量,通过Class类的以下方法实现:
1 public Field getDeclaredField(String name) // 获得该类某个变量 2 Field[] fields getDeclaredFields() //获得该类自身声明的所有变量,不包括其父类的变量 3 public Field getField(String name) // 获得该类自所有的public成员变量,包括其父类变量
参数是成员变量的名字。
例如一个类A有如下成员变量:
1 private int n;
如果A有一个对象a,那么就可以这样得到其成员变量:
1 Class c = a.getClass(); 2 Field field = c.getDeclaredField("n");
获取构造函数
同上,类的成构造函数也是一个对象,它是java.lang.reflect.Constructor
的一个对象,所以我们通过java.lang.reflect.Constructor
里面封装的方法来获取这些信息。
单独获取某个构造函数,通过Class类的以下方法实现:
1 public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) //获得该类所有的构造器,不包括其父类的构造器 2 public Constructor<T> getConstructor(Class<?>... parameterTypes) // 获得该类所以public构造器,包括父类
这个参数为构造函数参数类的类类型列表
例如类A有如下一个构造函数:
1 public A(String a, int b) { 2 // code body 3 }
获取这个构造函数:
1 Class c = Class.forName("com.tengj.reflect.Person");//获取构造函数 2 Constructor constructor = c.getDeclaredConstructor(String.class, int.class);