Class类

Class类存在于java.lang包下,Class类的实例表示Java运行时的类(class and enum)或接口(interface and annotation),数组也同样被映射为一个Class对象,所有具有相同元素类型和维数的数组都共享该class对象,基本数据类型和void关键字同样表现为class对象

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement

Class的特点:

  • Class类也是类的一种,与class关键字不一样(平时描述中也要区分Class和class的区别)

  • 没有公共的构造函数,但是有私有构造函数,私有构造函数的目的主要是用于避免生成默认的构造函数,并只能由JVM创建和加载

    Class类对象是在ClassLoader类加载时由虚拟机自动构造,并通过调用类加载器中的defineClass方法来构造

    //防止生成默认的构造函数
    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对象,每当编写并且编译一个新创建的类就会产生一个对应的Class对象,并且这个Class对象会被保存在新建类的.class文件中(.class文件存储的就是Class对象)

  • 每个通过class关键字标识的类,在内存中有且只有一个与之对应的Class对象来描述其类型信息,实例对象与Class对象是多对一的关系

  • Class类的实例作用是运行时提供或获取某个对象的类型信息

3.1 class类文件结构

JVM虚拟机只与class文件绑定,即不论上层是什么语言,只要最终能编译为class文件,就可以被JVM识别并加载

一个class文件对应唯一一个类或接口的Class对象实例信息

类或接口并不一定都存在对应的磁盘文件(因为类或接口也可以通过类加载器直接生成)

JVM严格定义了class文件,例如哪个字节代表什么含义、长度多少、先后顺序等都是不允许改变的

3.1.1 class文件格式

这里所说的class文件表示的是一组以8位字节为基础单位的二进制流,各个数据严格按照顺序紧凑的排列在class文件之中,中间不存在任何分隔符,整个文件都是程序运行的必要数据

如果遇到需要占用8位字节以上空间的数据项时,则会按照高位在前的方式分割成若干个8位字节进行存储

class文件格式采用的是类似于C语言结构体的伪结构来存储数据,这种伪结构只存在两种数据类型:无符号数和表

  • 无符号数:属于常见的数据类型,以u1\u2\u4\u8来分表代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用于描述数字、索引引用、数量值或者按照UTF-8编码构成的字符串值

  • 表:是多个无符号数或其他表作为数据项构成的复合数据类型,所有表都习惯性的以_info结尾。表用于描述有层次关系的复合结构数据

整个class文件本质上就是一张表

名称类型数量
u4magic11
u2minor_version21
u2major_version31
u2constant_pool_count41
cp_infoconstant_poolconstant_pool_count-1
u2access_flags51
u2this_class1
u2super_class1
u2interfaces_count1
u2interfacesinterfaces_count
u2fields_count1
field_info fieldsfields_count
u2methods_count1
method_infomethodsmethods_count
u2attributes_count1
attribute_infoattributesattributes_count

具体class文件的详解参考:

3.2 类加载的角度分析Class对象

该内容参考类加载器子系统

类的执行流程:加载->验证–>准备–>解析(验证、准备、解析称为类的连接)–>初始化–>使用–>卸载
在这里插入图片描述

Class对象也叫类模版,通过Class类模版生成多个实例对象,反射即是在获取Class对象及其类内部信息,反向控制实例对象

3.3 反射常用类

Java中提供了Class类和java.lang.reflect类库,对反射技术进行支持,在反射包中,我们常用的类主要有:

  • java.lang.reflect.Method代表类的方法

  • java.lang.reflect.Filed代表类的成员变量

  • java.lang.reflect.Constructor代表类的构造器

  • java.lang.Class代表一个类,Class对象表示某个类加载后在堆中的对象,通过Class对象可以获取上述反射包中的内容

3.3.1创建Class类的三种方式

  1. 可以通过运行时类.class来创建
    Class c=Student.class;//String.class

  2. 可以通过类的对象.getClass()
    Student s=new Student();
    Class c=s.getClass();

  3. 可以通过Class类中的静态方法 forName();
    Class<?> c = Class.forName("com.carl.test.classObject.TestClass");

3.4 Class类的源码解析及常用方法

toString()

toString()将对象转换为字符串,字符串表示形式为:“class"或"interface”+空格+类的全限定名,如果此Class对象表示基本数据类型,则此方法返回基本数据类型的名称,如果这个Class对象表示void,则该方法返回void

public String toString() {
    return (isInterface() ? "interface " : (isPrimitive() ? "" : "class "))
        + getName();
}
toGenericString()

toGenericString()将返回描述该类的字符串,包括修饰符和泛型参数的信息,返回格式为:权限修饰符+类类型(基本数据类型、class、enum、interface、@interface或void)+全限定类名+用逗号分隔的泛型参数列表(没有则不显示)

public String toGenericString() {
    if (isPrimitive()) {
        return toString();
    } else {
        StringBuilder sb = new StringBuilder();

        // Class modifiers are a superset of interface modifiers
        int modifiers = getModifiers() & Modifier.classModifiers();
        if (modifiers != 0) {
            sb.append(Modifier.toString(modifiers));
            sb.append(' ');
        }

        if (isAnnotation()) {
            sb.append('@');
        }
        if (isInterface()) { // Note: all annotation types are interfaces
            sb.append("interface");
        } else {
            if (isEnum())
                sb.append("enum");
            else
                sb.append("class");
        }
        sb.append(' ');
        sb.append(getName());

        TypeVariable<?>[] typeparms = getTypeParameters();
        if (typeparms.length > 0) {
            boolean first = true;
            sb.append('<');
            for(TypeVariable<?> typeparm: typeparms) {
                if (!first)
                    sb.append(',');
                sb.append(typeparm.getTypeName());
                first = false;
            }
            sb.append('>');
        }

        return sb.toString();
    }
}
forName()

forName(String className)返回与给定字符串名称的类或接口关联的Class对象,调用此方法等价于forName(String name, boolean initialize,ClassLoader loader)方法,其中loader表示当前类的类加载器,className必须是类的全限定名,Class.forName("java.lang.Thread")会导致Thread类被初始化

@CallerSensitive
public static Class<?> forName(String className)
            throws ClassNotFoundException {
    //获取类加载器,来加载驱动
    Class<?> caller = Reflection.getCallerClass();
    //forName0方法参数说明:类的全路径名、加载后是否初始化该类、使用哪个类加载器、调用forName方法的类
    return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}

private static native Class<?> forName0(String name, boolean initialize,
                                        ClassLoader loader,
                                        Class<?> caller)
    throws ClassNotFoundException;

是否初始化取决于initalize参数,默认为true,可以通过forName(String name, boolean initialize,ClassLoader loader)方法实现加载不初始化;

虽然官方API表示forName(String className)和forName(String name,boolean initialize,ClassLoader loader)方法等价,只是说效果一致,即返回结果一致,异常抛出机制一致,forName(String name,boolean initialize,ClassLoader loader)可以只传入name,initialize为true,loader为null才等价,否则并不等价。

forName(String name, boolean initialize,ClassLoader loader)使用给定的类加载器返回与给定字符串名称的类或接口关联的Class对象。

参数说明:

name:类或接口的完全限定名(与getName返回的格式相同),该方法会通过name参数定位、加载和链接类或接口。如果name表示基本数据类型或void,则会尝试在未命名包中定位名称为name的值的用户定义类。因此,此方法不能用于获取表示基本数据类型或void的任何Class对象。如果name表示数组类,则加载该数组类的组件类型,但不初始化。

initialize:只有initialize形参为true且之前未初始化时,类才会初始化。

loader:指定的类加载器用于加载类或接口。如果类加载器参数为空,则默认通过引导类加载器(bootstrapClassLoader)加载类。

@CallerSensitive
public static Class<?> forName(String name, boolean initialize,
                               ClassLoader loader)
    throws ClassNotFoundException
{
    Class<?> caller = null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        //如果安全管理器不为空,则调用getCallerClass方法进行反射调用,否则避免进行此调用产生的开销
        caller = Reflection.getCallerClass();
        if (sun.misc.VM.isSystemDomainLoader(loader)) {
            ClassLoader ccl = ClassLoader.getClassLoader(caller);
            if (!sun.misc.VM.isSystemDomainLoader(ccl)) {
                //如果类加载器不为空,则进行安全检查--获取当前类加载器进行权限校验,确保可以可以访问bootstraoClassLoader类加载器
                sm.checkPermission(
                    SecurityConstants.GET_CLASSLOADER_PERMISSION);
            }
        }
    }
    return forName0(name, initialize, loader, caller);
}

注意,此方法不检查所请求的类是否可被其调用者访问。如果加载器为空,且存在安全管理器,且调用者的类加载器不为空,则该方法使用RuntimePermission(“getClassLoader”)权限调用安全管理器的checkPermission方法,以确保可以访问引导类加载器。

newInstance()

newInstance()创建由此Class对象表示的类的新实例。等价于空参构造器的new实例(String str = new String())

返回此对象表示的类的新分配的实例,如果该类的空构造函数为不可访问或者该类是Class类,则抛出IllegalAccessException异常

如果该类表示一个抽象类、接口、数组、基本类型或void,或者没有空构造函数,或者由于其他原因实例化失败,则抛出InstantiationException异常

如果此方法引发的初始化失败,则抛出ExceptionInInitializerError错误

如果存在安全管理器,调用者的类加载器与当前类的类加载器不同或者不是其基类,或者调用s.checkpackageaccess()方法会拒绝访问该类加载器的包,则会抛出SecurityException异常

@CallerSensitive
public T newInstance()
    throws InstantiationException, IllegalAccessException
{
    if (System.getSecurityManager() != null) {
        //如果安全管理器不为空,则检查成员访问权限
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);
    }

    // NOTE: the following code may not be strictly correct under
    // the current Java memory model.

    // 构造函数查找
    if (cachedConstructor == null) {
        //如果该类是Class类,则抛出异常,因为Class类本身就没有空参构造器
        if (this == Class.class) {
            throw new IllegalAccessException(
                "Can not call newInstance() on the Class for java.lang.Class"
            );
        }
        try {
            //构造函数的参数值,如果是空,则表示空参构造
            Class<?>[] empty = {};
            //调用getConstructor0方法,Member.DECLARED表示当前类或接口已声明的方法集合
            //这里是抛出NoSuchMethodException的位置,如果找不到空参构造则会抛出异常
            final Constructor<T> c = getConstructor0(empty, Member.DECLARED);
            //不支持访问构造函数检查,必须在这里进行安全检查
            java.security.AccessController.doPrivileged(
                new java.security.PrivilegedAction<Void>() {
                    public Void run() {
                            //检查当前构造函数是否可访问后,设置访问标志
                            //true为可访问,不需要执行访问检查
                            //false为不可访问,需要强制执行访问检查
                            //这里是抛出SecurityException异常的位置
                            c.setAccessible(true);
                            return null;
                        }
                    });
            cachedConstructor = c;
        } catch (NoSuchMethodException e) {
            //捕获NoSuchMethodException并抛出InstantiationException异常
            throw (InstantiationException)
                new InstantiationException(getName()).initCause(e);
        }
    }
    Constructor<T> tmpConstructor = cachedConstructor;
    // 安全检查
    //获取权限修饰符
    //public=0x00000001 private=0x00000002 protected=0x00000004
    int modifiers = tmpConstructor.getModifiers();
    //快速检查成员访问权限
    //检查当前实例化的类和构造函数是否为public权限,如果不是public,则进入,是public则跳过
    if (!Reflection.quickCheckMemberAccess(this, modifiers)) {
        //获取当前类的反射调用
        Class<?> caller = Reflection.getCallerClass();
        //如果当前创建的实例和反射调用的类不一样
        if (newInstanceCallerCache != caller) {
            //就会去检查反射调用的类的空参构造函数的访问权限是否是public
            //这里是抛出IllegalAccessException的位置,确认不可访问,则会抛出异常
            Reflection.ensureMemberAccess(caller, this, null, modifiers);
            newInstanceCallerCache = caller;
        }
    }
    // Run constructor
    try {
        //一系列检查后,调用构造器的创建实例方法
        return tmpConstructor.newInstance((Object[])null);
    } catch (InvocationTargetException e) {
        //创建失败则会抛出异常
        Unsafe.getUnsafe().throwException(e.getTargetException());
        // Not reached
        return null;
    }
}

注意:此方法继承由空构造器抛出的任何异常,包括已检查异常。使用此方法可以有效的绕过编译器的编译时异常检查。 newInstance()方法将构造器抛出的所有异常,封装在InvocationTargeException中来避免这个问题

isAnnotation()

isAnnotation()如果此Class对象为注解类型,则返回true,否则返回false

如果这个方法返回true,则isInterface()也将返回true

public boolean isAnnotation() {
    return (getModifiers() & ANNOTATION) != 0;
}

isSynthetic()

isSynthetic()如果此Class类为合成类,则返回true,否则返回false,当且仅当该类是java语言规范定义的合成类时返回true

public boolean isSynthetic() {
    return (getModifiers() & SYNTHETIC) != 0;
}

getName()

getName()返回由class对象表示的实体(类、接口、数组、基本类型或void)的名称

  • 如果这个类对象表示的是引用类型,不是数组类型,则返回类的二进制名称(二进制名称就是全限定名)

    System.out.println(String.class.getName());
    //输出结果为:
    java.lang.String
    
  • 如果这个类对象表示一个基本数据类型或void,则返回这个基本数据类型或void的字符串
    基本数据类型

    	System.out.println(short.class.getName());
    	//输出结果为:
    	short
    

    void

    System.out.println(void.class.getName());
    //输出结果为:
    void
    
  • 如果这个类对象表示一个数组类型,则名称的内部形式由元素类型的名称加上一个或多个表示数组嵌套深度的’['字符组成。
    元素类型名称编码:

    元素类型编码
    booleanZ
    byteB
    charC
    class or InterfaceLclassname;
    doubleD
    floatF
    intI
    longJ
    shortS

    class or interface的L表示元素类型名称,className表示全路径名
    例子:

    • 基本数据类型的数组
      long[][] test = new long[5][5];
      System.out.println(test.getClass().getName());
      //输出结果为:
      [[J
      //[[表示二维数组,J表示long类型的数组
      
      int[][] testInt = new int[5][5];
      System.out.println(testInt.getClass().getName());
      //输出结果为:
      [[I
      //[[表示二维数组,I表示int类型的数组
      
      byte[] testByte = new byte[5];
      System.out.println(testByte.getClass().getName());
      //输出结果为:
      [B
      //[表示一维数组,B表示byte类型的数组
      
    • 引用类型的数组
      String[] testString = new String[5];
      System.out.println(testString.getClass().getName());
      //输出结果为:
      [Ljava.lang.String;
      //[表示一维数组,L表示引用数据类型的数组
      
      Object[][] testObject = new Object[5][5];
      System.out.println(testObject.getClass().getName());
      //输出结果为:
      [[Ljava.lang.Object;
      //[[表示二维数组,L表示引用数据类型的数组
      
public String getName() {
    String name = this.name;
    if (name == null)
        this.name = name = getName0();
    return name;
}

// 缓存该名称,减少对虚拟机的调用次数
private transient String name;
private native String getName0();

getClassLoader()

getClassLoader()返回当前类的类加载器,一些实现方法,通过null来表示需要调用bootstrapClassLoader,因此

  • 如果该类由bootstrapClassLoader类加载器载入,则此方法将返回null;

  • 如果存在安全管理器,且调用者的类加载器不为空,且调用者的类加载器与当前类的类加载器不同,或者不是当前类的类加载器的基类,则会调用RuntimePreminssion(“getClassLoader”)权限调用安全管理器的checkPermission方法,确保可以访问该类的类加载器

  • 如果该对象表示基本数据类型或void,则返回null

getClassLoader()方法的返回值为:加载此对象表示的类或接口的类加载器

@CallerSensitive
public ClassLoader getClassLoader() {
    ClassLoader cl = getClassLoader0();
    if (cl == null)
        return null;
    SecurityManager sm = System.getSecurityManager();
    if (sm != null) {
        ClassLoader.checkClassLoaderPermission(cl, Reflection.getCallerClass());
    }
    return cl;
}

// Package-private to allow ClassLoader access
ClassLoader getClassLoader0() { return classLoader; }

// 在JVM中初始化,而不是在私有构造函数中初始化
// 该字段从反射接入中过滤,即getDeclaredField()方法,将会抛出NoSuchFieldException异常
private final ClassLoader classLoader;

getTypeParameters()

getTypeParameters()返回一个TypeVariable对象的数组,该数组按照声明顺序表示由此GenericDeclaration对象表示的泛型声明的类型变量,如果底层泛型没有声明类型变量,则返回长度为0的数组

异常:如果此泛型声明的泛型签名不符合Java™虚拟机规范自:1.5中指定的格式则抛出GenericSignatureFormatError

public TypeVariable<Class<T>>[] getTypeParameters() {
    ClassRepository info = getGenericInfo();
    if (info != null)
        return (TypeVariable<Class<T>>[])info.getTypeParameters();
    else
        return (TypeVariable<Class<T>>[])new TypeVariable<?>[0];
}
TypeVariable<Class<ArrayList>>[] typeParameters = ArrayList.class.getTypeParameters();
System.out.println(typeParameters[0]);
//输出结果为:
E

getGenericSuperclass()

getGenericSuperclass()返回Type对象,表示由这个Class对象表示的实体(类、接口、基本数据类型或void)的直接父类

  • 如果父类是参数化类型,则返回的type对象必须准确的反应源代码中使用的实际类型参数,表示父类的参数化类型如果没有创建,则创建它

有关参数化类型创建过程的语义,参考ParameterizedType的声明

  • 如果这个Class类表示Object类接口基本数据类型void,则返回null

  • 如果此对象表示一个数组类,则返回表示object类的class对象

异常处理

  • 如果类签名不符合Java虚拟机规范中指定的格式,则抛出异常GenericSignatureFormatError

  • 如果父类引用了一个不存在的类型声明,则抛出异常TypeNotPresentException

  • 如果父类引用了一个任何原因导致的不能实例化的参数化类型,则抛出异常MalformedParameterizedTypeException

public native Class<? super T> getSuperclass();
public Type getGenericSuperclass() {
    ClassRepository info = getGenericInfo();
    if (info == null) {
        return getSuperclass();
    }

    // Historical irregularity:
    // Generic signature marks interfaces with superclass = Object
    // but this API returns null for interfaces
    if (isInterface()) {
        return null;
    }

    return info.getSuperclass();
}
Type genericSuperclass = String.class.getGenericSuperclass();
System.out.println(genericSuperclass);
//输出结果为:
class java.lang.Object

getInterface()

getInterface()返回此对象表示的类或接口实现的接口,不会携带泛型参数

  • 如果该对象表示一个类,则返回值为一个数组,其中包括该类实现的所有接口的对象,数组中接口对象的顺序对应implement子句中接口名称的顺序

  • 如果该对象表示一个接口,则数组包含该接口中扩展的所有接口的对象,数组中接口对象的熟悉怒对应extends子句中接口名称的顺序

  • 如果此对象不实现接口的类或接口,则该方法返回长度为0的数组

  • 如果是基本数据类型或void,则返回长度为0的数组

  • 如果此Class对象表示数组类型,则接口Cloneable和java.ioSerializable将按此顺序返回

Object[][] testObject = new Object[5][5];
Type[] genericInterfaces1 = testObject.getClass().getGenericInterfaces();
for (Type type : genericInterfaces1){
    System.out.println(type);
}
//输出结果为:
interface java.lang.Cloneable
interface java.io.Serializable
public Class<?>[] getInterfaces() {
    ReflectionData<T> rd = reflectionData();
    if (rd == null) {
        // no cloning required
        return getInterfaces0();
    } else {
        Class<?>[] interfaces = rd.interfaces;
        if (interfaces == null) {
            interfaces = getInterfaces0();
            rd.interfaces = interfaces;
        }
        // defensively copy before handing over to user code
        return interfaces.clone();
    }
}

// Lazily create and cache ReflectionData
private ReflectionData<T> reflectionData() {
    SoftReference<ReflectionData<T>> reflectionData = this.reflectionData;
    int classRedefinedCount = this.classRedefinedCount;
    ReflectionData<T> rd;
    if (useCaches &&
        reflectionData != null &&
        (rd = reflectionData.get()) != null &&
        rd.redefinedCount == classRedefinedCount) {
        return rd;
    }
    // else no SoftReference or cleared SoftReference or stale ReflectionData
    // -> create and replace new instance
    return newReflectionData(reflectionData, classRedefinedCount);
}

private native Class<?>[] getInterfaces0();

getGenericInterfaces()

getGenericInterfaces()返回当前类或接口的直接实现接口数组,会携带泛型参数

  • 如果父接口是参数化类型,则返回type对象必须准确的反应源代码中使用的实际类型参数,表示每个父接口的参数化类型,如果没创建,则创建

  • 如果该对象表示一个类,则返回一个包含该类实现的所有接口的对象,数组中接口对象的顺序对应implements子句中的接口名称的顺序

  • 如果该对象表示一个数组,则返回Cloneable和Serializable接口对象

  • 如果该对象表示一个接口,则返回接口对象的顺序对应extends子句中的接口名称的顺序

  • 如果为基本数据类型或void,则该方法返回数组长度为0

public Type[] getGenericInterfaces() {
    ClassRepository info = getGenericInfo();
    return (info == null) ?  getInterfaces() : info.getSuperInterfaces();
}

getPackage()

getPackage()获取当前类的包名、规范和版本,用逗号分隔

该方法利用类加载器查找包,如果类时由bootstrapClassLoader类加载器加载,则搜索从ClassPath加载的包集合可以找到该类的包

如果该类的类加载器没有创建包对象,则返回null

只有当信息是在伴随类的清单中定义,并且类加载器使用清单中的属性创建包实例时,包才具有版本和规范的属性

public Package getPackage() {
    return Package.getPackage(this);
}
Package aPackage = String.class.getPackage();
System.out.println(aPackage);
//输出结果为:
package java.lang, Java Platform API Specification, version 1.8

getEnclosingMethod()

getEnclosingMethod()如果此Class对象表示方法中的局部类或匿名类,则返回一个method对象,表示底层类的直接封闭方法,否则返回null

  • 如果底层类是由类型声明、实例初始化或静态初始化器立即括起来的本地类或匿名类,则此方法返回null
@CallerSensitive
public Method getEnclosingMethod() throws SecurityException {
    EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo();

    if (enclosingInfo == null)
        return null;
    else {
        if (!enclosingInfo.isMethod())
            return null;

        MethodRepository typeInfo = MethodRepository.make(enclosingInfo.getDescriptor(),
                                                          getFactory());
        Class<?>   returnType       = toClass(typeInfo.getReturnType());
        Type []    parameterTypes   = typeInfo.getParameterTypes();
        Class<?>[] parameterClasses = new Class<?>[parameterTypes.length];

        // Convert Types to Classes; returned types *should*
        // be class objects since the methodDescriptor's used
        // don't have generics information
        for(int i = 0; i < parameterClasses.length; i++)
            parameterClasses[i] = toClass(parameterTypes[i]);

        // Perform access check
        Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass();
        enclosingCandidate.checkMemberAccess(Member.DECLARED,
                                             Reflection.getCallerClass(), true);
        /*
         * Loop over all declared methods; match method name,
         * number of and type of parameters, *and* return
         * type.  Matching return type is also necessary
         * because of covariant returns, etc.
         */
        for(Method m: enclosingCandidate.getDeclaredMethods()) {
            if (m.getName().equals(enclosingInfo.getName()) ) {
                Class<?>[] candidateParamClasses = m.getParameterTypes();
                if (candidateParamClasses.length == parameterClasses.length) {
                    boolean matches = true;
                    for(int i = 0; i < candidateParamClasses.length; i++) {
                        if (!candidateParamClasses[i].equals(parameterClasses[i])) {
                            matches = false;
                            break;
                        }
                    }

                    if (matches) { // finally, check return type
                        if (m.getReturnType().equals(returnType) )
                            return m;
                    }
                }
            }
        }

        throw new InternalError("Enclosing method not found");
    }
}

private native Object[] getEnclosingMethod0();

private EnclosingMethodInfo getEnclosingMethodInfo() {
    Object[] enclosingInfo = getEnclosingMethod0();
    if (enclosingInfo == null)
        return null;
    else {
        return new EnclosingMethodInfo(enclosingInfo);
    }
}

private static Class<?> toClass(Type o) {
  if (o instanceof GenericArrayType)
      return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
                               0)
          .getClass();
  return (Class<?>)o;
}

getEnclosingConstructor()

getEnclosingConstructor()如果此Class对象表示构造函数中的本地类或匿名类,则返回底层类的直接括号中的构造函数的Constructor对象,否则返回null

@CallerSensitive
public Constructor<?> getEnclosingConstructor() throws SecurityException {
    EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo();

    if (enclosingInfo == null)
        return null;
    else {
        if (!enclosingInfo.isConstructor())
            return null;

        ConstructorRepository typeInfo = ConstructorRepository.make(enclosingInfo.getDescriptor(),
                                                                    getFactory());
        Type []    parameterTypes   = typeInfo.getParameterTypes();
        Class<?>[] parameterClasses = new Class<?>[parameterTypes.length];

        // Convert Types to Classes; returned types *should*
        // be class objects since the methodDescriptor's used
        // don't have generics information
        for(int i = 0; i < parameterClasses.length; i++)
            parameterClasses[i] = toClass(parameterTypes[i]);

        // Perform access check
        Class<?> enclosingCandidate = enclosingInfo.getEnclosingClass();
        enclosingCandidate.checkMemberAccess(Member.DECLARED,
                                             Reflection.getCallerClass(), true);
        /*
         * Loop over all declared constructors; match number
         * of and type of parameters.
         */
        for(Constructor<?> c: enclosingCandidate.getDeclaredConstructors()) {
            Class<?>[] candidateParamClasses = c.getParameterTypes();
            if (candidateParamClasses.length == parameterClasses.length) {
                boolean matches = true;
                for(int i = 0; i < candidateParamClasses.length; i++) {
                    if (!candidateParamClasses[i].equals(parameterClasses[i])) {
                        matches = false;
                        break;
                    }
                }

                if (matches)
                    return c;
            }
        }

        throw new InternalError("Enclosing constructor not found");
    }
}

getDeclaringClass()

getDeclaringClass()如果此class对象表示的类或接口是另一个类的成员,则返回声明它的类的Class对象

  • 如果这个类或接口不是任何其他类的成员,则此方法返回null

  • 如果此class对象表示数组类、基本数据类型或void,则此方法返回null

@CallerSensitive
public Class<?> getDeclaringClass() throws SecurityException {
    final Class<?> candidate = getDeclaringClass0();

    if (candidate != null)
        candidate.checkPackageAccess(
                ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
    return candidate;
}

private native Class<?> getDeclaringClass0();

getEnclosingClass()

getEnclosingClass()返回内部类的直接外部类,如果底层类是顶层类,此方法返回null

@CallerSensitive
public Class<?> getEnclosingClass() throws SecurityException {
    // There are five kinds of classes (or interfaces):
    // a) Top level classes
    // b) Nested classes (static member classes)
    // c) Inner classes (non-static member classes)
    // d) Local classes (named classes declared within a method)
    // e) Anonymous classes


    // JVM Spec 4.8.6: A class must have an EnclosingMethod
    // attribute if and only if it is a local class or an
    // anonymous class.
    EnclosingMethodInfo enclosingInfo = getEnclosingMethodInfo();
    Class<?> enclosingCandidate;

    if (enclosingInfo == null) {
        // This is a top level or a nested class or an inner class (a, b, or c)
        enclosingCandidate = getDeclaringClass();
    } else {
        Class<?> enclosingClass = enclosingInfo.getEnclosingClass();
        // This is a local class or an anonymous class (d or e)
        if (enclosingClass == this || enclosingClass == null)
            throw new InternalError("Malformed enclosing method information");
        else
            enclosingCandidate = enclosingClass;
    }

    if (enclosingCandidate != null)
        enclosingCandidate.checkPackageAccess(
                ClassLoader.getClassLoader(Reflection.getCallerClass()), true);
    return enclosingCandidate;
}

getSimpleName()

getSimpleName()返回当前Class对象的类名,如果当前类为匿名类,则返回空字符串,数组的名称是附加了’[]‘的组件类型名称,特别是组件类型为匿名的数组,简单名称为’[]

public String getSimpleName() {
    if (isArray())
        return getComponentType().getSimpleName()+"[]";

    String simpleName = getSimpleBinaryName();
    if (simpleName == null) { // top level class
        simpleName = getName();
        return simpleName.substring(simpleName.lastIndexOf(".")+1); // strip the package name
    }
    // According to JLS3 "Binary Compatibility" (13.1) the binary
    // 非包类的名称是直接包含类的二进制名称,后跟'$'
    // (对于嵌套类或内部类): 类名.
    // (对于本地类): 1或多个数字后跟类名
    // (对于匿名类): 1或多个数字.

    // 由于getSimpleBinaryName()将去掉立即包含的类的二进制名称,因此我们看到的时一个正则表达式
    //"\[0-9]"后跟类名的字符串,匿名类的类名为空字符串

    //从类名中删除前缀"\[0-9]"
    int length = simpleName.length();
    if (length < 1 || simpleName.charAt(0) != '$')
        throw new InternalError("Malformed class name");
    int index = 1;
    while (index < length && isAsciiDigit(simpleName.charAt(index)))
        index++;
    // Eventually, this is the empty string iff this is an anonymous class
    return simpleName.substring(index);
}

getTypeName()

getTypeName()返回此类的信息字符串,类或接口返回全限定名,基本数据类型或void返回对应字符串,数组如果是引用类型数组,则返回全限定名加[],例如:java.lang.Object[][],如果是基本数据类型数组,则返回基本数据类型加[],例如int[][]

public String getTypeName() {
    if (isArray()) {
        try {
            Class<?> cl = this;
            int dimensions = 0;
            while (cl.isArray()) {
                dimensions++;
                cl = cl.getComponentType();
            }
            StringBuilder sb = new StringBuilder();
            sb.append(cl.getName());
            for (int i = 0; i < dimensions; i++) {
                sb.append("[]");
            }
            return sb.toString();
        } catch (Throwable e) { /*FALLTHRU*/ }
    }
    return getName();
}

getCanonicalName()

getCanonicalName()返回由java语言规范定义的类的规范名称,如果没有规范名称,例如本地类或匿名类或其他组件类型没有规范名的数组,则返回null

public String getCanonicalName() {
    if (isArray()) {
        String canonicalName = getComponentType().getCanonicalName();
        if (canonicalName != null)
            return canonicalName + "[]";
        else
            return null;
    }
    if (isLocalOrAnonymousClass())
        return null;
    Class<?> enclosingClass = getEnclosingClass();
    if (enclosingClass == null) { // top level class
        return getName();
    } else {
        String enclosingName = enclosingClass.getCanonicalName();
        if (enclosingName == null)
            return null;
        return enclosingName + "." + getSimpleName();
    }
}

isAnonymousClass()

isAnonymousClass()判断是否为匿名类

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

isLocalClass()

isLocalClass()判断是否是本地类

public boolean isLocalClass() {
    return isLocalOrAnonymousClass() && !isAnonymousClass();
}

isMemberClass()

isMemberClass()判断是否为成员类

public boolean isMemberClass() {
    return getSimpleBinaryName() != null && !isLocalOrAnonymousClass();
}

getClasses()

getClasses()返回一个包含Class对象的数组,该数组表示此Class对象的类的所有公共类和成员接口,如果Class对象没有公共类或接口,则返回长度为0的数组,如果此Class对象标识基本类型,数组或void,则此方法返回长度为0的数组

@CallerSensitive
public Class<?>[] getClasses() {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), false);

    // Privileged so this implementation can look at DECLARED classes,
    // something the caller might not have privilege to do.  The code here
    // is allowed to look at DECLARED classes because (1) it does not hand
    // out anything other than public members and (2) public member access
    // has already been ok'd by the SecurityManager.

    return java.security.AccessController.doPrivileged(
        new java.security.PrivilegedAction<Class<?>[]>() {
            public Class<?>[] run() {
                List<Class<?>> list = new ArrayList<>();
                Class<?> currentClass = Class.this;
                while (currentClass != null) {
                    Class<?>[] members = currentClass.getDeclaredClasses();
                    for (int i = 0; i < members.length; i++) {
                        if (Modifier.isPublic(members[i].getModifiers())) {
                            list.add(members[i]);
                        }
                    }
                    currentClass = currentClass.getSuperclass();
                }
                return list.toArray(new Class<?>[0]);
            }
        });
}

getFields()

getFields()返回当前类的所有可访问(public)公共字段Field对象的数组

  • 如果当前Class对象表示一个没有可访问公共字段的类或接口,则此方法返回一个长度为0的数组

  • 如果该Class对象表示一个接口或类,此方法返回该类或接口及其所有父类或父接口的字段

  • 如果该Class对象表示数组,基本数据类型或void,此方法返回长度为0的数组

注意:返回数组中的元素没有任何特定的顺序

@CallerSensitive
public Field[] getFields() throws SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    return copyFields(privateGetPublicFields(null));
}

getMethods()

getMethods()返回Method对象的数组,该数组表示该类对象对应类或接口中的所有public方法,包括类或接口中声明的方法以及父类或父接口中的继承的方法

  • 如果一个Class对象有多个具有相同名称和参数类型,但返回值不同的公共方法,则返回的数组中每个这个样的方法都有一个Method对象

  • 如果该Class对象表示一个数组类型,则返回的数组会返回Object继承的每个public方法对应的Method对象,但是不包含clone()的Method对象

  • 如果此Class对象表示接口,则返回的数组不包含任何来自Object的隐式声明方法,如果该接口或其任何父接口中没有显示声明方法,则返回的数组长度为0

  • 如果Class对象表示类,则除了当前类的public方法和父类继承的public方法,还总是有Object的public方法

  • 如果Class对象表示基本数据类型或void,则返回的数组长度为0

  • 如果Class对象表示的类或接口的父类或父接口中声明的静态方法也会被包含在Method对象中

@CallerSensitive
public Method[] getMethods() throws SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    return copyMethods(privateGetPublicMethods());
}
//测试类的父类
public class SuperClass {

    public static void play(){
        System.out.println("static play()");
    }
}
//测试类
public class MemberClass {
    private String name;

    private String sex;

    public String description;

    public int age;

    public static void sleep(){
        System.out.println("static sleep()");
    }
    public void show(){
        System.out.println("void show()");
    }

    public int show(int age){
        return age;
    }

    private String privateInfo(String name, String sex){
        return name+sex;
    }
}

测试

Method[] methods = MemberClass.class.getMethods();
for (Method method : methods) {
    System.out.println(method);
}
//输出结果为:
public static void com.carl.test.classObject.MemberClass.sleep()
public int com.carl.test.classObject.MemberClass.show(int)
public void com.carl.test.classObject.MemberClass.show()
public static void com.carl.test.classObject.SuperClass.play()
public final void java.lang.Object.wait() throws java.lang.InterruptedException
public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
public boolean java.lang.Object.equals(java.lang.Object)
public java.lang.String java.lang.Object.toString()
public native int java.lang.Object.hashCode()
public final native java.lang.Class java.lang.Object.getClass()
public final native void java.lang.Object.notify()
public final native void java.lang.Object.notifyAll()

getConstructors()

getConstructors()返回当前Class对象的所有public构造器对应的Constructor对象数组

如果类没有公共构造函数、数组、基本数据类型或void,则返回长度为0的数组

注意:getConstructors()返回的是Constructor<?>类型的数组,不是Constructor类型的数组,因为这个方法返回后,数组是可以被修改,用于保存不用的类的Constructor对象,如果使用Constructor将仅限于当前类的Constructor对象

@CallerSensitive
public Constructor<?>[] getConstructors() throws SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    return copyConstructors(privateGetDeclaredConstructors(true));
}

getField()

getField(String name)返回一个field对象,该对象反应由此class对象表示的类或接口的指定public成员字段

如果该Class类或接口中没有找到字段,将会递归该Class对象的类或接口的父类或父接口,直接父接口或父类将按照声明升序进行搜索

如果Class类或接口及其父类或父接口都没找到,则抛出异常NoSuchFieldException

@CallerSensitive
public Field getField(String name)
    throws NoSuchFieldException, SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    Field field = getField0(name);
    if (field == null) {
        throw new NoSuchFieldException(name);
    }
    return field;
}

getMethod()

getMethod(String name, Class<?>... parameterTypes)

获取当前Class对象表示的类或接口的指定public公共成员方法。

  • name表示所需方法的方法名

  • parameterTypes是一个Class对象的数组,按照声明的顺序标识方法的形参类型

    • 如果parameterTypes为空则视为空数组,方法无形参

    • 如果方法名为"<init>“或”<clinit>",将会抛出异常NoSuchMethodException

匹配规则:

  • 如果该Class对象表示一个类或接口,则优先在当前类或接口中查找,匹配到对应方法就会返回

  • 如果Class对象表示的一个类或接口有父类或父接口,则递归调用匹配算法直到匹配对应方法并返回

  • 如果Class对象表示的一个类或接口中具有多个方法名和形参完全相同的public方法,则返回类型更具体的方法,将会被反射获取,否则会任意选择其中一个方法(虽然Java语言禁止一个类声明具有相同签名,但是返回类型不同的多个方法,但是java虚拟机不会禁止,虚拟机中增加灵活性可用于实现各种语言特性)

  • 如果Class对象表示数组,则此方法不会找到clone()方法

  • getMethod也可以获取Class对象表示的类或接口中的静态方法

@CallerSensitive
public Method getMethod(String name, Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException {
    checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
    Method method = getMethod0(name, parameterTypes, true);
    if (method == null) {
        throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
    }
    return method;
}

getConstructor()

getConstructor(Class<?>... parameterTypes)获取Class对象表示的类的public构造函数

parameterTypes表示构造函数的形参数组,按照声明顺序查找构造函数的形参。

  • 如果Class对象表示在非静态上下文中声明的内部类,则形参parameterTypes中外部类实例作为第一个形参(必须放在第一个,放在其他位置报错NoSuchMethodException)

    示例:

    public class MemberClass extends SuperClass{
    
        public MemberClass(String name, String sex){
    
        }
        public class InnerClass{
            private String inner;
            public InnerClass(String inner){
    
            }
        }
    }
    
    Constructor<MemberClass.InnerClass> constructor = MemberClass.InnerClass.class.getConstructor(MemberClass.class,String.class);
    System.out.println(constructor);
    //输出结果为:
    public com.carl.test.classObject.MemberClass$InnerClass(com.carl.test.classObject.MemberClass,java.lang.String)
    
  • 如果没找到匹配的构造函数,则抛出NoSuchMethodException

    @CallerSensitive
    public Constructor<T> getConstructor(Class<?>... parameterTypes)
        throws NoSuchMethodException, SecurityException {
        checkMemberAccess(Member.PUBLIC, Reflection.getCallerClass(), true);
        return getConstructor0(parameterTypes, Member.PUBLIC);
    }
    

getDeclaredClasses()

getDeclaredClasses()获取当前Class对象表示的类或接口中的所有已声明的类或接口,包括public、protected、private、default修饰的类和接口,但不包括继承的类和接口

  • 如果Class对象表示的类或接口没有声明任何类或接口作为成员,则返回长度为0的数组

  • 如果Class对象表示的是基本数据类型、数组或void,则返回长度为0的数组

@CallerSensitive
public Class<?>[] getDeclaredClasses() throws SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), false);
    return getDeclaredClasses0();
}

getDeclaredFields()

getDeclaredFields()获取当前Class对象表示的类或接口中所有已经声明的字段,包括public、protected、private、default修饰的字段,不包括继承的字段

  • 如果Class对象表示的类或接口没有声明任何字段作为成员,则返回长度为0的数组

  • 如果Class对象表示的是基本数据类型、数组或void,则返回长度为0的数组

@CallerSensitive
public Field[] getDeclaredFields() throws SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    return copyFields(privateGetDeclaredFields(false));
}

getDeclaredMethods()

getDeclaredMethods()获取当前Class对象表示的类或接口中所有已经声明的方法,包括public、protected、private、default修饰的方法,不包括继承的方法

  • 如果Class对象表示的类或接口没有声明任何方法作为成员,则返回长度为0的数组

  • 如果Class对象表示的是基本数据类型、数组或void,则返回长度为0的数组

@CallerSensitive
public Method[] getDeclaredMethods() throws SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    return copyMethods(privateGetDeclaredMethods(false));
}

getDeclaredConstructors()

getDeclaredConstructors()获取当前Class对象表示的类中所有已经声明的构造器,包括public、protected、private、default修饰的构造器,返回的数组中元素没有任何特定的顺序,默认构造函数也会包含在返回的数组中

  • 如果Class对象表示接口、基本数据类型、数组或void,则此方法都将返回长度为0的数组
@CallerSensitive
public Constructor<?>[] getDeclaredConstructors() throws SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    return copyConstructors(privateGetDeclaredConstructors(false));
}

getDeclaredField()\getDeclaredMethod()\getDeclaredConstructor()

getDeclaredField()获取指定的声明字段,name表示字段名,如果Class对象表示数组类型,则此方法不会找到该数组类型的length字段

getDeclaredMethod()获取指定的声明方法,name表示字段名,parameterTypes表示形参,注意事项参考getDeclaredMethods()

getDeclaredConstructor()获取指定的声明构造器,parameterTypes表示形参,注意事项参考getDeclaredConstructors()

@CallerSensitive
public Field getDeclaredField(String name)
    throws NoSuchFieldException, SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    Field field = searchFields(privateGetDeclaredFields(false), name);
    if (field == null) {
        throw new NoSuchFieldException(name);
    }
    return field;
}
@CallerSensitive
public Method getDeclaredMethod(String name, Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    Method method = searchMethods(privateGetDeclaredMethods(false), name, parameterTypes);
    if (method == null) {
        throw new NoSuchMethodException(getName() + "." + name + argumentTypesToString(parameterTypes));
    }
    return method;
}
@CallerSensitive
public Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
    throws NoSuchMethodException, SecurityException {
    checkMemberAccess(Member.DECLARED, Reflection.getCallerClass(), true);
    return getConstructor0(parameterTypes, Member.DECLARED);
}

  1. 每个Class文件的头4个字节(0xCAFEBABE)称为魔数(Magic Number),它的唯一作用是确定这个文件是否是Class文件,扩展名是可以随意改变的,为了安全,很多文件都采用了魔数进行身份识别 ↩︎

  2. 5~6位字节,表示次版本号。例如:次版本号为0x0003,0x0003的十进制等于3,次版本号为3 ↩︎

  3. 7~8位字节,表示主版本号;版本号采用的是大端序存储 ↩︎

  4. 常量池容量计数值,从1开始计数,在常量池中的第0项,通常用于表示“不引用任何一个常量池项目” ↩︎

  5. 访问标志:用于识别一些类或接口层次的访问信息 ↩︎

  • 38
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Carl·杰尼龟

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值