1. 反射的概念
对于一个人来说,了解自己的能力、本事、特点,对于他去干事创业来说,是很重要的。
同样的,对于一门面向对象的语言来说,了解类(对象其实就是类的实现)本身也是重要的,可以在很多地方帮助程序更好的进行。
那么类/对象本身包含那些内容呢,无非就是类名称;父类;继承的接口;类的属性;类的方法,这些都属于是类的信息。
好的,那么这些信息程序员都知道啊,类的信息在定义类的时候不是都写的明明白白的吗。但是反射的意义却是:在程序跑起来之后可以使用代码去获取类的信息。这个,没有反射可办不到。
Java是面向对象的,所有的东西都是有类别的。所以哦,类的信息也是一种类型(就像用户信息可以用UserInfo类描述),类的信息对应的Java类为Class类,注意不是关键字class哈。
举个最常见的栗子:
public class ClassDemo {
public static void main(String[] args) {
try {
Class mysqlDriver=Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
1
2
3
4
5
6
7
8
9
这里Class.forName很明显是Class类的一个static方法,这个方法的意思就是按类名(完整的带包路径的类名)返回类对应的Class对象。因为forName的参数是可以随便写的嘛,所以会抛出一个ClassNotFoundException。
Class.forName方法是在程序运行时按类名称获取类的信息的方法,这就是反射机制。
2. 如何获取类的Class对象
我们定义一个普通类Student,可以有三种方式获取到Student的类型信息:
package temp; public class Student { String studentName; public String getStudentName(){ return studentName; } public static void main(String[] args) throws ClassNotFoundException { //方式1 利用类名称 Class class1 = Class.forName("temp.Student"); //方式2 利用类 Class class2=Student.class; //方式3 利用对象 Student student=new Student(); Class class3=student.getClass(); } }
3. 通过类的Class对象获取类的属性和方法
获取到Class(类的类型)之后,再获取属性和方法就简单了,直接使用Class类封装的方法即可。
getDeclaredFields():获取类属性
getDeclaredMethods():获取类方法
1
2
使用一个完整的程序演示如下:
package temp; import java.lang.reflect.Field; import java.lang.reflect.Method; public class Student { String studentName; public String getStudentName(){ return studentName; } public static void main(String[] args) throws ClassNotFoundException { Class classStu=Student.class; Field[] fields = classStu.getDeclaredFields(); for(Field field:fields){ System.out.println("属性类型:"+field.getType().getSimpleName()+",属性名称:"+field.getName()); } Method[] methods=classStu.getDeclaredMethods(); for(Method method:methods){ System.out.println("方法名称:"+method.getName()+",返回类型"+method.getReturnType()); } } }
执行结果如下:
属性类型:String,属性名称:studentName
方法名称:main,返回类型void
方法名称:getStudentName,返回类型class java.lang.String
1
2
3
可见,通过Class类封装的方法,可以在程序运行时候直接获取类的信息。
4. 反射的意义
凡是都有正反两个方面,先说不好的消息吧,用了反射,性能肯定是会降低的。注意此处的性能低,并不是说通过反射获取类的信息性能低,因为除了反射也没有啥可以获取类的信息的机制了。
性能低是指通过反射调用方法性能低,看下面的例子,通过反射获取到方法之后,可以将该方法应用到一个对象上实现该对象的方法调用。本来可以直接调用,反射之后再调用肯定效率要低的。
Class classStu=Student.class;
Student student=new Student();
Method methodGet=classStu.getDeclaredMethod("getStudentName");
//可以通过Method类的invoke方法调用类方法,当然必须得提供对象
String name=(String)methodGet.invoke(student);
System.out.println(name);
1
2
3
4
5
6
但是反射的正面意义还是光辉的,首先提供了一种了解类的信息的手段,使程序运行编写、运行更加自由灵活,充满了更多可能性。
简单的想,在将对象转换为json时,键值对的键不就是对象的属性名称么,用反射获取对象的属性名称是多么爽快的事情啊。