在Java运行时环境中,对于任意一个类,能否知道这个类有哪些属性和方法?对于任意一个对象,能否调用它的任意一个方法?
答案是肯定的。
这种动态获取类的信息以及动态调用对象的方法的功能来自于Java语言的反射(Reflection)机制。
来通过代码来看看java反射机制的使用。
package com.lql.demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class test2 {
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>public static void main(String[] args) {
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>String str = new String();
<span style="white-space:pre"> </span>System.out.println(str.getClass());//通过getClass()获取对象的类
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>try {
<span style="white-space:pre"> </span>Class class1 = Class.forName("java.util.Date");//通过forName("包名+类名"),指定包下的类
<span style="white-space:pre"> </span>System.out.println(class1);
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>} catch (ClassNotFoundException e) {
<span style="white-space:pre"> </span>// TODO Auto-generated catch block
<span style="white-space:pre"> </span>e.printStackTrace();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>Class class2 = String.class;//通过.class获取某个类的类
<span style="white-space:pre"> </span>System.out.println(class2);
<span style="white-space:pre"> </span>System.out.println("-------------------------------");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//通过Class的class2对象所对应的类中所声明的所有方法,
<span style="white-space:pre"> </span>Method[] methods = class2.getDeclaredMethods();
<span style="white-space:pre"> </span>for(Method method2 : methods){
<span style="white-space:pre"> </span>System.out.println(method2);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>System.out.println("-------------------------------");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//通过Class的class2对象所对应的类中所声明的字段,
<span style="white-space:pre"> </span>Field[] fields = class2.getDeclaredFields();
<span style="white-space:pre"> </span>for(Field field : fields){
<span style="white-space:pre"> </span>System.out.println(field);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>System.out.println("-------------------------------");
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//通过Class的class2对象创建一个class2所对应类的一个对象,
<span style="white-space:pre"> </span>try {
<span style="white-space:pre"> </span>Object object = class2.newInstance();//通过java的反射机制会调用class2所对应类的无参构造方法
<span style="white-space:pre"> </span>System.out.println(object instanceof String);//打印true,说明class2对应的是类是String
<span style="white-space:pre"> </span>} catch (InstantiationException e) {
<span style="white-space:pre"> </span>// TODO Auto-generated catch block
<span style="white-space:pre"> </span>e.printStackTrace();
<span style="white-space:pre"> </span>} catch (IllegalAccessException e) {
<span style="white-space:pre"> </span>// TODO Auto-generated catch block
<span style="white-space:pre"> </span>e.printStackTrace();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>//获取class2所对应类的所有构造方法
<span style="white-space:pre"> </span>System.out.println("-------------------------------");
<span style="white-space:pre"> </span>try {
<span style="white-space:pre"> </span>Constructor[] constructors = class2.getConstructors();
<span style="white-space:pre"> </span>for(Constructor constructor : constructors){
<span style="white-space:pre"> </span>System.out.println(constructor);
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>} catch (SecurityException e) {
<span style="white-space:pre"> </span>// TODO Auto-generated catch block
<span style="white-space:pre"> </span>e.printStackTrace();
<span style="white-space:pre"> </span>}
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>
<span style="white-space:pre"> </span>}
}
以上代码中,无论是获取某个对象的Class,还是通过Class 的一个对象class2获取其对应的类下的Method,Field,Constructor,都是通过java的反射机制来实现的。
java通过反射机制为我们提供了以下功能:
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判段任意一个类所具有的成员变量和方法
在运行时调用任一个对象的方法
在运行时创建新类对象
在使用Java的反射功能时,基本首先都要获取类的Class对象,再通过Class对象获取其他的对象。
再来看看如何通过反射调用
package com.lql.demo;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class test3 {
public static void main(String[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException, InstantiationException {
NumAdd numAdd = new NumAdd();
//获取numAdd所对应的Class对象,当然也可以通过类名.class()或者forName();的方式
Class class1 = numAdd.getClass();
System.out.println(class1);
System.out.println("-------------------------------------------------");
//通过反射获取NumAdd的所有属性
Field[] fields = class1.getDeclaredFields();
for(Field field : fields){
System.out.println(field);
}
System.out.println("-------------------------------------------------");
//通过反射获取NumAdd的所有方法
Method[] methods = class1.getDeclaredMethods();
for(Method method : methods){
System.out.println(method);
}
System.out.println("-------------------------------------------------");
//通过反射获取NumAdd的所有构造方法
Constructor[] constructors = class1.getConstructors();
for(Constructor constructor : constructors){
System.out.println(constructor);
}
System.out.println("-------------------------------------------------");
//获取指定的参数的方法,然后调用,不使用NumAdd的对象调用,而是使用反射机制
//第一个参数是方法名,第二个参数是方法中的参数类型的数组
Method addMethod = class1.getDeclaredMethod("add",new Class[]{int.class , int.class});
//调用addMethod,addMethod,先获取一个class1所对应类的一个对象,然后给addMethod指定所需参数
Object instance = class1.newInstance();
addMethod.invoke(instance,new Integer[]{1,2});
System.out.println("-------------------------------------------------");
//同样通过反射调用另一个打印方法
Method printMethod = class1.getDeclaredMethod("myprint",new Class[]{String.class});
printMethod.invoke(instance, new String("hello world"));
}
}
class NumAdd{
private int num;
public String str;
public NumAdd(){
}
public NumAdd(int num){
this.num = num;
}
public NumAdd(int num,String str){
this(num);
this.str = str;
}
public void add(int a , int b){
System.out.println(a + b);
}
public void myprint(String message){
System.out.println(message);
}
}