反射可以用于分析每个类的具体信息。
1. 前置知识:Class类
运用反射机制就要知道一个叫Class的类。这个类的主要功能就是记录一个类的各种信息。在Java中,每个class都有一个相应的Class对象。也就是说,当我们编写一个类,编译完成后,在生成的.class文件中,就会产生一个Class对象,用于表示这个类的类型信息。
比如对一个Math类,其对应的Class类就记录了Math类中有多少域,方法和构造器等信息。
Class类的获取途径
不同于传统类用构造器或者工厂方法获得,该类的获取途径有3个:
- 实例.getClass()
- 类名.class
- Class.forName()
实例.getClass()
Animal a = new Animal();
Animal b = new Dog();
...
Class c_Ani = a.getClass(); //c_Ani的信息是Animal类的Class类的信息
Class c_Dog = b.getClass(); //c_Dog的信息是Dog类的Class类里面的信息
类名.class
Class c_AniClass = Animal.class; //直接通过类名调用该类的class类
Class.forName()
forName()是Class类的一个静态方法。使用如下:
Class c_Math = Class.forName("Math"); //错误,类名不完整
Class c_MathCorrect = Class.forName("java.lang.Math"); //正确
利用Class类进行实例化
这利用了反射的思想,即对于运行当中产生的类,我们可以通过以下代码对其动态(识别)实例化:
public class Test{
public void method(Object obj){
Object instance_One = obj.getClass.newInstance();//也可以在newInstance中放入参数,不放参数则调用默认构造器
Object instance_Two = obj.getClass.newInstance(Object[] args);
}
}
2. 利用反射进行分析——类Field,Method,Constructor
在java.lang.reflect包中有三个类Field,Method,Constructor用于去对Class类包含的域,方法和构造器信息进行分析。
Field类
Field类的获得方法采用了工厂方法:
Field[] f = E.class.getFields();
Field[] f = E.class.getDeclaredFields();
Field f = E.class.getField("域名,如name");
在得到该类的某个域后,可以采用如下方式进行查看/设置(反射回去设置)
Dog dog = new Dog("charls");
Field fName = Dog.class.getField("name");
String newName = fName.get(dog); //查看或设置时侯可能需要权限,这时候要用setAccessible()方法
fName.set(dog, "puppy"); //设置
Method类
Method类的获取方法大致同Field。由于方法名可能相同,因此会有一种特殊的获得方法getMethod(String name,Class<?>... parameterTypes)
方法的调用则采用invoke()
方法。
import java.lang.reflect.Method;
public class MethodTest {
public static void main(String[] args) throws Exception {
User user = new User();
user.setName("jeey");
user.setAge(20);
Class c1= user.getClass();
Method m = c1.getDeclaredMethod("getAge");
System.out.println("获取age属性值:"+m.invoke(user));
//获得重载方法
m = c1.getDeclaredMethod("setAge",int.class);
m.invoke(user, 99);
System.out.println("修改后的值:"+user.getAge());
}
}
Constructor类
Constructor类的获得方法和Method类一致,在具体的使用上是采用了newInstance()
方法
import java.lang.reflect.Constructor;
public class ConstructorTest {
public static void main(String[] args) throws Exception {
User user = new User();
user.setName("jeey");
user.setAge(20);
Class c1= user.getClass();
Constructor cons = c1.getDeclaredConstructor(String.class,int.class);
//通过构造方法创建实例
User u = (User)cons.newInstance("jack",33);
System.out.println("创建实例:name="+u.getName()+",age="+u.getAge());
}
3. 利用反射构造泛型数组——类Array
在程序运行过程中,如果需要构建一个数组,我们可以采用Object[] objs = new Object[length];
的方法进行构建,但是这样构建的数组是不可以转换成某一个类的数组的,因此,要构建泛型数组,就要采用Array类。具体涉及的方法如下:
public boolean isArray() //Class类
public Class<?> getComponentType() //Class类
public static Object newInstance(Class<?> componentType,int length) //Array类
import java.lang.reflect.Array;
public class ArrayTest {
public static void main(String[] args) {
String[] aa = {"aa","bb"};
Class c1 = aa.getClass();
System.out.println("是否是数值:"+c1.isArray()); //判断是否为数组类
System.out.println("数组组件类型的 Class:"+c1.getComponentType());
//初始化数值
String[] arr = (String[])Array.newInstance(c1.getComponentType(), 2);
//数组设值
Array.set(arr, 0, "111");
Array.set(arr, 1, "222");
//访问
System.out.println(arr[0]);
System.out.println(Array.get(arr, 1));
}
}
*部分代码参考Java反射(java.lang.reflect)