Annotation

作用:可以被其他程序(如编译器)读取
@SuppressWarnings(),镇压警告,含参(看源码)
自定义注解:
@Target(value={…}):表示注解用在哪些地方
@Retention(value={…}):表示注解在哪些地方有效(runtime>class>sources)
@Documented:表示是否将注解生成在javadoc中
@Inherited:表示子类可以继承注解

Reflection

优点:动态创建对象和编译,灵活
缺点:影响性能
主要API:java.lang.class
一个数据类型只有一个Class,任何类型都有class

例:JavaSE2021_study\注解与反射\src\com\qihang\Reflection\反射获得Class类.java

Java内存分析

1622268739610-2021-05-29 141137

类加载过程

1622268942588-2021-05-29 141516

1
2
3
4
5
6
7
8
9
Load:如图
Link:1-验证:确保加载的类符合JVM规范,没有安全方面的问题
2-准备:正式为类变量(static)分配内存并设置类变量默认初始值的阶段,这些内存都将在方法区中进行分配
3-解析:虚拟机常量池中的符号引用(常量名)替换为直接引用(地址)的过程
Initialize:
->执行类构造器<clinit>()方法的过程。类构造器<clinit>()方法是由编译器自动收集类中所有类变量的
赋值动作和静态代码块中的语句合并产生的。(类构造器是构造类信息的,不是构造类对象的构造器)
->当初始化一个类的时候,如果发现其父类还没初始化,则需要触发器父类的初始化
->虚拟机会保证一个类的<clinit>()方法在多线程环境中被正确加锁和同步

例:JavaSE2021_study\注解与反射\src\com\qihang\Reflection\Test02.java

什么时候发生类的初始化

1.类的主动引用(一定会发生类的初始化)

  • 当虚拟机启动先初始化main所在的类
  • new 一个类的对象
  • 调用类的静态成员(除了final常量)和方法
  • 使用java.lang.reflect包中的方法对类进行反射调用
  • 当初始化一个类,如果父类没有被初始化,则先初始化它的父类

2.类的被动引用

  • 当访问一个静态域时,只有真正声明这个域的类才会被初始化,如:当通过子类引用父类的静态常量,不会导致子类初始化
  • 通过数组定义类引用,不会触发此类的初始化
  • 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
1
2
3
4
5
6
7
8
9
Class c1=Class.forName("...");

Field[] fields=c1.getFields();//只能获得public属性
fields=c1.getDeclaredFields();//获得全部属性
c1.getMethods();//获得方法
c1.getDeclaredmethods();
c1.getConstructor();
c1.getDeclredConstructor();

动态创建对象(反射)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Class c1=Class.forName("...User");

//利用无参构造创建(保证类里写了无参构造)
User user=(User)c1.newInstance();
//利用指定构造器
Constructor con=c1.getDeclaredConstructor(...);
User user=(User)con.newInstande(...);

//通过反射操作方法:
User user=(User)c1.newInstance();
Method m=c1.getDeclaredMethod(...);
//invoke激活并传参
m.invoke(user,"..." or ...);

//提升代码效率:
method.setAccessible(true);