JAVA反射
1.定义
在《JAVA核心技术 卷一》这样写道:能够分析类能力的程序称为反射。
简单来说就是,可以动态的获取任意一个类的方法,属性,构造函数等信息。
2.反射用到的类
- Class类:保存(获取)类的信息
- Field类:保存(获取)类的成员变量
- Method类:保存(获取)类的方法
- Constructor类:保存(获取)类的构造器
下面具体说一下以上各类:
重要的几个方法
Class这个类主要是通过对象或者字符串获取相关类的信息,人们可以通过Class中的方法对这个类进行相关的处理。
1.forName(String className):
这个方法大家应该在数据库的时候见到过,主要是通过传入类的全类名,从而加载这个类(注意这里并不是创建的这个类的对象,而是加载这个类并且赋值给Class的对象变量)。
比如:
try {
Class s = Class.forName("com.cyk.text.Dog");
} catch (Exception e) {
// TODO: handle exception
}
这个代码将com.cyk.text包下的Dog类进行加载并赋值给Class的对象变量s,该对象存储了Dog类的相关信息,并且初始化了Dog中的相关的实例域和代码块(比如静态代码块),但并不执行构造函数。
同时还有一个重点就是,这个forName方法在书写的时候必须要进行异常信息的处理,也就是添加try…catch方法。因为forName方法是一个已检查异常。
这里简单的说一些异常的分类:
异常大体上可以分为两种:
1.以检测异常:在编写的时候需要添加try…catch,如果程序出现异常将会通过catch进行抛出。这个在编写的时候编译器会进行提示是否需要添加try…catch.
2.未检测异常:在编写的时候并不需要一定的添加try…catch。在程序运行的时候出现错误,程序将会终止,并在控制台打印错误,比如:空指针异常。
当然有关异常的其他情况在这就不做详细的介绍了。
2.Object.getClass()
该方法将会返回一个Class类的对象,该对象将存储了Object类中的相关信息。
Dog dog = new Dog();
Class class1 = dog.getClass();
该方法和forName方法大同小异,一个是通过字符串,另一个直接通过类的对象。那么我们就会产生一个疑问,这两个生成的Class对象是相等吗?
if (class1==s) {
System.out.println("11");
}
结果如下图所示,很明显,两个对象是相等的。也就是说用这两个方法哪一个都是一样的。
3.newInstance()
该方法将会动态的创建一个类的实例(通过调用无参的构造方法,如果没有无参的构造方法将会报错)。也就是直接就生成了该类的对象,例子如下:
Dog dog = new Dog();
try {
Dog class1 = dog.getClass().newInstance();
} catch (InstantiationException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IllegalAccessException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
以上的代码将会获得一个Dog对象,注意这个方法也是一个已检查异常,需要添加try…catch。
在上面说到getClass方法和froName方法的到的结果是一样的,但是在使用这个方法的时候却并不相同,下面是forName方法调用newInstance()方法的代码:
try {
Dog s = (Dog) Class.forName("com.cyk.text.Dog").newInstance();
} catch (Exception e) {
// TODO: handle exception
}
可以发现通过forName调用newInstance()方法返回的并不是一个dog对象,而是一个Object对象,需要通过强制转化成为Dog对象。
4.Field[] getFields()与Field[] getDelcaredFields()
这是两个相关的方法:
getFields():该方法将会记录该类以及其超类的公有域;
getDelcaredFields():该方法将会记录该类的所有的属性,但不能记录超类的属性。
实例:
在Animal类中:
public class Animal {
public String ss="0";
//动物的年龄
private int age;
//动物的性别
private String gender;
}
在Dog类中:
public class Dog extends Animal{
public String b="11";
//狗的名字
private String name;
}
测试类:
Dog dog = new Dog();
Class class1 = dog.getClass();
Field []aFields = class1.getDeclaredFields();
for (Field field : aFields) {
System.out.println(field);
}
这里调用了getDeclaredField(),这个方法将会记录该类中的全部属性在Field的数组中,并循环输出,结果如下:
很明显返回了Dog类中的所以属性,并没有返回超类的。
接下来调用getFields方法:
Dog dog = new Dog();
Class class1 = dog.getClass();
Field []aFields = class1.getFields();
for (Field field : aFields) {
System.out.println(field);
}
结果如下:
可以发现结果中是该类和超类中的public的属性。
5.Method[] getMethods() 与 Method[] getDeclaredMethods()
这是两个相关的方法:
getMethods():该方法将会记录该类以及其超类的共有方法;
getDeclaredMethods():该方法将会记录该类的所有的方法,但不能记录超类的方法。
我们给Animal和Dog类中的属性添加get和set方法(都是publice),并给Dog中添加一个私有的方法:
private void name() {
System.out.println("这个是狗的私有方法");
}
在测试类中调用getMethods方法,并将结果循环输出
Dog dog = new Dog();
Class class1 = dog.getClass();
Method []methods = class1.getMethods();
for (Method method : methods) {
System.out.println(method);
}
结果如下图所示:
可以发现Dog和Animal的共有方法都展现出来了,当然也会有Object中的共有方法,因为所有的类都继承与Object。
接下来调用另一个方法getDeclaredMethods,并循环输出:
Dog dog = new Dog();
Class class1 = dog.getClass();
Method []methods = class1.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method);
}
结果如下图所示:
可以很清楚的发现,这个方法返回了Dog类中的所有方法。
6.Constructor[] getConstructors() 与 Constructor[] getDeclaredConstructors()
这是两个相关的方法:
getConstructors():该方法将会记录该类以及其超类的公有构造器;
getDeclaredConstructors():该方法将会记录该类的所有的构造器,但不能记录超类的构造器。
在狗类中添加相应的构造器方法:
private Dog(String name){
System.out.println("这是狗的名字"+name);
}
public Dog() {
System.out.println("这是狗的方法");
}
在Animal中也添加相应的构造器方法:
public Animal() {
System.out.println("这是动物的构造方法");
}
在测试类中调用getConstructors方法
Dog dog = new Dog();
Class class1 = dog.getClass();
Constructor [] constructors = class1.getConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
结果如下:
该方法会显示出Dog类中的所有的共有构造器方法。
下面利用测试类调用getDeclaredConstructorsf方法
Constructor [] constructors = class1.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println(constructor);
}
结果如下:
可以发现该方法将会展现出Dog类张的所有的构造器。
当然还有很多的方法:
getModifiers():该方法将返回一个描述方法的修饰符的整型数值(可以利用toString(Class对象.getgetModifiers)方法返回修饰符,既可以返回publice,private等);
getName():返回相应的方法,属性的名字;
getParameterTypes():返回一个用于描述参数类型的对象
getReturnType():用于一个描述返回类型的对象
…
还有很多的方法在这就不做一一的介绍了,
总结
本文列举了反射一些常用的方法,渎职可以进行借鉴,反射可以动态的获取一些类的信息,从而获取类中的方法,属性,构造器等信息。