最近公司招了几名刚毕业的大学生,在给他们培训的过程中,讲到反射,他们有些人听不懂,对反射的概念云里雾里的,不知道反射有什么用。
因此就有了本文的诞生。
反射是java提供的一个重要功能,可以在运行时检查类、接口、方法和变量等信息,无需知道类的名字,方法名等。还可以在运行时实例化新对象,调用方法以及设置和获取变量值。
反射非常强大和有用,很多java框架中都有反射的影子,例如spring、mybatis等等,
JDBC利用反射将数据库的表字段映射到java对象的getter/setter方法。
Jackson, GSON, Boon等类库也是利用反射将JSON文件的属性映射到java对的象getter/setter方法。
可见,只要使用java,反射就无处不在。
Class对象
检查一个类之前,必须获取到java.lang.Class对象,java中的所有类型,包括long,int,数组等基本数据类型,都和Class对象有关系。
我们很多人去医院参加体检的时候,都做过B超检查,医生只需把一个探头在我们身上滑动就可以将我们体内的肝、胆、肾等器官反射到B超设备上显示。
Class类对象就相当于B超的探头,将一个类的方法、变量、接口、类名、类修饰符等信息告诉运行的程序。
Java提供了两种方式获取Class对象,一种是使用.class,另外一种是使用Class.forName()。
.class方式适用于在编译时已经知道具体的类。
Class.forName()方式适用于运行时动态获取Class对象,只需将类名作为forName方法的参数:
try{ Class alunbarClass1 = Class.forName("Alunbar"); } catch(ClassNotFoundException e){ System.out.println("找不到Alunbar类"); }这个方法会出现类找不到的情况,因此使用这个方法获取Class对象时,必须捕获ClassNotFoundException异常。
获取类名
package cn.alunbar; public class Alunbar { public static void main(String arts[]){ Class alunbarClass = Alunbar.class; System.out.println(alunbarClass.getName()); System.out.println(alunbarClass.getSimpleName()); } }上面代码运行结果如下:
cn.alunbar.Alunbar AlunbargetName()方法获取的类名包含包信息。getSimpleName()方法只是获取类名,不包含包信息。
获取类修饰符
public class Alunbar { public static void main(String arts[]){ Class alunbarClass = Alunbar.class; System.out.println(alunbarClass.getModifiers()); System.out.println(Modifier.isPublic(alunbarClass.getModifiers())); Class birdClass = Bird.class; System.out.println(birdClass.getModifiers()); System.out.println(Modifier.isPublic(birdClass.getModifiers())); } private class Bird{ } }类修饰符有public、private等类型,getModifiers()可以获取一个类的修饰符,但是返回的结果是int,结合Modifier提供的方法,就可以确认修饰符的类型。
Modifier.isAbstract(int modifiers) Modifier.isFinal(int modifiers) Modifier.isInterface(int modifiers) Modifier.isNative(int modifiers) Modifier.isPrivate(int modifiers) Modifier.isProtected(int modifiers) Modifier.isPublic(int modifiers) Modifier.isStatic(int modifiers) Modifier.isStrict(int modifiers) Modifier.isSynchronized(int modifiers) Modifier.isTransient(int modifiers) Modifier.isVolatile(int modifiers)获取包信息
package cn.alunbar; public class Alunbar { public static void main(String arts[]){ Class birdClass = Bird.class; System.out.println(birdClass.getPackage()); } private class Bird{ } }getPackage()方法获取包信息。上面代码运行的结果:
package cn.alunbar获取父类的Class对象
public class Alunbar { public static void main(String arts[]){ Class birdClass = Bird.class; Class superclass = birdClass.getSuperclass(); System.out.println(superclass.getSimpleName()); } private class Bird extends Animal{ } private class Animal{ } }上面代码运行的结果:
AnimalgetSuperclass()方法返回的父类的Class对象。
获取接口信息
获取接口信息的方法:
一个类可以实现多个接口,所以getInterfaces()方法返回的是Class[]数组。
注意:getInterfaces()只返回指定类实现的接口,不会返父类实现的接口。
获取构造函数Constructor
获取构造函数的方法:
一个类会有多个构造函数,getConstructors()返回的是Constructor[]数组,包含了所有声明的用public修饰的构造函数。
如果你已经知道了某个构造的参数,可以通过下面的方法获取到回应的构造函数对象:
public class Alunbar { public static void main(String arts[]){ Class birdClass = Bird.class; try{ Constructor constructors = birdClass.getConstructor(new Class[]{String.class}); }catch(NoSuchMethodException e){ } } private class Bird { public Bird(){ } public Bird(String eat){ } } }上面获取构造函数的方式有2点需要注意:
1、只能获取到public修饰的构造函数。
2、需要捕获NoSuchMethodException异常。