Class类是反射与加载器最常用的核心类,最近计划写一个JAVA加载器框架,决定重新温习相关接口和类的源码文档,实践相关用法以消除心中所存不确定。
- 目录结构
- 类说明
- 对象创建
- UML类图
- 类成员方法
- 学习总结
1 类说明
翻译Class类源码英文文档,分段翻译并配合理解和例子加深印象。
英文:Instances of the class {@code Class} represent classes and interfaces in a running Java application.
中文:在一个运行中的JAVA程序,Class类的实例,代表用关键字class或interface声明的对象,如public class AnyObject
与public interface AnyInterface
。
英文:An enum is a kind of class and an annotation is a kind of interface.
中文:Enum-枚举是一种Class类型,Annotation-注解是一种接口类型。
英文:Every array also belongs to a class that is reflected as a {@code Class} object that is shared by all arrays with the same element type and number of dimensions.
中文:每一个数组属于一个类,按照数组元素类型和维度被反射为一个类对象,这个类对象被具有相同元素类型和维度的数组共享。
应用理解
序号 | 变量声明 | 变量声明 | 是否相同 | 差异因素 |
---|---|---|---|---|
1 | String[] o1 = new String[3] | String[] o2 = new String[10] | 相同 | 无 |
2 | String[] o1 = new String[3] | String[][] o3 = new String[3][5] | 不同 | 数组维度 |
3 | String[] o1 = new String[3] | byte[] o4 = new byte[1024] | 不同 | 元素类型 |
英文:The primitive Java types ({@code boolean}, {@code byte}, {@code char}, {@code short},{@code int}, {@code long}, {@code float}, and {@code double}), and the keyword {@code void} are also represented as {@code Class} objects.
中文:JAVA原始类型boolean / byte / char / short / int / long / float / double 与void关键字,也都有一种类对象代表。
原始类型与类对象对应表
序号 | 原始类型 | 对象类型 | 类型缩写 |
---|---|---|---|
1 | boolean | java.lang.Boolean | Z |
2 | byte | java.lang.Byte | B |
3 | char | java.lang.Character | C |
4 | short | java.lang.Short | S |
5 | int | java.lang.Integer | I |
6 | long | java.lang.Long | J |
7 | float | java.lang.Float | F |
8 | double | java.lang.Double | D |
9 | void | java.lang.Void | V |
注意:原始类型与对象类型的Class不一样,类型缩写在.class文件中用到。另外,class或interface的类型缩写为L。
2 对象创建
英文:{@code Class} has no public constructor. Instead {@code Class} objects are constructed automatically by the Java Virtual Machine as classes are loaded and by calls to the {@code defineClass} method in the class loader.
中文:Class没有公有构造器函数,虚拟机装载类对象或被调用ClassLoader的defineClass方法时,Class对象实例被JAVA虚拟机自动构造。
Class对象实例的获取方式
- 对象实例调用getClass方法
Thread thobj = new Thread();
Class clazz = thobj.getClass();
System.out.println(clazz.getName());
对任何对象类型的实例,调用getClass()函数可以获取对象类型。
- 类字面量.class方式
Class clazz = String.class;
System.out.println(clazz.getName());
类字面量,就是指用class关键字声明的对象名称,如public class Foo {}
,Foo
就是这个类的类字面量。
- 静态函数forName
Class<?> clazz = Class.forName("java.lang.ArrayList");
请求参数为对象类型的全限定名称,一般情况,不需要额外制定类加载器。
- 泛型类型的获取方式
Class<String> clazz = String.class
System.out.println(clazz.getName());
3 UML类图
- Class类声明
public final class Class<T> implements java.io.Serializable, GenericDeclaration, Type, AnnotatedElement {
//主体代码
}
声明分析
1 final关键字,Class类不能被继承;
2 实现AnnotatedElement接口,支持注解功能;
3 支持泛型,Class<T>声明,实现GenericDeclaration,支持获取泛型参数方法getTypeParameter;
4 实现Serializable接口,支持序列化。
-
Class类图
整理Class类实现的接口,依赖的类与接口。
4 类成员方法
4.1 构造函数
函数声明:private Class(ClassLoader loader)
- 使用说明
不能直接用new生成Class实例,也不提默认构造函数,直接由JVM在类装载或ClassLoader调用defineClass是调用。
4.2 成员方法
4.2.1 forName方法
- 方法作用
静态方法forName
通过类的全限定名称加载类对象,常用于反射功能模块。两个函数的区别主要区别在于第二个函数制定了一个类加载器,函数实现时增加对加载器的安全权限检查。 - 方法声明
public static Class<?> forName(String name) throws ClassNotFoundException
public static Class<?> forName(String name, bool isInit, ClassLoader loader) throws ClassNotFoundException
方法抛出异常还有LinkageError与ExceptionInInitializerError。
forName
底层调用静态本地方法forName0
函数:
private static native Class<?> forName0(String name, boolean isInit, ClassLoader loader, Caller<?> caller) throws ClassNotFoundException;
4.2.2 newInstance方法
- 方法作用
调用默认构造函数生成对象实例。 - 方法声明
@CallerSensitive
public T newInstance() throws InstantiationException, IllegalAccessException
- 函数分析
注解@CallerSensitive,表明函数执行是否成功与调用者权限有关,Class类代码首先调用系统安全管理器检查调用者对本类是否有访问权限;
方法无参数,就是说,只能生成具有默认无参构造函数的类实例;若需要调用含参数列表的构造函数,需要通过反射技术调用Constructor类的newInstance方法;
4.2.3 isInstance方法
- 方法作用
判断本类型是否继承或实现参数制定的类或接口。 - 方法声明
public native boolean isInstance(Object obj);
返回值说明
序号 | this类型 | obj说明 | 返回值 |
---|---|---|---|
1 | class | obj是该类对象实例或子类型实例 | true |
2 | array | obj能执行类型转换为array对象 | true |
3 | interface | obj的类或上级类实现此接口 | true |
4 | 原始类型 | 任何情况 | false |
4.2.4 isAssignedFrom方法
- 方法作用
判断本类型是否为参数clazz的相同,或者是其子类或实现类。 - 方法声明
public native boolean isAssignedFrom(Class<?> clazz);
注意:与isInstance方法不同,这个参数是Class类型,而isInstance的参数是对象实例。
4.2.5 常用判断方法
public native boolean isInterface(); #判断是否为接口对象
public native boolean isArray(); #判断是否为数组对象
public native boolean isPrimitive(); #判断是否为原始类型,如byte, int等
public boolean isAnnotation(); #判断是否为注解类型
public boolean isSynthetic(); #判断是否为合成类,不是手动编写的静态类
public boolean isAnonymousClass(); #判断是否为匿名类
public boolean isLocalClass(); #判断是否为本地类
public boolean isMemberClass(); #判断是否为成员类
public boolean isEnum(); #判断是否为枚举类型
4.2.6 字段操作方法
4.2.6.1 getField
- 方法作用
获取类声明的公有成员变量。 - 方法声明
@CallerSensitive
public Field getField(String name);
根据名称参数name
获取类的同名字段,没有名称对应的字段将抛出NoSuchFieldException。
4.2.6.2 getFields
- 方法作用
获取类声明的所有公有成员变量,返回Field数组,没有成员变量返回空数组。 - 方法声明
@CallerSensitive
public Field[] getFields() throws SecurityException;
4.2.6.3 getDeclaredField方法
- 方法作用
获取类声明的同名成员变量,不管是公有还是私有,没有此名称成员变量抛出异常。 - 方法申明
public Field getDeclaredField(String name);
4.2.6.4 getDeclaredFields方法
- 方法作用
获取类声明的所有成员变量,无论是公有还是私有,无成员变量返回空数组。
@CallerSensitive
public Field[] getDeclaredFields() throws SecurityException;
4.2.7 构造器方法
4.2.7.1 getConstrucutor
- 方法作用
获取与参数列表类型匹配的公有构造函数。 - 方法申明
@CallerSensitive
public Constructor<T> getConstructor(Class<?>... paramTypes) throws NoSuchMethodException, SecurityException
4.2.7.2 getDeclaredConstructor
- 方法作用
获取与参数列表类型匹配的构造函数,不论公有私有。 - 方法声明
@CallerSensitive
public Constructor<T> getDeclaredConstructor(Class<?>... paramTypes) throws NoSuchMethodException, SecurityException
4.2.7.3 getConstructors
- 方法作用
获取类声明的所有公有构造函数,返回Constructor数组。 - 方法声明
@CallerSensitive
public Constructor[] getConstructors() throws SecurityException;
4.2.7.4 getDeclaredConstructors
- 方法作用
获取类声明的所有构造函数,不论公有私有,返回Constructor数组。 - 方法声明
@CallerSensitive
public Constructor[] getDeclaredConstructors() throws SecurityException;
4.2.8 成员方法函数
4.2.8.1 getMethod
- 方法作用
获取与参数列表类型匹配的公有方法。 - 方法申明
@CallerSensitive
public Method getMethod(Class<?>... paramTypes) throws NoSuchMethodException, SecurityException
4.2.8.2 getDeclaredMethod
- 方法作用
获取与参数列表类型匹配的方法,不论公有私有。 - 方法声明
@CallerSensitive
public Method getDeclaredMethod(Class<?>... paramTypes) throws NoSuchMethodException, SecurityException
4.2.8.3 getMethods
- 方法作用
获取类声明的所有公有方法,返回Method数组。 - 方法声明
@CallerSensitive
public Method[] getMethods() throws SecurityException;
4.2.8.4 getDeclaredMethods
- 方法作用
获取类声明的所有方法,不论公有私有,返回Method数组。 - 方法声明
@CallerSensitive
public Method[] getDeclaredMethods() throws SecurityException;
4.2.9 getModifiers方法
- 方法作用
获取类声明的访问修饰符,如public, protected, final等。 - 方法声明
public native int getModifiers();
4.2.10 getInterfaces方法
- 方法作用
获取类实现的接口列表数组,返回Class<?>数组, 没有实现接口返回空数组。 - 方法声明
public Class<?>[] getInterfaces();
4.2.11 getClasses方法
- 方法作用
获取类继承或实现接口的数组,返回Class<?>数组, 没有集成与实现接口返回空数组。 - 方法声明
public Class<?> getClasses();
注意:getClasses方法包含getInterfaces方法返回的接口数组,排序与源代码声明顺序一致。
4.2.12 getSuperclass方法
- 方法作用
获取类的父类型,Class代表的类型可以是class / interface / 原始类型 / void。 - 方法声明
public native Class<? super T> getSuperclass();
- 返回值说明
如果this是原始类型,父类型返回null;如果this代表一个数组,父类型返回java.lang.Object。
4.2.13 getPackage方法
- 方法作用
返回类所在的包对象。 - 方法声明
public Package getPackage();
4.2.14 getComponentType方法
- 方法作用
获取数组元素类型,如果this不是数组类型,返回null。 - 方法声明
public native Class<?> getComponentType()
- 应用示例
数组String[],函数返回数组元素类型java.lang.String。
4.2.15 getName方法
- 方法作用
获取this对象的全限定名称。 - 方法声明
public String getName();
- 应用示例
- 对象类型,如String.class.getName(),返回名称为java.lang.String;
- 原始类型,如byte.class.getName(),返回名称与原始类型一样,这里返回"byte";
- 数组类型,分两种情况:1)原始类型数组,返回“前缀[ + 类型缩写",如byte[5],返回字符串”[B“;2)对象数组,返回前缀[ + 类型全限定名称”,如String[5], 返回[Ljava.lang.String;
- 多维数组,与数组类型格式一致,数组有几维、就有几个前缀[,如long[2][3][4][5],返回字符串“[[[[J”;
4.2.16 注解操作方法
Spring / MyBatis就是调用Class类的注解操作方法,解析BEAN对象等的注解配置的,研究框架得多了解下这几个函数。
4.2.16.1 getAnnotation方法
- 方法作用
根据注解的类型获取类声明的注解对象。 - 方法声明
public <A extends Annotation> A getAnnotation(Class<A> annotationType);
- 使用示例
@RestController("/message")
class MessageController {
@RequestMapping(value="annotation")
public String getAnnotation(){
RestController obj =(RestController)this.getClass().getAnnotation(RestController.class);
System.out.println(obj.value());
return obj.value();
}
}
4.2.16.2 getAnnotations方法
- 方法作用
获取类声明的所有注解对象,返回Annotation数组,没有注解返回空数组。 - 方法声明
public Annotation[] getAnnotations();
4.2.16.3 isAnnotationPresent方法
- 方法作用
返回类是否声明annotationType参数指定的注解。 - 方法声明
public boolean isAnnotationPresent(Annotation<? extends Annotation> annotationType) ;
- 方法示例
@Deprecated
public class App{
public static void main(String[] args){
/* 判断App类是否被Deprecated注解标识成Deprecated */
boolean isOld = App.class.isAnnotationPresent(Deprecated.class);
}
}
4.2.16.4 getAnnotationsByType方法
- 方法作用
根据注解类型annotationType获取类声明的所有注解,返回Annotion[]。 - 方法声明
public <A extends Annotation> A[] getAnnotationsByType(Class<A extends Annotation> annotationType)
4.3 其它函数
Class类的方法还有不少,尤其是要研究几个内部类的作用,如EnclosingMethodInfo、ReflectionData等,了解其缓存优化等特点。
5 学习总结
Class类是反射技术的核心类
掌握forName方法使用,熟练使用构造函数、成员变量、成员变量获取函数
了解getSuperclass、getClasses与getInterfaces方法使用,动态代理过程常用
熟悉注解对象操作函数,框架对象属性配置经常用到