反射机制(笔记)

一、反射的基本概念

1.1. 反射机制的应用

  • 在运行时判断任意一个对象所属的类
  • 在运行时构造任意一个类的对象
  • 在运行时判断任意一个类所具有的成员变量和方法
  • 在运行时获取泛型信息
  • 在运行时调用任意一个对象的成员变量和方法
  • 在运行时处理注解
  • 生成动态代理

1.2. 反射相关api

java,lang.class: 代表一个类
java.lang.reflect.Method: 代表类的方法
java.lang.reflect.Field: 代表类的成员变量
java.lang.reflect.Constructor: 代表类的构造器
... ...

1.3. 反射的优缺点

优点:

  • 提高了Java程序的灵活性和扩展性,降低了拥合性,提高 自适应能力
  • 允许程序创建和控制任何类的对象,无需提前 硬编码 目标类

缺点:

  • 反射的性能较低。
    • 反射机制主要应用在对灵活性和扩展性要求很高的系统框架上
  • 反射会 模糊 程序内部逻辑,可读性较差 。

二、Class类的理解与类的加载

2.1. CLass类的理解

针对于编写好的.java源文件进行编译(使用javac.exe),会生成一个或多个.class字节码文件。接着,我们使用java.exe命令对指定的.class文件进行解释运行,这个解释运行的过程中,我们需要将class字节码文件加载(使用类的加载器)到内存中(存放在方法区)。加载到内存中的.class文件对应的结构即为CLass的一个实例。

比如,加载到内存中的Person类或string类或User类,都作为class的一个一个的实例

2.2. 获得CLass类的几种方式

	//1。调用运行时类的静态何性: cLass
	Class clazz1 = User.class;
	System.out.println(clazz1);

	//2. 调用运行时类的对象的getCLass()
	User u1 = new User();
	Class clazz2 = u1.getClass();

	//3. 调用CLass的静态方法forName(String className)
	String className = "com.tp._class.User"; //全类名
	Class clazz3 = Class.forName(className);
	System.out.println(clazz1 == clazz2);//true
	System.out.println(clazz1 == clazz3);//true

	//4. 使用类的加载器的方式 (了解)
	Class clazz4 = ClassLoader.getSystemClassLoader().loadClass(className);
	System.out.println(clazz1 == clazz4);//true

三、反射的应用

3.1. 创建运行时类的对象

3.1.1. 如何实现

通过Class的实例调用newInstance()方法即可

3.1.2. 需要满足什么条件

  1. 要求运行时类中必须提供一个空参的构造器
  2. 要求提供的空参的构造器的权限要足够
    1. public修饰符
    2. 默认修饰符,但必须在同一个包下

3.1.3. 在jdk9中标识为过时,替换成什么结构

通过Constructor类调用newInstance(...)

3.2. 获取运行时类的内部结构

3.2.1. 获取所有属性、所有方法、所有构造器(了解)

    Class clazz = Person.class;
    //getFields(): 获取到运行时类本身及其所有的父类中声明为public 权限的属性
    Field[] fields = clazz.getFields();
    for(Field f : fields){
        System.out.println(f);
    }

    //getDecLaredFieLds():获取当前运行时类中声的所有属性
    Field[] decLaredFields = clazz.getDeclaredFields();
    for(Field f : decLaredFields) {
        System.out.println(f);
    }

3.2.2. 获取父类、结构们、包、带泛型的父类、父类的泛型等

    Class clazz = Class.forName( "com.tp._class.Person");
    // 1.获取运行时类的父类
    Class superClass = clazz.getSuperclass();
    System.out.println(superClass);

    // 2.获取运行时类的带泛型的父类
    Type superclass = clazz.getGenericSuperclass();
    System.out.println(superclass);

    // 3.获取运行时类实现的接口
    Class[] interfaces = clazz.getInterfaces();
    for (Class c : interfaces) {
        System.out.println(c);
    }

    // 4.获取运行时类所在的包
    Package pack = clazz.getPackage();
    System.out.println(pack);

    // 5.获取运行时类的父类的泛型
    //如果父类是带泛型的,则可以强转为ParameterizedType
    ParameterizedType paramType = (ParameterizedType) superclass;
    //调用getActualTypeArguments()获取泛型的参数,结果是一个数组,因为可能有多个泛型参数。
    Type[] arguments = paramType.getActualTypeArguments();
    // 获取泛型参数的名称
    System.out.println(((Class)arguments[0]).getName());

posted @ 2023-03-16 11:03  Pearl...T  阅读(17)  评论(0编辑  收藏  举报