【狂神说Java】注解和反射

1、反射让Java变成了半动态语言

2、反射介绍

反射总体有两种作用:获得类的信息、生产动态代理(AOP、框架有用)
3、反射优缺点

4、反射主要API

5、Class类

6、获得Class对象的方法
(1)getClass() 实例对象 ---> 全类名
假设CA类的对象a,
则a.getClass()返回CA类对应的Class类对象classA,
Class类的toString()被重写了,a.getClass().toString()返回classA存储的全类名(CA类的全类名)
(2)Class.forName() 全类名---> Class对象
(3)类名.class
(4)包装类.TYPE 返回基本类型名,如int

7、Class类的常用方法

8、哪些对象有Class对象

9、从内存分析反射过程



生成Class对象,是在加载阶段
生成静态变量并对其初始化(已经知道变量类型了),是在链接阶段
静态代码的执行、类的初始化、创建类的实例,是在初始化阶段
10、类的初始化

会引起类初始化的情况有以上五种,对于这5种会触发类进行初始化的场景,虚拟机规范种使用了一个很强烈的限定语:"有且只有",这5种场景中的行为称为对一个类进行主动引用。除此之外的所有引用类的方式都不会触发类的初始化,称为被动引用。
不会引起类初始化的情况:
(1)子类引用父类的静态变量,子类不会初始化,父类会初始化
????(2)定义某个类的数组,如People[] peoples = new People[10]
(3)引用常量、static final等放入常量池中的数据
总之,以上几种行为都是在链接阶段就可以完成、不涉及类初始化的行为。
11、类加载器的作用





12、各种类加载器的继承关系


13、双亲委派机制
(1)参考 https://www.cnblogs.com/luckforefforts/p/13642685.html

(2)参考中有这么一句话,“如果开发者尝试编写一个与rt.jar类库中重名的Java类,可以正常编译,但是永远无法被加载运行。”
测试如下:


(3)参考文章中,“从JDK1.2之后,双亲委派模式已经被引入到类加载体系中,自定义类加载器时不需要在自己写双亲委派的逻辑,因此不鼓励重写loadClass方法,而推荐重写findClass方法。”

loadClass()写着双亲委派机制的过程,不鼓励重写oladClass()表明不推荐打破双亲委派机制
按照loadClass()的逻辑,如果自带的类加载器都无法加载,才可以使用findClass(),即自定义的类加载器。自定义的类加载器也是ClassLoader的子类,所以也算是扩展了双亲委派机制。
如果要可以破坏双亲委派机制,可以重写loadClass(),见参考文章中的代码。
(4)双亲委派机制的弊端
参考文章中,“双亲委派模式很好地解决了各个类加载器的基础类统一问题,越基础的类由越上层的类加载器进行加载,但是这个基础类统一有一个不足,当基础类想要调用回下层的用户代码时无法委派子类加载器进行类加载。为了解决这个问题JDK引入了ThreadContext线程上下文,通过线程上下文的setContextClassLoader方法可以设置线程上下文类加载器。”
另有百度到的以下解释,
检查类是否加载的委派过程是单向的, 这个方式虽然从结构上说比较清晰,
使各个 ClassLoader 的职责非常明确, 但是同时会带来一个问题, 即顶层的
ClassLoader 无法访问底层的 ClassLoader 所加载的类
通常情况下,启动类加载器中的类为系统核心类,包括一些重要的系统接口,而在应用类加载器中,为应用类。
按照这种模式,应用类访问系统类自然是没有问题,但是系统类访问应用类就会出现问题。
比如在系统类中提供了一个接口, 该接口需要在应用类中得以实现, 该接口还绑定一个工厂方法,用于创建该接口的实例, 而接口和工厂方法都在启动类加载器中。这时,就会出现该工厂方法无法创建由应用类加载器加载的应用实例。
14、Class类的常用方法
Field[] getFields()
返回一个包含Field对象的数组,存放该类或接口的所有可访问公共属性(含继承的公共属性)。
Field[] getDeclaredFields()
返回一个包含Field对象的数组,存放该类或接口的所有属性(不含继承的属性)。
Field getField(String name)
返回一个指定公共属性名的Field对象。
Method[] getMethods()
返回一个包含Method对象的数组,存放该类或接口的所有可访问公共方法(含继承的公共方法)。
Method[] getDeclaredMethods()
返回一个包含Method对象的数组,存放该类或接口的所有方法(不含继承的方法)。
Constructor[] getConstructors()
返回一个包含Constructor对象的数组,存放该类的所有公共构造方法。
Constructor getConstructor(Class[] args)
返回一个指定参数列表的Constructor对象。
Class[] getInterfaces()
返回一个包含Class对象的数组,存放该类或接口实现的接口。
T newInstance()
使用无参构造方法创建该类的一个新实例。
String getName()
以String的形式返回该类(类、接口、数组类、基本类型或void)的完整名。
15、利用反射创建对象


16、利用反射调用方法修改属性


利用反射不但可以访问类的私有属性、方法、构造器,还可以使用私有构造器创建对象,重新设置私有属性的值,调用私有方法。

具体代码参考
https://blog.csdn.net/gao_zhennan/article/details/123828322
https://blog.csdn.net/kaszxc/article/details/109395102
17、利用反射获取泛型


参考: https://zhuanlan.zhihu.com/p/69132741
18、利用反射获取注解信息
ORM,使用注解将类与表进行映射
学到Spring和mybatis的时候再回来看一下