引言

Class作为类和接口(包括简单类型、数组和void)在运行时的表示,融合了不同的特性,它既是一个GenericDeclaration,又是一个Type,还是一个AnnotatedElement,同时还是反射的入口,自然而然要提供对应于这些特性的方法。这篇文章,我们对Class的方法分类进行分析,相信通过这篇文章,我们能很清楚地理解Class的关键功能。

构造方法和ClassLoader成员变量

Class类只有一个构造方法,还是私有的:

  1. /*
  2. * Private constructor. Only the Java Virtual Machine creates Class objects.
  3. * This constructor is not used and prevents the default constructor being
  4. * generated.
  5. */
  6. private Class(ClassLoader loader) {
  7. // Initialize final field for classLoader. The initialization value of non-null
  8. // prevents future JIT optimizations from assuming this final field is null.
  9. classLoader = loader;
  10. }

注释解释的很清楚,只有java虚拟机才能创建Class对象,私有构造方法是为了防止默认的构造方法被创建。也就是说,我们不能在代码中通过构造方法来创建Class对象。关于怎样创建Class对象,上一篇文章我们已经介绍的很清楚了。
还有一点需要注意,对于某个类来说,代表这个类的Class对象在虚拟机类加载过程的第一个阶段也就是加载阶段就会被创建在内存中,之后,无论什么时候以何种方式获取这个类的Class对象,都会返回加载阶段创建好的对象。看下面的例子:

  1. public class ClassInitTest {
  2. public static void main(String[] args) throws ClassNotFoundException {
  3. ClassInitTest classInitTest = new ClassInitTest();
  4. Class<?> aClass = Class.forName("person.andy.concurrency.reflect.cl.ClassInitTest");
  5. System.out.println(classInitTest.getClass() == ClassInitTest.class);
  6. System.out.println(aClass == ClassInitTest.class);
  7. }
  8. }

输出:

  1. true
  2. true

构造方法中初始化了classLoader这个成员变量,我们来看它的声明:

  1. // Initialized in JVM not by private constructor
  2. // This field is filtered from reflection access, i.e. getDeclaredField
  3. // will throw NoSuchFieldException
  4. private final ClassLoader classLoader;

注释也给出了说明,它的初始化是jvm做的而不是构造方法做的,也就是在类加载器加载一个类后,就会初始化代表这个类的Class对象的classLoader属性。为什么不是构造方法初始化的要在构造方法中声明这个参数呢?因为classLoader是final的,如果不在构造方法中有初始化的声明,就会报错。
Class提供了getClassLoader方法来让我们获取这个类的类加载器,如果一个类是被bootstrap class loader加载的,那么这个类的类加载器就是null,也就是这个方法会用null来代表bootstrap class loader。

  1. @CallerSensitive
  2. public ClassLoader getClassLoader() {
  3. ClassLoader cl = getClassLoader0();
  4. if (cl == null)
  5. return null;
  6. SecurityManager sm = System.getSecurityManager();
  7. if (sm != null) {
  8. ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
  9. }
  10. return cl;
  11. }
  12. // Package-private to allow ClassLoader access
  13. ClassLoader getClassLoader0() { return classLoader; }

不去理关于安全的逻辑,getClassLoader其实就是返回了Class的classLoader对象,看下面的例子:

  1. public class ClassInitTest {
  2. public static void main(String[] args) {
  3. System.out.println(String.class.getClassLoader());
  4. System.out.println(ClassInitTest.class.getClassLoader());
  5. }
  6. }

输出:

  1. null
  2. sun.misc.Launcher$AppClassLoader@18b4aac2

String类是rt.jar中的类,在\lib目录中,是由bootstrap class loader加载的,所以返回的是null,而我们自定义的类是由应用类加载器AppClassLoader加载的。

判断Class代表的类类型

Class代表可以是类、接口、数组和原始类型,枚举归属于类,注解归属于接口,为了判断某个Class代表的具体是什么类型,Class提供了几个方法:

  1. public native boolean isInterface();
  2. public native boolean isArray();
  3. public native boolean isPrimitive();
  4. public boolean isAnnotation() {
  5. return (getModifiers() & ANNOTATION) != 0;
  6. }
  7. public boolean isEnum() {
  8. // An enum must both directly extend java.lang.Enum and have
  9. // the ENUM bit set; classes for specialized enum constants
  10. // don't do the former.
  11. return (this.getModifiers() & ENUM) != 0 &&
  12. this.getSuperclass() == java.lang.Enum.class;
  13. }
  14. public boolean isSynthetic() {
  15. return (getModifiers() & SYNTHETIC) != 0;
  16. }

这几个方法分别用来判断一个Class代表的是一个接口、一个数组、原始类型、注解、枚举和编译器产生的,其中,接口、数组和原始类型都是native方法,而是否是注解、枚举和编译器产生的这三个是用getModifiers()方法的返回值与Class对应声明的int常量作比较来得出的:

  1. private static final int ANNOTATION= 0x00002000;
  2. private static final int ENUM = 0x00004000;
  3. private static final int SYNTHETIC = 0x00001000;

这三个值其实就是二进制类文件结构中访问标志部分中对应的值:
accessFlags.png
注意判断枚举还加了另外一个条件:这个类的父类必须是java.lang.Enum.class;
看下面的例子:

  1. public class ClassIsTest {
  2. public static void main(String[] args) {
  3. System.out.println(int.class.isPrimitive());
  4. int[] ints = new int[10];
  5. System.out.println(ints.getClass().isArray());
  6. System.out.println(Cloneable.class.isInterface());
  7. System.out.println(ElementType.class.isEnum());
  8. System.out.println(Deprecated.class.isAnnotation());
  9. }
  10. }

输出都是true,我没有找到编译器生成的类的例子。

获取父类和接口

获取父类

getSuperclass()方法可以用来获取这个Class代表的类型的父类,这是一个native方法:

  1. public native Class<? super T> getSuperclass();

当Class代表的是Object类、接口、原始类型或者void,返回值为null,如果Class代表的是一个数组,返回的是代表Object的Class。看下面的例子:

  1. public class SuperClassTest<T,E> {
  2. public static void main(String[] args) {
  3. System.out.println(int.class.getSuperclass());
  4. System.out.println(void.class.getSuperclass());
  5. System.out.println(Object.class.getSuperclass());
  6. System.out.println(Cloneable.class.getSuperclass());
  7. int[] ints = new int[10];
  8. System.out.println(ints.getClass().getSuperclass());
  9. System.out.println(SuperClassTestSub.class.getSuperclass());
  10. System.out.println(SuperClassTest.class.getSuperclass());
  11. }
  12. static class SuperClassTestSub extends SuperClassTest<String,Object>{
  13. }
  14. }

输出:

  1. null
  2. null
  3. null
  4. null
  5. class java.lang.Object
  6. class person.andy.concurrency.reflect.type.SuperClassTest
  7. class java.lang.Object

当父类是参数化类型时,我们可以使用getGenericSuperclass方法来获取带有类型参数的父类表示,上面例子中的SuperClassTest就是一个参数化类型,getSuperclass只能返回Class代表的原生类型,不带有类型参数。看下面的例子:

  1. public class SuperClassTest<T,E> {
  2. public static void main(String[] args) {
  3. Class<SuperClassTestSub> superClassTestSubClass = SuperClassTestSub.class;
  4. System.out.println(superClassTestSubClass.getGenericSuperclass().getClass());
  5. System.out.println(superClassTestSubClass.getGenericSuperclass());
  6. }
  7. static class SuperClassTestSub extends SuperClassTest<String,Object>{
  8. }
  9. }

输出:

  1. class sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
  2. person.andy.concurrency.reflect.type.SuperClassTest<java.lang.String, java.lang.Object>

可以看出调用getGenericSuperclass()方法返回的是ParameterizedType的实现类ParameterizedTypeImpl,当我们拿到了ParameterizedType之后,就能调用它的一些方法例如getActualTypeArguments()等。这些已经在介绍ParameterizedType接口时详细介绍过了,这里不再赘述。

获取继承的接口

我们可以使用getInterfaces来获取Class代表的类继承的接口,如果Class代表的类或者接口,就会按顺序返回implements或者extends后面的接口;如果Class代表的是简单类型或者void,这个方法返回的是长度为0的数组;如果Class代表的是数组,会返回两个接口:Cloneable和Serializable,这点需要注意。
看下面的例子:

  1. public class InterfaceTest implements Walkable, Flyable,Readable<SimpleObject> {
  2. public static void main(String[] args) {
  3. System.out.println(Arrays.toString(int.class.getInterfaces()));
  4. System.out.println(Arrays.toString(void.class.getInterfaces()));
  5. int[] ints = new int[10];
  6. System.out.println(Arrays.toString(ints.getClass().getInterfaces()));
  7. System.out.println(Arrays.toString(InterfaceTest.class.getInterfaces()));
  8. System.out.println(Arrays.toString(SuperInterfaceTest.class.getInterfaces()));
  9. }
  10. }
  11. interface Walkable{
  12. }
  13. interface Flyable{
  14. }
  15. interface Readable<T>{
  16. }
  17. interface SuperInterfaceTest extends Walkable, Flyable,Readable<String>{
  18. }

输出:

  1. []
  2. []
  3. [interface java.lang.Cloneable, interface java.io.Serializable]
  4. [interface person.andy.concurrency.reflect.type.Walkable, interface person.andy.concurrency.reflect.type.Flyable, interface person.andy.concurrency.reflect.type.Readable]
  5. [interface person.andy.concurrency.reflect.type.Walkable, interface person.andy.concurrency.reflect.type.Flyable, interface person.andy.concurrency.reflect.type.Readable]

与获取父类类似,Class也提供了获取参数化类型的接口的方法getGenericInterfaces(),这个方法的返回值也是type[]。看这个例子:

  1. public class InterfaceTest{
  2. public static void main(String[] args) {
  3. System.out.println(Arrays.toString(SuperInterfaceTest.class.getGenericInterfaces()));
  4. }
  5. }
  6. interface Walkable<T>{
  7. }
  8. interface Flyable<T>{
  9. }
  10. interface Readable<T>{
  11. }
  12. interface SuperInterfaceTest extends Walkable<Integer>, Flyable<Object>,Readable<String>{
  13. }

输出:

  1. [person.andy.concurrency.reflect.type.Walkable<java.lang.Integer>, person.andy.concurrency.reflect.type.Flyable<java.lang.Object>, person.andy.concurrency.reflect.type.Readable<java.lang.String>]

这里不再解释。

获取字段、方法和构造方法

获取字段

获取字段有四个方法:

  1. public Field[] getFields() throws SecurityException {}
  2. public Field getField(String name){}
  3. public Field[] getDeclaredFields() throws SecurityException {}
  4. public Field getDeclaredField(String name)

这里我们只分析不带参数的两个即可,带有参数的只是从中返回名称为name的字段。
getFields()方法返回当前类或者接口所有能够访问的公共的字段的数组,如果Class代表一个类,那么返回的是这个类的public字段和它的父类、父接口的public字段。如果Class代表的是一个接口,返回的是这个接口的所有字段和它的所有父接口的字段(接口中的字段默认是public static final的,所以这里没加public)。
看下面的例子:

  1. public class FieldTest extends FieldTestParent1 implements FiledTestInterface1 , FiledTestInterface2 {
  2. public String aPublicName;
  3. String aDefaultName;
  4. private String aPrivateName;
  5. protected String aProtectedName;
  6. public static void main(String[] args) {
  7. Class<FieldTest> fieldTestClass = FieldTest.class;
  8. Field[] fields = fieldTestClass.getFields();
  9. for (Field field : fields) {
  10. System.out.println(field);
  11. }
  12. }
  13. }
  14. public class FieldTestParent1 {
  15. public String aPublicParentString;
  16. String aDefaultParentString;
  17. private String aPrivateParentString;
  18. protected String aProtectedParentString;
  19. }
  20. public interface FiledTestInterface1 {
  21. String A_STRING_IN_INTERFACE1 = "";
  22. }
  23. public interface FiledTestInterface2 {
  24. String A_STRING_IN_INTERFACE2 = "";
  25. }

输出:

  1. public java.lang.String person.andy.concurrency.reflect.field.FieldTest.aPublicName
  2. public static final java.lang.String person.andy.concurrency.reflect.field.FiledTestInterface1.A_STRING_IN_INTERFACE1
  3. public static final java.lang.String person.andy.concurrency.reflect.field.FiledTestInterface2.A_STRING_IN_INTERFACE2
  4. public java.lang.String person.andy.concurrency.reflect.field.FieldTestParent1.aPublicParentString

都是该类本身或者父类或者实现的接口的public字段。
getDeclaredFields方法与getFields方法不同之处是,getDeclaredFields方法会返回这个Class代表的类或者接口本身声明的所有访问权限的字段,包括public、protected、default和private,但是不会返回继承来的字段,还是上面的例子,我们修改一下main方法:

  1. public static void main(String[] args) {
  2. Class<FieldTest> fieldTestClass = FieldTest.class;
  3. Field[] fields = fieldTestClass.getDeclaredFields();
  4. for (Field field : fields) {
  5. System.out.println(field);
  6. }
  7. }

输出:

  1. public java.lang.String person.andy.concurrency.reflect.field.FieldTest.aPublicName
  2. java.lang.String person.andy.concurrency.reflect.field.FieldTest.aDefaultName
  3. private java.lang.String person.andy.concurrency.reflect.field.FieldTest.aPrivateName
  4. protected java.lang.String person.andy.concurrency.reflect.field.FieldTest.aProtectedName

都是FieldTest这个类自己声明的字段,并且所有的访问权限的字段都会返回。
另外注意一点,如果Class代表的是简单类型、void和数组类型,会返回一个长度为0的数组。

获取方法

获取方法同样有四个方法,并且与获取字段的方法有相似的逻辑:

  1. public Method[] getMethods() throws SecurityException {}
  2. public Method getMethod(String name, Class<?>... parameterTypes)
  3. public Method[] getDeclaredMethods() throws SecurityException {}
  4. public Field getDeclaredField(String name)

我们同样只分析不带参数的两个就行。
getMethods()方法返回的是Class代表的类或者接口中声明的public方法和它从父类、接口(接口中的方法都是public的)中继承来的public方法:

  1. public class FieldTest extends FieldTestParent1 implements FiledTestInterface1 , FiledTestInterface2 {
  2. public static void main(String[] args) {
  3. Class<FieldTest> fieldTestClass = FieldTest.class;
  4. Method[] methods = fieldTestClass.getMethods();
  5. for (Method method : methods) {
  6. System.out.println(method);
  7. }
  8. }
  9. @Override
  10. public void testInterface1() {
  11. }
  12. @Override
  13. public void testInterface2() {
  14. }
  15. }
  16. public class FieldTestParent1 {
  17. public void aPublicMethod(){
  18. }
  19. void aDefaultMethod(){
  20. }
  21. private void aPrivateMethod(){
  22. }
  23. public static void aPublicStaticMethod(){
  24. }
  25. }
  26. public interface FiledTestInterface1 {
  27. void testInterface1();
  28. }
  29. public interface FiledTestInterface2 {
  30. void testInterface2();
  31. }

输出:

  1. public static void person.andy.concurrency.reflect.field.FieldTest.main(java.lang.String[])
  2. public void person.andy.concurrency.reflect.field.FieldTest.testInterface1()
  3. public void person.andy.concurrency.reflect.field.FieldTest.testInterface2()
  4. public void person.andy.concurrency.reflect.field.FieldTestParent1.aPublicMethod()
  5. public static void person.andy.concurrency.reflect.field.FieldTestParent1.aPublicStaticMethod()
  6. public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
  7. public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
  8. public final void java.lang.Object.wait() throws java.lang.InterruptedException
  9. public boolean java.lang.Object.equals(java.lang.Object)
  10. public java.lang.String java.lang.Object.toString()
  11. public native int java.lang.Object.hashCode()
  12. public final native java.lang.Class java.lang.Object.getClass()
  13. public final native void java.lang.Object.notify()
  14. public final native void java.lang.Object.notifyAll()

可以看到,输出的都是public的方法,包括父类和接口,也包括static方法。
还有很多需要注意的情况,我们逐一来说:
(1)如果Class代表的是一个类,那么Object类的公共方法也会被返回,Object中,除了clone()和finalize()方法,其他的都是public的。我们在上面的例子中已经看到了。
(2)如果Class代表的是一个接口,那么Object中的方法不会返回,除非这个接口显示声明了Object中的这些方法。看下面的例子:

  1. public interface MethodInterface {
  2. }
  3. public class MethodTest {
  4. public static void main(String[] args) {
  5. Class<MethodInterface> methodTestClass = MethodInterface.class;
  6. Method[] methods = methodTestClass.getMethods();
  7. for (Method method : methods) {
  8. System.out.println(method);
  9. }
  10. }
  11. }

一个方法都不会输出。
(3)如果Class代表的是一个数组,那么会返回Object中的public方法。

  1. public class MethodTest {
  2. public static void main(String[] args) {
  3. int[] ints = new int[10];
  4. Method[] methods = ints.getClass().getMethods();
  5. for (Method method : methods) {
  6. System.out.println(method);
  7. }
  8. }
  9. }

输出如下:

  1. public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
  2. public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
  3. public final void java.lang.Object.wait() throws java.lang.InterruptedException
  4. public boolean java.lang.Object.equals(java.lang.Object)
  5. public java.lang.String java.lang.Object.toString()
  6. public native int java.lang.Object.hashCode()
  7. public final native java.lang.Class java.lang.Object.getClass()
  8. public final native void java.lang.Object.notify()
  9. public final native void java.lang.Object.notifyAll()

注意也是只有public,没有clone和finalize方法。
(4)如果Class代表的是简单类型或者void,返回的数组长度为0。
这个不再举例。
(5)这个接口代表的类或接口的父接口中的静态方法不会被返回。

  1. public interface FiledTestInterface2 {
  2. void testInterface2();
  3. static void testStaticInterface(){
  4. System.out.println("静态方法");
  5. }
  6. }
  7. public class Test implements FiledTestInterface2 {
  8. public static void main(String[] args) {
  9. Class<Test> filedTestInterface2Class = Test.class;
  10. Method[] methods = filedTestInterface2Class.getMethods();
  11. for (Method method : methods) {
  12. System.out.println(method);
  13. }
  14. }
  15. @Override
  16. public void testInterface2() {
  17. }
  18. }

输出的结果中不会有FiledTestInterface2这个接口中的静态方法testStaticInterface。

getDeclaredMethods方法与getDeclaredFields类似,返回的是Class代表的类或者接口中声明的所有类型的方法,包括public、protected、default和private,但是不会返回从父类或者接口继承来的方法。
如果Class代表的是简单类型、void或者数组,会返回一个长度为0的数组。
看下面的例子:

  1. public class FieldTest extends FieldTestParent1 implements FiledTestInterface1 , FiledTestInterface2 {
  2. public void aPublicMethod(){
  3. }
  4. void aDefaultMethod(){
  5. }
  6. @Override
  7. public void aPublicParentMethod() {
  8. super.aPublicParentMethod();
  9. }
  10. protected void aProtectedMethod(){
  11. }
  12. private void aPrivateMethod(){
  13. }
  14. public static void main(String[] args) {
  15. Class<FieldTest> fieldTestClass = FieldTest.class;
  16. Method[] methods = fieldTestClass.getDeclaredMethods();
  17. for (Method method : methods) {
  18. System.out.println(method);
  19. }
  20. }
  21. @Override
  22. public void testInterface1() {
  23. }
  24. @Override
  25. public void testInterface2() {
  26. }
  27. }
  28. public class FieldTestParent1 {
  29. public void aPublicParentMethod(){
  30. }
  31. void aDefaultParentMethod(){
  32. }
  33. private void aPrivateParentMethod(){
  34. }
  35. public static void aPublicParentStaticMethod(){
  36. }
  37. }
  38. public interface FiledTestInterface2 {
  39. void testInterface2();
  40. }
  41. public interface FiledTestInterface1 {
  42. void testInterface1();
  43. }

输出:

  1. public static void person.andy.concurrency.reflect.field.FieldTest.main(java.lang.String[])
  2. protected void person.andy.concurrency.reflect.field.FieldTest.aProtectedMethod()
  3. public void person.andy.concurrency.reflect.field.FieldTest.aPublicMethod()
  4. void person.andy.concurrency.reflect.field.FieldTest.aDefaultMethod()
  5. private void person.andy.concurrency.reflect.field.FieldTest.aPrivateMethod()
  6. public void person.andy.concurrency.reflect.field.FieldTest.aPublicParentMethod()
  7. public void person.andy.concurrency.reflect.field.FieldTest.testInterface1()
  8. public void person.andy.concurrency.reflect.field.FieldTest.testInterface2()

注意FieldTest重写了父类的aPublicParentMethod方法,这个方法被返回了,另外,它继承的两个接口的方法也被返回了,这是因为重写了父类的方法,这个方法就不再是继承来的了,属于这个类自己,而接口的方法必须得实现,也属于这个类自己,所以也返回了。

获取构造方法

获取构造方法的形式与获取字段、方法的形式一致,也有四个方法:

  1. public Constructor<?>[] getConstructors() throws SecurityException {}
  2. public Constructor<T> getConstructor(Class<?>... parameterTypes)
  3. public Constructor<?>[] getDeclaredConstructors() throws SecurityException {}
  4. public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)

首先我们需要知道,构造方法和普通方法的不同之处,就是构造方法是不能被继承的,所以获取的构造方法只能是Class代表的类中声明的构造方法,并且接口是没有构造方法的。
我们还是只看不带参数的两个方法:
getConstructors方法会返回这个Class代表的类的public构造方法,看下面的例子:

  1. public class ConstructorTest {
  2. public int age;
  3. public String name;
  4. public ConstructorTest() {
  5. }
  6. public ConstructorTest(int age, String name) {
  7. this.age = age;
  8. this.name = name;
  9. }
  10. private ConstructorTest(int age) {
  11. this.age = age;
  12. }
  13. private ConstructorTest(String name) {
  14. this.name = name;
  15. }
  16. public static void main(String[] args) {
  17. Class<ConstructorTest> constructorTestClass = ConstructorTest.class;
  18. Constructor<?>[] constructors = constructorTestClass.getConstructors();
  19. for (Constructor<?> constructor : constructors) {
  20. System.out.println(constructor);
  21. }
  22. }
  23. }

ConstructorTest有四个构造方法,两个公有,两个私有,返回的是两个公有的:

  1. public person.andy.concurrency.reflect.con.ConstructorTest(int,java.lang.String)
  2. public person.andy.concurrency.reflect.con.ConstructorTest()

而getDeclaredConstaructors()方法会返回各种访问权限的构造方法,包括public、private、protected和default。我们修改一下上面例子中的main方法:

  1. private person.andy.concurrency.reflect.con.ConstructorTest(java.lang.String)
  2. private person.andy.concurrency.reflect.con.ConstructorTest(int)
  3. public person.andy.concurrency.reflect.con.ConstructorTest(int,java.lang.String)
  4. public person.andy.concurrency.reflect.con.ConstructorTest()

可以看到所有的构造方法都被返回了。

判断内部类的方法

Class提供了几个方法用来判断Class代表的是否是某种内部类,例如成员内部类、匿名内部类和局部内部类。
isMemberClass()用来判断是否是成员内部类,包括成员内部类(类声明中没有static)和静态内部类(类声明中有static)。

  1. public boolean isMemberClass() {
  2. return getSimpleBinaryName() != null && !isLocalOrAnonymousClass();
  3. }

isLocalClass()用来判断一个类是否是局部内部类,局部内部类是定义在方法或者作用域内的类。

  1. public boolean isLocalClass() {
  2. return isLocalOrAnonymousClass() && !isAnonymousClass();
  3. }

isAnonymousClass()判断一个类是否是匿名内部类,匿名内部类也是在方法或者作用域内定义的类。

  1. public boolean isAnonymousClass() {
  2. return "".equals(getSimpleName());
  3. }

看下面的例子:

  1. public class InnerClassTest {
  2. public static void main(String[] args) {
  3. Class<InnerClass> innerClassClass = InnerClass.class;
  4. System.out.println(innerClassClass.isMemberClass());
  5. Class<StaticInnerClass> staticInnerClassClass = StaticInnerClass.class;
  6. System.out.println(staticInnerClassClass.isMemberClass());
  7. new Thread(new Runnable() {
  8. @Override
  9. public void run() {
  10. System.out.println(this.getClass().isAnonymousClass());
  11. }
  12. }).start();
  13. class LocalClass{
  14. }
  15. System.out.println(LocalClass.class.isLocalClass());
  16. }
  17. class InnerClass{
  18. }
  19. static class StaticInnerClass{
  20. }
  21. }

输出:

  1. true
  2. true
  3. true
  4. true

与注解相关的方法

Class代表的类或者接口,也是可注解元素的一种,所以它实现了AnnotatedElement接口,我们就能通过AnnotatedElement接口的几个方法获取Class代表的类或者接口上的各种类型的注解,这几个方法已经在这篇文章中详细介绍过了,这里不再赘述。

小结

Class提供的这些方法使得我们很轻松就能使用它的特性,例如获取方法、字段等,但每个或者说每类方法都有需要注意的地方,理解它们的前提是我们对继承关系、注解、枚举、内部类等有比较深入的理解。
除了上面的这几类方法,还有一些方法没有介绍到但是也很重要,读者可以自己去更完整地了解。