java源码分析-反射Class类
1.Class类是什么
Class本质上也是java的一个类,这个类是对java所有的类的相关信息进行提取和抽象。简单说,Class类就表示创建类的类型信息。Class类的对象能够在允许时提供某个类对象的类型信息,包含了对构造函数、方法、变量等一系列操作。
public final class Class<T> implements java.io.Serializable,
GenericDeclaration,
Type,
AnnotatedElement
2.如何得到Class对象
获取一个类的Class对象有三种方式。
2.1getClass()方法
通过对象实例的getClass()方法,可以获取到Class对象。
public final native Class<?> getClass();
这是Object类中的一个native本地方法。
ClassDemo classDemo = new ClassDemo();
Class clazz = classDemo.getClass();
System.out.println(clazz);
2.2class属性
通过类的class属性可以获取到Class对象。
Class clazz1 = ClassDemo.class;
System.out.println(clazz1);
2.3通过Class的forName()方法
public static Class<?> forName(String className)
throws ClassNotFoundException
Class clazz2 = Class.forName("test.java.lang.reflect.ClassDemo");
System.out.println(clazz2);
3.Class常用方法
3.1获取构造函数对象
(1)getDeclaredConstructors()
获取某个类所有的构造函数,包括私有构造函数和公共构造函数。
public Constructor<?>[] getDeclaredConstructors() throws SecurityException
(2)getConstructors()
获取某个类的公共构造函数。
public Constructor<?>[] getConstructors() throws SecurityExceptionp
(3)getConstructor(…)
根据参数列表类型获取某个类的指定构造函数。
public Constructor<T> getConstructor(Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
测试:
定义一个ClassDemo类:
public class ClassDemo extends ClassDemoPareson implements IClassDemo {
public ClassDemo() {
}
public static final Integer MIN = 0;
public String age;
private String name;
public ClassDemo(String name){
this.name = name;
}
public String getName() {
return name;
}
@Override
public int getNum() {
return 0;
}
public void setName(String name) {
this.name = name;
}
private String test(String arg){
return null;
}
}
测试类:
package test.java.lang.reflect;
import java.lang.reflect.Constructor;
import java.util.Arrays;
public class ClassTest {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
// ClassDemo classDemo = new ClassDemo();
// Class clazz = classDemo.getClass();
// System.out.println(clazz);
// Class clazz1 = ClassDemo.class;
// System.out.println(clazz1);
// Class clazz2 = Class.forName("test.java.lang.reflect.ClassDemo");
// System.out.println(clazz2);
ClassDemo classDemo = new ClassDemo();
Class clazz = classDemo.getClass();
Constructor[] declaredConstructors = clazz.getDeclaredConstructors();
System.out.println(Arrays.toString(declaredConstructors));
Constructor[] constructors = clazz.getConstructors();
System.out.println(Arrays.toString(constructors));
Constructor constructor = clazz.getConstructor(String.class);
System.out.println(constructor);
}
}
结果:
3.2获取成员方法对象
(1)getDeclaredMethods()
获取某个类定义的所有方法对象,包括私有方法、公共方法和静态方法。
public Method[] getDeclaredMethods() throws SecurityException
(2)getMethods()
获取所有的公共方法对象。
public Method[] getMethods() throws SecurityException
(3)getMethod(…)
根据方法名和参数列表获取指定的方法Method对象。
public Method getMethod(String name, Class<?>... parameterTypes)
throws NoSuchMethodException, SecurityException
测试:
Method[] declaredMethods = clazz.getDeclaredMethods();
System.out.println(Arrays.toString(declaredMethods));
Method[] methods = clazz.getMethods();
System.out.println(Arrays.toString(methods));
Method setNameMethod = clazz.getMethod("setName", String.class);
System.out.println(setNameMethod);
结果:
3.3获取成员变量对象
(1)getDeclaredFields()
获取所有的成员变量Field对象,包括私有的、公共的和静态的。
public Field[] getDeclaredFields() throws SecurityException
(2)getFields()
获取公共的成员变量对象
public Field[] getFields() throws SecurityException
(3)getDeclaredField(…)
根据变量名称获取变量对象。
public Field getDeclaredField(String name)
throws NoSuchFieldException, SecurityException
测试:
Field[] declaredFields = clazz.getDeclaredFields();
System.out.println(Arrays.toString(declaredFields));
Field[] fields = clazz.getFields();
System.out.println(Arrays.toString(fields));
Field name = clazz.getDeclaredField("name");
System.out.println(name);
结果:
3.4其他方法
(1)getModifiers()
获取某个类的语言修饰符的整数值。
java语言描述符包括:
-
可访问描述符:
private、public、protected、默认
-
不可访问描述符
static、final、abstract、synchronized、volatile…
每一个描述符都对应着一个整数值。其具体的值在java.lang.reflect.Modifier类中有定义。
/**
* The {@code int} value representing the {@code public}
* modifier.
*/
public static final int PUBLIC = 0x00000001;
/**
* The {@code int} value representing the {@code private}
* modifier.
*/
public static final int PRIVATE = 0x00000002;
/**
* The {@code int} value representing the {@code protected}
* modifier.
*/
public static final int PROTECTED = 0x00000004;
/**
* The {@code int} value representing the {@code static}
* modifier.
*/
public static final int STATIC = 0x00000008;
/**
* The {@code int} value representing the {@code final}
* modifier.
*/
public static final int FINAL = 0x00000010;
/**
* The {@code int} value representing the {@code synchronized}
* modifier.
*/
public static final int SYNCHRONIZED = 0x00000020;
/**
* The {@code int} value representing the {@code volatile}
* modifier.
*/
public static final int VOLATILE = 0x00000040;
/**
* The {@code int} value representing the {@code transient}
* modifier.
*/
public static final int TRANSIENT = 0x00000080;
/**
* The {@code int} value representing the {@code native}
* modifier.
*/
public static final int NATIVE = 0x00000100;
/**
* The {@code int} value representing the {@code interface}
* modifier.
*/
public static final int INTERFACE = 0x00000200;
/**
* The {@code int} value representing the {@code abstract}
* modifier.
*/
public static final int ABSTRACT = 0x00000400;
/**
* The {@code int} value representing the {@code strictfp}
* modifier.
*/
public static final int STRICT = 0x00000800;
// Bits not (yet) exposed in the public API either because they
// have different meanings for fields and methods and there is no
// way to distinguish between the two in this class, or because
// they are not Java programming language keywords
static final int BRIDGE = 0x00000040;
static final int VARARGS = 0x00000080;
static final int SYNTHETIC = 0x00001000;
static final int ANNOTATION = 0x00002000;
static final int ENUM = 0x00004000;
static final int MANDATED = 0x00008000;
class.getModifiers()方法就是获取这个整数值。它是一个本地方法。
public native int getModifiers();
(2)isInterface()
判断这个类是否是接口。
public native boolean isInterface();
(3)getName()
获取类的全路径名。
public String getName()
(4)getSuperclass()
获取该类的父类类型Class。
public native Class<? super T> getSuperclass();
测试:
int modifiers = clazz.getModifiers();
System.out.println(modifiers);
boolean anInterface = clazz.isInterface();
System.out.println(anInterface);
String clazzName = clazz.getName();
System.out.println(clazzName);
Class clazzSuperclass = clazz.getSuperclass();
System.out.println(clazzSuperclass);
结果:
还有很多其他的方法,这里就不一一举例了。
4.重点解析
下面我们针对以下几个方法重点看一下源码。
4.1getConstructors()方法
前面说过getConstructors()是获取类的公共构造函数对象Constructor。
public Constructor<?>[] getConstructors() throws SecurityException { //获取公共构造器public
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);//(1)
return copyConstructors(privateGetDeclaredConstructors(true));//(2)
}
getConstructors主要分为两个部分,一个是校验成员权限,另一个是获取Constructor对象。
(1)校验权限
private void checkMemberAccess(int which, Class<?> caller, boolean checkProxyInterfaces) { //设置成员的访问权限
final SecurityManager s = System.getSecurityManager(); //获取安全管理器,默认是关闭的,所以这里是null
if (s != null) {
/* Default policy allows access to all {@link Member#PUBLIC} members,
* as well as access to classes that have the same class loader as the caller.
* In all other cases, it requires RuntimePermission("accessDeclaredMembers")
* permission.
*/
final ClassLoader ccl = ClassLoader.getClassLoader(caller);//获取调用类的类加载器
final ClassLoader cl = getClassLoader0();
if (which != Member.PUBLIC) { //如果不是public公共的访问标识符
if (ccl != cl) {
s.checkPermission(SecurityConstants.CHECK_MEMBER_ACCESS_PERMISSION); //设置权限
}
}
this.checkPackageAccess(ccl, checkProxyInterfaces); //设置包的访问权限
}
}
SecurityManager类:这是java安全管理器,允许应用程序实现安全策略。具体可看《java反射源码分析-SecurityManager》一片,有介绍。
简单来说这段代码就是来检查程序操作是否具有对应的权限,一般情况下默认是没有启动安全管理器的。
(2)获取Constructor对象
先看privateGetDeclaredConstructors()方法
private Constructor<T>[] privateGetDeclaredConstructors(boolean publicOnly) { //获取构造方法(有参和无参)
checkInitted();// 1
Constructor<T>[] res;
ReflectionData<T> rd = reflectionData();
if (rd != null) { //2
res = publicOnly ? rd.publicConstructors : rd.declaredConstructors;
if (res != null) return res;
}
// No cached value available; request value from VM
if (isInterface()) { //3
@SuppressWarnings("unchecked")
Constructor<T>[] temporaryRes = (Constructor<T>[]) new Constructor<?>[0];
res = temporaryRes;
} else { //4
res = getDeclaredConstructors0(publicOnly);
}
if (rd != null) { //5
if (publicOnly) {
rd.publicConstructors = res;
} else {
rd.declaredConstructors = res;
}
}
return res;
}
总结一下privateGetDeclaredConstructors()方法:
1)初始化校验,查看系统内部相关配置是否加载完成;
2)获取ReflectionData对象,该对象用于缓存constructor等相关数据;如果有缓存,则直接从缓存中获取对应的数据,并返回;
// Lazily create and cache ReflectionData
private ReflectionData<T> reflectionData() { //惰性创建和缓存反射的数据
SoftReference<ReflectionData<T>> reflectionData = this.reflectionData; //使用软引用的方式来创建ReflectionData对象 //软引用:内存不足时会回收此对象
int classRedefinedCount = this.classRedefinedCount; //设置重新定义的次数
ReflectionData<T> rd;
if (useCaches && //启用缓存
reflectionData != null && //软引用不为空
(rd = reflectionData.get()) != null && //ReflectionData对象不为空
rd.redefinedCount == classRedefinedCount) { //redefinedCount值等于classRedefinedCount
return rd;
}
// else no SoftReference or cleared SoftReference or stale ReflectionData
// -> create and replace new instance
return newReflectionData(reflectionData, classRedefinedCount);//否则新建缓存
}
3)判断Class对象所表示的类是否是接口,如果是则返回一个空的Constructor数组对象,因为接口是没有构造函数的;
4)如果不是接口,则会通过本地方法getDeclaredConstructors0来获取构造函数;
private native Constructor<T>[] getDeclaredConstructors0(boolean publicOnly);
5)将获取到的数据保存到缓存对象ReflectionData中。
获取到Constructor之后并没有直接返回给调用方,而是在通过拷贝的方式返回。具体看一下copyConstructors源码
private static <U> Constructor<U>[] copyConstructors(Constructor<U>[] arg) {//拷贝constructors
Constructor<U>[] out = arg.clone();//获取Constructor副本
ReflectionFactory fact = getReflectionFactory(); //获取获取反射工厂
for (int i = 0; i < out.length; i++) {
out[i] = fact.copyConstructor(out[i]);//通过反射工厂拷贝Constructor
}
return out;
}
可以看到,通过copyConstructors方法,将Constructors的拷贝副本返回该调用者。这样调用者对Constructor做的任何改变都不影响原本的Constructor。
4.2newInstance()方法
该方法也是Class对象的一个重要的方法,起作用就是根据class类型创建一个实例对象。
public T newInstance()
throws InstantiationException, IllegalAccessException
{
if (System.getSecurityManager() != null) { //1
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
}
// NOTE: the following code may not be strictly correct under
// the current Java memory model.
// Constructor lookup
if (cachedConstructor == null) { //2
if (this == Class.class) {
throw new IllegalAccessException(
"Can not call newInstance() on the Class for java.lang.Class"
);
}
try {
Class<?>[] empty = {};
final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
// Disable accessibility checks on the constructor
// since we have to do the security check here anyway
// (the stack depth is wrong for the Constructor's
// security check to work)
java.security.AccessController.doPrivileged(
new java.security.PrivilegedAction<Void>() {
public Void run() {
c.setAccessible(true);
return null;
}
});
cachedConstructor = c;
} catch (NoSuchMethodException e) {
throw (InstantiationException)
new InstantiationException(getName()).initCause(e);
}
}
Constructor<T> tmpConstructor = cachedConstructor;
// Security check (same as in java.lang.reflect.Constructor)
int modifiers = tmpConstructor.getModifiers();
if (!Reflection.quickCheckMemberAccess(this, modifiers)) { //3
Class<?> caller = Reflection.getCallerClass();
if (newInstanceCallerCache != caller) {
Reflection.ensureMemberAccess(caller, this, null, modifiers);
newInstanceCallerCache = caller;
}
}
// Run constructor
try {
return tmpConstructor.newInstance((Object[])null); //4
} catch (InvocationTargetException e) {
Unsafe.getUnsafe().throwException(e.getTargetException());
// Not reached
return null;
}
}
我们将newInstance方法分为四个部分,主要的工作如下:
(1)根据SecurityManager判断校验权限;
(2)获取cachedConstructor缓存对象,调用getConstructor0方法获取构造函数,并放入缓存中,方便下一次直接获取;
(3)设置成员访问权限;
(4)调用构造函数Constructor对象的newInstance方法获取实例对象。
public T newInstance(Object ... initargs)
throws InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException
{ //通过参数列表,构造该构造器对应的类的实例对象
if (!override) {//该标识表示是否覆盖语言级别的访问检查权限,初始false,可以通过通过constructor1.setAccessible(true)设置为true
if (!Reflection.quickCheckMemberAccess(clazz, modifiers)) {
Class<?> caller = Reflection.getCallerClass(); //获取调用类
checkAccess(caller, clazz, null, modifiers);//校验权限
}
}
if ((clazz.getModifiers() & Modifier.ENUM) != 0) //修饰符是否为枚举类型
throw new IllegalArgumentException("Cannot reflectively create enum objects");
ConstructorAccessor ca = constructorAccessor; // read volatile
if (ca == null) {
ca = acquireConstructorAccessor(); //获取构造器的访问器
}
@SuppressWarnings("unchecked")
T inst = (T) ca.newInstance(initargs);//通过构造函数声明类的newInstance来实例化对象
return inst;
}
至于ConstructorAccessor.newInstance()方法我们在《java反射源码分析-Constructor》中已经详细说明,这里就不再说了。
5.相关类
5.1ReflectionFactory
通过类名我们就可以大致知道,这是一个工厂,用于反射的工厂类。通常的工厂都是用于实例化具体产品,担任着类的对象的创建工作,但是ReflectionFactory却有点不同,它是通过深度克隆的方式来创建发射的核心对象Field、Constructor和Method。并不是创建,而是复制一份。我们看一下他的三个克隆方法:
那NewField()方法来看一下:
public Field newField(Class<?> var1, String var2, Class<?> var3, int var4, int var5, String var6, byte[] var7) {
return langReflectAccess().newField(var1, var2, var3, var4, var5, var6, var7); //通过LangReflectAccess调用newField方法
}
private static LangReflectAccess langReflectAccess() { //获取LangReflectAccess
if (langReflectAccess == null) {
Modifier.isPublic(1); //设置访问权限public
}
return langReflectAccess;
}
调用ReflectAccess类来进行实例化Field。
public Field newField(Class<?> declaringClass,
String name,
Class<?> type,
int modifiers,
int slot,
String signature,
byte[] annotations)
{
return new Field(declaringClass,
name,
type,
modifiers,
slot,
signature,
annotations);
}
也就是说通过反射工厂创建Field、Constructor和Method底层都是通过new的形式创建一个新的对应类型的实例。
5.2Reflection
Reflection类类似于一个工具类,提供了一些本地方法和用来校验相关成员权限的方法。
例如:
本地方法
@CallerSensitive
public static native Class<?> getCallerClass();//获取调用类的Class类型
校验成员权限
public static void ensureMemberAccess(Class<?> var0, Class<?> var1, Object var2, int var3) throws IllegalAccessException {
if (var0 != null && var1 != null) {
if (!verifyMemberAccess(var0, var1, var2, var3)) {
throw new IllegalAccessException("Class " + var0.getName() + " can not access a member of class " + var1.getName() + " with modifiers \"" + Modifier.toString(var3) + "\"");
}
} else {
throw new InternalError();
}
}
6.小结
本章主要是对java反射机制中的核心类Class进行类分析,下面总结几点:
(1)想要通过反射对某个类或对象进行操作,首先需要获取这个类的Class对象;
(2)获取Class对象的方式有三种,分别是对象的getClass()方法,class属性和通过Class.forName()方法获取;
(3)得到了Class对象之后就可以获取到这个类所有信息了,并进行后续操作;