jdk源码之Class
一、类图
二、是什么
- Class对象的由来是将.class文件读入内存,并为之创建一个Class对象。
- Class类的实例表示正在运行的java应用程序中的类和接口。枚举是一种类,注解是一种接口。每个数组被映射为Class对象的一个类,所有具有相同元素类型和维数的数组都共享该Class对象。基本的java类型和关键字void也表示为Class对象。
Class 类没有公共的构造方法。Class对象是在加载类时由java虚拟机调用类加载器中的defineClass方法自动构造的。 - 在运行期间,一个类,只有一个Class对象产生。
三、构造方法
private Class(ClassLoader loader) {
// Initialize final field for classLoader. The initialization value of non-null
// prevents future JIT optimizations from assuming this final field is null.
classLoader = loader;
}
只有一个构造方法,私有的。仅Java虚拟机创建Class对象。
四、获取实例
三种方式
1.运用.class和.TYPE
// 普通类获取Class的实例。接口,枚举,注解,都可以通过这样的方式进行获得Class实例
Class<Stuent> mainClass = Stuent.class;
// 基本类型和封装类型获得Class实例的方式,两者等效的。
Class<Integer> integerClass = int.class;
Class<Integer> integerClass1 = Integer.class;
Class<Integer> integerClass2 = Integer.TYPE;
- 对象.getClass()
这是利用了Object提供的一个方法getClass() 来获取当着实例的Class对象。 - 使用Class类的静态方法forName()
// 由于方法区 Class 类型信息由类加载器和类全限定名唯一确定,所以参数name必须是全限定名
//参数说明 name:class名,initialize为true表示这个类将会初始化,loader 类加载器
@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
ClassLoader loader)
throws ClassNotFoundException
{
Class<?> caller = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
// Reflective call to get caller class is only needed if a security manager
// is present. Avoid the overhead of making this call otherwise.
caller = Reflection.getCallerClass();
if (sun.misc.VM.isSystemDomainLoader(loader)) {
ClassLoader ccl = ClassLoader.getClassLoader(caller);
if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
sm.checkPermission(
SecurityConstants.GET_CLASSLOADER_PERMISSION);
}
}
}
//调用核心方法
return forName0(name, initialize, loader, caller);
}
//核心方法
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
throws ClassNotFoundException;
// 上个方法的重载,平时一般都使用这个。initialize为true。
@CallerSensitive
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
五、常用方法
1. 获得类的构造方法
-
public Constructor[] getConstructors() :获取类对象的所有可见的构造函数
-
public Constructor[] getDeclaredConstructors():获取类对象的所有的构造函数
-
public Constructor getConstructor(Class… parameterTypes): 获取指定的可见的构造函数,参数为:指定构造函数的参数类型数组(就是参数列表的Class类型),如果该构造函数不可见或不存在,会抛出 NoSuchMethodException 异常
-
public Constructor getDeclaredConstructor(Class… parameterTypes) :获取指定的构造函数,参数为:指定构造函数的参数类型数组,无论构造函数可见性如何,均可获取
注意getConstructors()只能获得被public修饰的构造方法,如果要获得被(protected,default,private)修饰的构造方法,就要使用的getDeclaredConstructors()这个方法了。
getConstructors()的源码:
public Constructor<?>[] getConstructors() throws SecurityException {
// 检查是否允许访问。如果访问被拒绝,则抛出SecurityException。
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
// privateGetDeclaredConstructors(boolean publicOnly) 方法就是返回构造方法,参数为true就是只有public的构造方法
return copyConstructors(privateGetDeclaredConstructors(true));
}
private static <U> Constructor<U>[] copyConstructors(Constructor<U>[] arg) {
// 使用克隆,得到当前类的所有构造函数
Constructor<U>[] out = arg.clone();
// 使用ReflectionFactory构造一个对象,也是不使用构造方法构造对象的一种方式。
ReflectionFactory fact = getReflectionFactory();
// 遍历,将构造函数进行拷贝返回。
for (int i = 0; i < out.length; i++) {
out[i] = fact.copyConstructor(out[i]);
}
return out;
}
2. 获得类的属性
- public Field[] getFields():获取所有可见的字段信息,Field数组为类中声明的每一个字段保存一个Field 实例
- public Field[] getDeclaredFields():获取所有的字段信息,但不包括继承的字段
- public Field getField(String name) :通过字段名称获取字段信息,该字段必须可见,否则抛出异常
- public Field getDeclaredField(String name) :通过字段名称获取字段信息,但不包括继承的字段
getConstructors()的源码:
public Field[] getFields() throws SecurityException {
// 检查是否允许访问。如果访问被拒绝,则抛出SecurityException。
checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
return copyFields(privateGetPublicFields(null));
}
private static Field[] copyFields(Field[] arg) {
// 声明一个Filed的数组,用来存储
Field[] out = new Field[arg.length];
ReflectionFactory fact = getReflectionFactory();
for (int i = 0; i < arg.length; i++) {
out[i] = fact.copyField(arg[i]);
}
return out;
}
3. 获得类的一般方法
-
public Method[] getMethods(): 获取所有可见的方法
-
public Method[] getDeclaredMethods() :获取所有的方法,无论是否可见,但不包括继承的方法
-
public Method getMethod(String name, Class… parameterTypes) :根据方法名和参数获取可见的方法
-
public Method getDeclaredMethod(String name, Class… parameterTypes):根据方法名和参数获取方法,无论是否可见
4. 获得注解
- Class.getAnnotations() 获取所有的注解,包括自己声明的以及继承的
- Class.getAnnotation(Class< A > annotationClass) 获取指定的注解,该注解可以是自己声明的,也可以是继承的
- Class.getDeclaredAnnotations() 获取自己声明的注解
- 注解只有标注了@Inherited才能被子类继承
- 当某个类没有标注任何注解时,getAnnotations()和getDeclaredAnnotations()返回空数组
- 当某个注解查询不到时,getAnnotation(Class< A > annotationType)方法返回null
- 子类重写的方法,注解无法被继承,针对方法而言,getAnnotations()与getDeclaredAnnotations()返回的结果似乎永远都是一样的。
5. 判断类的类型的方法
返回值类型 | 方法名 | 备注 |
---|---|---|
boolean | isAnnotation() | 判断是不是注解 |
boolean | isArray() | 判断是否为数组 |
boolean | isEnum() | 判断是否为枚举类型 |
boolean | isInterface() | 是否为接口类型 |
boolean | isMemberClass() | 当且仅当基础类是成员类时,返回“true” |
boolean | isPrimitive() | 确定指定的“类”对象是否表示原始类型。 |
boolean | isSynthetic() | 如果这个类是合成类,则返回’ true ';否则返回“false”。 |
六、其他
注:java中instanceof和getClass的区别分析
class A { }
class B extends A { }
Object o1 = new A();
Object o2 = new B();
o1 instanceof A => true
o1 instanceof B => false
o2 instanceof A => true // 注意1
o2 instanceof B => true
o1.getClass().equals(A.class) => true
o1.getClass().equals(B.class) => false
o2.getClass().equals(A.class) => false // 注意2
o2.getClass().equals(B.class) => true
instanceof 是子类的实例也会返回true,而getClass不会。