Class类的作用
Class类是一个特殊类,它用于表示JVM运行时类或接口的信息。
Class类提供很多方法用于获取类的各种信息,比如获取类名、判断该类是否是一个接口还是普通类等等。
在Java中枚举类是一种类,而注解是一个接口,数组也是一个类;Java原始类型(boolean, byte, char, short, int, long, float, and double)和关键字void也被表示为Class的对象。
在每一个基本类型的包装类中都有一个共有的静态变量,例如Integer:
public static final Class TYPE = (Class) Class.getPrimitiveClass(“int”);
TYPE就是这个基本类型的Class对象表示。
Class类的父类
Class类是java中的一个类和其他非继承类一样,默认的父类也是Object。
public class ClassParentTest {
public static void main(String[] args) {
boolean assignableFrom = Object.class.isAssignableFrom(Class.class);
System.out.println(assignableFrom);
}
}
Class#isAssignableFrom(Class<?> cls)方法用于判断cls的实例能否赋值给该Class的引用;换句话说,该方法可以用来判断cls类是否是该Class的子类或者如果Class是接口表示cls是否实现了该接口。
上边那段代码将输出true,说明Class类的父类是Object类
Class类的forName方法
用于手动加载一个类,该方法是一个公共静态方法,有多个重载。
方法签名:
public static Class<?> forName(String className)
public static Class<?> forName(String name, boolean initialize,ClassLoader loader)
throws ClassNotFoundException
//下面这个是JDK9新增加的,用于从模块中加载一个类,不对类进行初始化
public static Class<?> forName(Module module, String name)
//第一个和第二个都是调用下面的native方法forName0来加载类
private static native Class<?> forName0(String name, boolean initialize,
ClassLoader loader,
Class<?> caller)
关于参数boolean initialize
注意这里的参数boolean initialize表示是否对类进行初始化,这里的初始化指的是类加载过程中收集静态代码块和静态变量形成的方法的初始化,不是指类构造函数的执行(构造函数的执行是在类生成实例的时候执行的,是对实例变量的初始化,不要搞混)。
class A{
private static final int i = 0;//#1
private static final String str = "hello";//#2
static {
System.out.println("static block!"); //#3
}
public A(){
System.out.println("constructor!");
}
}
在类加载的过程中,会将#1,#2,#3
按照顺序收集在一起形成<clinit>
方法,为了帮助理解,可以表示成下面的伪代码:
<clinit>() {
private static final int i = 0;//#1
private static final String str = "hello";//#2
System.out.println("static block!"); //#3
}
参数boolean initialize
就是来表示是否在类加载的时候执行这个<clinit>
方法!
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<A> aClass = (Class<A>) Class.forName("com.company.A",
true,Test4.class.getClassLoader());
}
上边的代码将参数initialize
设置为true
,执行会输出static block!
,说明执行了类的初始化!
如果改成false
,将不会输出static block!
,也就是不执行类的初始化,这将类的初始化延迟到第一次创建该类的实例!
String hello = "hello";
boolean isStr = String.class.isInstance(hello);
类的构造函数是类实例化时执行的。
A a = aClass.getConstructor().newInstance();
通过以上方式创建A
类的实例将输出constructor!
Class类的isInstance和isAssignableFrom方法
这两个方法都是native方法。
isInstance
public native boolean isInstance(Object obj);
isInstance
用于判断obj对象是否是该Class或该Class子类的一个实例。
String hello = "hello";
boolean isStr = String.class.isInstance(hello);
isStr
为true
。
boolean is = Number.class.isInstance(Integer.valueOf(1));
is
为true
,因为Integer
是Number
的子类。
该方法还可以用于类型转换时,为了避免对象的转换异常,进行类型检查:
public void method(Object str){
String str1;
if(String.class.isInstance(str)){
str1 = (String) str;
}
}
但是我们一般不会这样写,因为java给我提供了instanceof
。
isAssignableFrom
public native boolean isAssignableFrom(Class<?> cls);
该方法用于判断cls的实例能否赋值给该Class的引用;换句话说,该方法可以用来判断cls类是否是该Class的子类或者如果Class是接口表示cls是否实现了该接口。
boolean is = Number.class.isAssignableFrom(Integer.class);
boolean is2 = List.class.isAssignableFrom(ArrayList.class);
is和is2都是true,因为Integer继承了Number,ArrayList间接的实现了List接口。
看Spring中的一段代码(代码摘自MapMethodProcessor类,HandlerMethodArgumentResolver的实现类,用于自动注入Controller方法参数):
@Override
public boolean supportsParameter(MethodParameter parameter) {
return Map.class.isAssignableFrom(parameter.getParameterType()) &&
parameter.getParameterAnnotations().length == 0;
}
它使用isAssignableFrom
方法来判断方法参数是否是Map类型。
Class类的isXXXX
Class类还提供了isXXXX的方法,这些方法大多用于判断Class的类型。
方法名 | 方法签名 | 作用 |
---|---|---|
isInterface | public native boolean isInterface() | 判断该Class是否是一个接口 |
isArray | public native boolean isArray() | 判断该Class是否是一个数组 (数组在Java中也是类) |
isPrimitive | public native boolean isPrimitive() | 判断该Class是否是基本类型 |
isAnnotation | public boolean isAnnotation() | 判断该Class是否是一个注解,如果该方法返回true,isInterface方法也将返回true,因为注解是特殊的接口 |
isSynthetic | public boolean isSynthetic() | 当且仅当该Class是Java语言规范定义的合成类时为true。 |
isAnonymousClass | public boolean isAnonymousClass() | 当且仅当该Class是匿名类时返回true。Runnable runnable = new Runnable() { public void run() { }};boolean is = runnable.getClass().isAnonymousClass(); 为true |
isLocalClass | public boolean isLocalClass() | 当且仅当该Class是局部类时返回true。 |
isMemberClass | public boolean isMemberClass() | 当且仅当该Class是一个类的成员返回true |
isAnnotationPresent | public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) | 判断该类是否有注解annotationClass |
isEnum | public boolean isEnum() | 判断是否是枚举类 |
Class类还有其他方法,但常用的也就这些了