什么是java反射机制?
当程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言。我们认为java并不是动态语言,但是它却有一个非常突出的动态相关机制,俗称:反射。
一、Class类
什么是Class类?
在面向对象的世界里,万事万物皆是对象。而在java语言中,static修饰的东西不是对象,但是它属于类。
普通的数据类型不是对象,例如:int a = 5;它不是面向对象,但是它有其包装类 Integer 或者封装类来弥补了它。除了以上两种不是面向对象,其余的封装类也有它的面向对象,所有类都是java.lang.Class类的实例化对象(注意Class是大写)。也就是说:
Class A{}
当我创建了A类,那么类A本身就是一个对象,谁的对象?java.lang.Class的实例对象。
二、获取Class类
在应用反射机制之前,首先我们先来看一下如何获取一个对象对应的反射类Class,在Java中我们有三种方法可以获取一个对象的反射类。
通过getClass方法
在Java中,每一个Object都有一个getClass()方法,通过getClass方法我们可以获取到这个对象对应的反射类:
ListTest listTest = new ListTest();
Class<?> clazz = listTest.getClass();
System.out.println(clazz.getName());
通过forName方法
我们也可以调用Class类的静态方法forName():
Class<?> clas = Class.forName("com.github.chengbin.auth.ListTest");
System.out.println(clas.getName());
使用T.class
或者我们也可以直接使用.class:
Class<?> c = People.class;
三、实例化Class类
获取到Class类之后,调用newInstance()可以实例化该类,获取该类的一个实例:
ListTest listTest = new ListTest();
Class<?> clazz = listTest.getClass();
System.out.println(clazz.getName());
ListTest listTest1 = (ListTest)clazz.newInstance();
四、Class类信息
class类里面有很多方法,通过这些方法可以获取类的详细信息,包括类名称、修饰符、父类、类加载器、类方法、类变量等;
try {
Class clas = Class.forName("com.github.chengbin.auth.ListTest");
System.out.println("name:" +clas.getName() + ",simpleName:" + clas.getSimpleName()
+ ",superClass:" +clas.getSuperclass() +",modifiers:" + clas.getModifiers() +
",classLoader:" + clas.getClassLoader());
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
打印:
name:com.github.chengbin.auth.ListTest
simpleName:ListTest
superClass:class java.lang.Object
modifiers:1
classLoader:sun.misc.Launcher$AppClassLoader@190d0630
public String getName() 方法:获取类的全路径类(包括包名),返回的是String类型
public String getSimpleName()方法:获取类的名称
Class<? super T> getSuperclass()方法:获取父类,返回的是Class类型
public ClassLoader getClassLoader():返回类的类加载器
public Field[] getDeclaredFields():返回该类申明的变量
public Method[] getDeclaredMethods():返回该类申明的方法,不包括从Object类继承过来的方法,如:toString、HashCode()、wait()等;
public Method[] getMethods():返回该类的所有的方法;
public Annotation[] getAnnotations():返回该类的所有注解
public native Class<?>[] getInterfaces():返回该类所实现的所有接口
public Constructor<?>[] getDeclaredConstructors():返回该类的构造器
public native int getModifiers()方法:返回类修饰符,该修饰符是java.lang.reflect.Modifier的静态属性。
对应表如下:
PUBLIC: 1
PRIVATE: 2
PROTECTED: 4
STATIC: 8
FINAL: 16
SYNCHRONIZED: 32
VOLATILE: 64
TRANSIENT: 128
NATIVE: 256
INTERFACE: 512
ABSTRACT: 1024
STRICT: 2048
五、Method信息
class通过getMethods()可以获取该类的所有方法,返回的是Method[]method数组:
Class<?> clas = Class.forName(“com.github.chengbin.auth.ListTest”);
Mehtod类里面有很多好用的方法,可以获取的类的方法的具体信息。
getName() 方法:获取方法名称
getModifiers()方法:获取方法的修饰符类型
public Class<?> getReturnType():获取方法的返回值类型
public Class<?>[] getExceptionTypes():获取方法抛出的异常的类型
public Class<?>[] getParameterTypes():获取方法的参数类型
public Annotation[] getAnnotations():获取方法的所有注解类型
举个栗子:
for (Method method : clas.getMethods()) {
System.out.println("name:" +method.getName() + "\nmodifiers:" + method.getModifiers()
+ "\nreturnType:" +method.getReturnType() +"\nexceptionTypes:" + method.getExceptionTypes() +
"\nparameterTypes:" + method.getParameterTypes() + "\nannotations:" + method.getAnnotations());
RateLimiter rateLimiter = method.getAnnotation(RateLimiter.class);
if(rateLimiter != null){
System.out.println("注解RateLimiter");
}
}
打印:
name:getInstance
modifiers:9
returnType:class java.lang.Object
exceptionTypes:[Ljava.lang.Class;@11dea651
parameterTypes:[Ljava.lang.Class;@30791901
annotations:[Ljava.lang.annotation.Annotation;@363f983f
注解RateLimiter
六、Field
class通过getDeclaredFields()可以获取该类申明的变量,返回的是Field[]Field数组:
Class<?> clas = Class.forName("com.github.chengbin.auth.ListTest");
Field[] fields = clas.getDeclaredFields();
Field类里面有很多好用的方法,可以获取的类的变量或者方法参数的具体信息。
for (Field field : fields) {
System.out.println("申明的变量:"+field.getName());
System.out.println("name:" +field.getName() + "\ntype:" + field.getType()
+ "\ncount:" +field.getInt("count") +"\nmodifiers:" + field.getModifiers());
}
getName():变量的名称
getModifiers():变量的修饰符
public Annotation[] getAnnotations():返回变量的注解
public Class<?> getType():变量的类型
反射虽然很强大,但是大量的使用反射会影响程序的性能,所以合理利用反射非常重要!