java:反射

课程:宋红康 JAVA

理解Class类并获取Class的实例

类的加载过程:

程序经过javac.exe命令以后,会生成一个或多个字节码文件(.class结尾)。接着我们使用java.exe命令对某个字节码文件进行解释运行。相当于将某个字节码文件加载到内存中。**此过程就称为类的加载**。

加载到内存中的类,我们就称为运行时类,此运行时类,就作为Class的一个实例。换句话说,Class的实例就对应着一个运行时类

加载到内存中的运行时类,会缓存一定的时间。在此时间之内,我们可以通过不同的方式来获取此运行时类

获取Class的实例的方式:

  1. 调用运行时类的属性:.class

    Class clazz1 = Person.class;
    
  2. 通过运行时类的对象,调用getClass()

    Person p1 = new Person();
    Class clazz2 = p1.getClass();
    
  3. 调用Class的静态方法:forName(String classPath)

    Class clazz3 = Class.forName("com.atguigu.java.Person");
    
  4. 使用类的加载器:ClassLoader (了解)

    ClassLoader classLoader = ReflectionTest.class.getClassLoader();
    Class clazz4 = classLoader.loadClass("com.atguigu.java.Person");
    

Class类的其他实例

可以作为Class的实例的并非只有类,只要时能加载的类的内存中的可以作为Class类的实例

Class c1 = Object.class;
Class c2 = Comparable.class; //(接口)
Class c3 = String[].class;
Class c4 = int[][].class;
Class c5 = ElementType.class;  //(枚举类)
Class c6 = Override.class;  //(注解)
Class c7 = int.class;
Class c8 = void.class; //(void也可以作为Class类的对象)
Class c9 = Class.class; //( Class也可以作为Class类的对象)
int[] a = new int[10];
int[] b = new int[100];
Class c10 = a.getClass();
Class c11 = b.getClass();
// 只要数组的元素类型与维度一样,就是同一个Class

类的加载与ClassLoader的理解

了解类的加载过程:

  1. 类的加载 load:将类的class文件读入内存,并为之创建一个java.lang.Class对象。此过程由类的加载器完成
  2. 类的链接 link:将二进制数据合并到JRE中
  3. 类的初始化 initialize:jvm负责对类进行初始化

类加载器

  1. 作用:将class文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时数据结构,然后再堆中生成一个代表着个类的java.lang.Class对象,作为方法区中类数据的访问入口。

  2. 类缓存:一旦某个类加载到加载器中,他会维持加载(缓存)一段时间。我么每声明同类型的Class类实际上的同一个对象。

  3. JVM规定的加载器类型:不同的类型会加载不同的类

    • Bootstap Classloader 引导类加载器:用C++编写的。是JVM自带的类加载器。复制Java平台核心库,用来装载核心类库。该加载器无法直接获取
    • Extension Classloader 扩展类加载器:它负责加载jre/lib/ext扩展库。它是ClassLoader的子类
    • Application Classloader 系统类加载器:它负责加载项目的classpath路径下的类。我们自定义的类就是他负责加载的。
    • 自定义类加载器:后面会见到的自定义类加载器:tomcat中
  4. 获取类的加载器:

    • Class的实例 . getClassLoader(),比如(ClassLoaderTest.class) . getClassLoader()

    • 获取上一级的加载器:classLoader.getParent()

  1. 利用类的加载器获取配置文件:classLoader.getResourceAsStream

创建运行时类的对象:newInstance()

创建运行时类的对象:运行时类.newInstance()

obj:没使用泛型或者强转时,得到的是一个Object类型

Class<Person>:泛型,指定newInstance()的返回值是Person

获取运行时类的完整结构

获取当前运行时类的属性结构

获取属性的所有信息

getFields():获取当前运行时类及其父类中声明为public访问权限的属性

getDeclaredFields():获取当前运行时类中声明的所有属性。(不包含父类中声明的属性)

获取属性的:权限修饰符 数据类型 变量名

权限修饰符

  • getModifiers():返回的是一个int型的值
  • Modifier.toString(modifier):利用这个方法可以把对应的数字翻译成对应的某个权限

数据类型:

  • getType():返回的是一个类型,如String类型,Person类型,是一个类,需要用Class接收
  • getName():值获取类名,如果不用这个方法,会把Class也答应出来

变量名:getName()

获取运行时类的方法结构

获取方法的所有信息

getMethods():获取当前运行时类及其所有父类中声明为public权限的方法

getDeclaredMethods():获取当前运行时类中声明的所有方法。(不包含父类中声明的方法)

获取方法的单个信息

方法里面包含:注解,权限修饰符 返回值类型 方法名(参数类型1 形参名1,…) throws XxxException{}

  • 获取注解:getAnnotations()
  • 获取返回值类型:getReturnType()
  • 获取形参列表:getParameterTypes(),也是各种类,所有要用Class接收
  • 获取抛出的异常:getExceptionTypes(),用Class接收

获取构造器结构

getConstructors():获取当前运行时类中声明为public的构造器

getDeclaredConstructors():获取当前运行时类中声明的所有的构造器

获取父类

获取运行时类的父类:getGenericSuperclass()

获取父类的泛型

获取运行时类的带泛型的父类的泛型:getActualTypeArguments();

获取接口

获取运行时类实现的接口:getInterfaces()

获取包

获取运行时类所在的包,getPackage()

获取注解

获取运行时类声明的注解:getAnnotations()

调用运行时类的指定结构

调用指定属性:

getField()):不需要掌握,因为只能获取调用public的属性

getDeclaredField(String fieldName):需要掌握

  • 获取Class的实例 Person.class
  • 创建运行时类的对象 clazz.newInstance()
  • 获取运行时类中指定变量名的属性 getDeclaredField(String fieldName)
  • 保证当前属性是可访问的 setAccessible(true)
  • 获取、设置指定对象的此属性值 :set(p,"Tom")
  • 获取当前属性的值 get()

调用指定的方法

getMethod():不需要掌握,因为只能获取调用public的属性

getDeclaredMethod(方法名,形参列表):需要掌握

  • 获取Class的实例 Person.class
  • 创建运行时类的对象 clazz.newInstance()
  • 获取指定的某个方法 getDeclaredMethod()
  • 保证当前方法是可访问的 setAccessible(true);
  • 调用方法并获得方法返回值 invoke()
  • 静态方法

调用指定的构造器

调用运行时类中的指定的构造器:getDeclaredConstructor(参数):指明构造器的参数列表


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 1909773034@qq.com

×

喜欢就点赞,疼爱就打赏