Class类简介

java反射中经常用到Class类, 本文对它以及它的方法进行简单说明



Class类简介

Class类位于java.lang包中, Class类的实例表示正在运行的Java应用程序中的类和接口.
枚举算类, 注解算接口; 数组算类,它映射的Class对象被有着相同元素和大小的数组共享;
Java的原生(primitive types)类型(boolean、byte、char、short、int、long、float、double)和关键字void也代表Class对象.

Class类实现了Serializable、GenericDeclaration、Type、AnnotatedElement接口

Class类无public构造函数, Class类对象是由JVM在类加载的时候调用类加载器的defineClass方法创建的.
如下方法能够获取类名:

  • obj.getClass().getName()
  • Foo.class.getName()

判定方法

这些方法可以判断某个类是否是接口、是否是枚举、是否是注解、是否有某个注解、是否是匿名类、是否是某个类的超类(是否可强制转换为该类)等

  1. boolean isArray(): 是否是数组; int[].class.isArray()true
  2. boolean isAnnotation(): 是否是注解, 若返回true,则isInterface也为ture; Target.class.isAnnotation()true
  3. boolean isEnum(): 是否是枚举类
  4. boolean isPrimitive(): 是否是原生类型(共9个, 包装类返回false), void.class.isArray()true
  5. boolean isInterface(): 是否是接口
  6. boolean isMemberClass(): 是否是成员类, 类的定义在另一个类里面的那种
  7. boolean isAnonymousClass(): 是否是匿名类
  8. boolean isLocalClass(): 是否是本地类
  9. boolean isSynthetic(): 是否是复合类 (接口Member也有这个方法)
  10. boolean isInstance(Object obj): obj是否是该类的一个实例
  11. boolean isAssignableFrom(Class<?> cls): cls是否可以被转换成该类
  12. boolean isAnnotationPresent(Class<? extends Annotation> annotationClass): 该类上是否存在这个注解(继承自接口AnnotatedElement)

下面是几个方法的实例说明:

public class Main {
    class Test{}  // 这是传说中的成员类
    public static void main(String[] args) {
        class LocalClass{}  // 这是传说中的本地类
        Object obj = new Hello(){    // Hello是其他地方定义的一个接口, 有一个sayHello()方法, 这就是匿名类(无类名)
            public void sayHello() {
            }
        };
        System.out.println(Test.class.isMemberClass());         // true
        System.out.println(obj.getClass().isAnonymousClass());  // true
        System.out.println(LocalClass.class.isLocalClass());    // true
        System.out.println(Hello.class.isInstance(obj));        // true
        System.out.println(Bean.class.isAnnotationPresent(Target.class));        // true
    }
}
  • instanceofisInstanceisAssignableFrom的区别

instanceof运算符只被用于对象引用变量, 比如: 自身类或子类的实例 instanceof 自身类 返回true
isInstance(Object obj)instanceof运算符的动态等价, 比如: 自身类.class.isInstance(自身类或子类的实例) 返回true
isAssignableFrom(Class<?> cls)是两个类之间的关系, 比如: 自身类.class.isAssignableFrom(自身类或子类.class) 返回true

获取内容系列方法

通过Class类可以获取这个类的一些内容性质的信息, 比如属性、方法、构造方法、注解

获取属性

  1. Field[] getFields(): 获取本类或父类中所有public属性
  2. Field getField(String name): 获取本类或父类中特定名字的public属性
  3. Field[] getDeclaredFields(): 获取本类中声明的所有属性
  4. Field getDeclaredField(String name): 获取本类中声明的特定名字的属性

获取方法

  1. Method[] getMethods(): 获取本类或父类中所有public方法(包括构造器方法)
  2. Method getMethod(String name, Class<?>... parameterTypes): 获取本类或父类中特定名字和参数的public方法
  3. Method[] getDeclaredMethods(): 获取本类中声明的所有方法(包括非public但不包括继承来的)
  4. Method getDeclaredMethod(String name, Class<?>... parameterTypes): 获取本类中声明的特定名字和参数的方法(最常用)

获取构造方法

  1. Constructor<?>[] getConstructors(): 获取本类中所有public构造器
  2. Constructor<T> getConstructor(Class<?>... parameterTypes): 获取本类中特定参数的public构造器
  3. Constructor<?>[] getDeclaredConstructors(): 获取本类中所有构造器
  4. Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes): 获取本类中指定参数的构造器

获取注解

这几个方法均继承自接口AnnotatedElement

  1. Annotation[] getAnnotations(): 获取这个元素上的所有注解(包括父类上被@Inherited标记的注解)
  2. <A extends Annotation> A getAnnotation(Class<A> annotationClass): 获取这个元素上指定类型的注解, 没有返回null
  3. Annotation[] getDeclaredAnnotations(): 获取直接标注在这个元素上的注解

父类子类(接口)相关

  1. Class<? super T> getSuperclass(): 返回本类的父类(直接超类);int[].classObject, int.classnull, Object.classnull
  2. Type getGenericSuperclass(): 以Type的形式返回本类的父类, 带有范型信息(没有范型信息时把Class以Type形式返回)
  3. Class<?>[] getInterfaces(): 返回本类直接实现的接口
  4. Type[] getGenericInterfaces(): 以Type的形式返回本类直接实现的接口, 带有范型信息
  5. <U> Class<? extends U> asSubclass(Class<U> clazz) : 把当前类转为clazz表示的子类(或自己), 不能转抛ClassCastException异常

asSubclass的作用

ArrayList.class.asSubclass(List.class)得到的还是ArrayList.class, 看起来没什么作用
但是它的作用体现在窄化未知的Class类型的范围, 比如通常我们用到Class.forName("XXX"), 它的返回是Class<?>比较宽泛, 我们可以窄化一下: Class.forName("XXX").asSubclass(List.class).newInstance(). 当XXX不是List的子类时,抛出ClassCastException异常

内部类相关

  1. Class<?> getEnclosingClass(): 获取底层类的直接封闭类, 如上面LocalClass的封闭类为Main, 那个匿名类的封闭类也是Main
  2. Constructor<?> getEnclosingConstructor(): 若该Class对象是在一个构造方法中的本地类或匿名类时, 返回这个构造器对象, 表示底层类直接封闭构造方法, 否则返回null; 上面的LocalClass不在构造方法中,因此返回null
  3. Method getEnclosingMethod(): 若该Class对象是在一个方法中的本地类或匿名类时, 返回这个Method对象, 表示底层类的直接封闭方法, 否则返回null
  4. Class<?> getDeclaringClass(): 该类是另一个类的成员(isMemberClass),则返回该类的声明类(外部类); 接口Member中也有该方法
  5. Class<?>[] getDeclaredClasses() : 返回该类中直接声明的所有类
  6. Class<?>[] getClasses() : 返回该类中直接声明的所有public类

名字相关

  1. static Class<?> forName(String className): 返回与给定的字符串名称相关联的Class对象
  2. String getSimpleName(): 返回源码中定义的简单类名, 匿名类返回空串, 数组返回”组件类型[]”
  3. String getCanonicalName: 返回底层类的Java语言规范中定义的标准名称
  4. public String getName(): 返回此Class对象所表示的实体(类,接口,数组类,基本类型或void)的名字, 略复杂,规则如下:
    • 若是原始类型(class), 则返回Java语言规范中定义的标准名称
    • 若是原生类型(primitive)或void, 直接返回关键字对应的字符串
    • 若是数组, 则用”[“代表数组维度,后面跟上元素类型代码,具体如下表:
元素类型 类型代码
boolean Z
byte B
char C
double D
float F
int I
long J
short S
class or interface Lclassname;

来个例子:

public class ClassTest {
    public static void main(String[] args) throws Exception {
        Class clazz = String.class;
        System.out.println(clazz.getSimpleName());    // String
        System.out.println(clazz.getCanonicalName()); // java.lang.String
        System.out.println(clazz.getName());          // java.lang.String

        clazz = int.class;
        System.out.println(clazz.getSimpleName());    // int
        System.out.println(clazz.getCanonicalName()); // int
        System.out.println(clazz.getName());          // int

        String[] strings = {"a", "b"};
        clazz = strings.getClass();
        System.out.println(clazz.getSimpleName());    // String[]
        System.out.println(clazz.getCanonicalName()); // java.lang.String[]
        System.out.println(clazz.getName());          // [Ljava.lang.String;

        int[][] array = {new int[]{1, 2}, new int[]{10, 20}};
        clazz = array.getClass();
        System.out.println(clazz.getSimpleName());    // int[][]
        System.out.println(clazz.getCanonicalName()); // int[][]
        System.out.println(clazz.getName());          // [[I
    }
}

其他方法

  1. TypeVariable<Class<T>>[] getTypeParameters(): 继承自接口GenericDeclaration,按照声明顺序返回声明的类型变量
  2. Class<?> getComponentType(): 若该类是个数组,则返回组件的类型

还有一些方法暂不介绍了.