注解
元注解
@Inherited 注解可以被子类继承
@Documented 文档注释会包含在javadoc
@Retention 注释在什么时候生效 Runtime Class Sources
@Target 注释可以使用在什么地方
自定义注解
@Target({ElementType.TYPE,ElementType.METHOD})
@Rentention(RelenLionPolicy.RUNTIME)
@Interface MyAnnotation{
String value() defalut "";
int id() default -1;
String[] schools() default {"",""};
}
类加载和初始化分析
类的加载
一、加载
- JVM通过类的全限定名获取该类的二进制(Class)文件
- 将该二进制文件转化为运行时数据结构
- 在方法区中生成java.lang.Class对象,作为该数据结构的访问接口
二、连接
- 验证:验证该类是否有合理的数据结构,类数据是否符合JVM的要求
- 准备:在方法区中为静态变量(static)分配内存,并赋予默认值,如static int a = 100,a在准备阶段就被赋予了默认值0,静态常量(final static)在准备阶段就被赋予了值,例如final static a = 100,a变量在准备阶段就被赋值为100,而静态变量要等到类初始化才会被赋值
- 解析:将二进制数据中的符号引用替换为直接引用
三、初始化
执行所有被static修饰的代码,包括变量和代码块,如果是静态变量则设置初始值,如果是静态方法则按顺序执行静态方法的代码。
类的加载器
类通过加载器进行加载主要包括
根类加载器(BootStrap ClassLoader) 加载核心类库(rt.jar),用户无法获取
扩展类加载器(Extension ClassLoader) 加载扩展类jar包
系统类加载器(Application ClassLoader) 加载指令目录下的jar包
加载器的层级为:根类加载器>扩展类加载器>系统类加载器
当加载一个类的时候,较低层会逐级询问高层是否已加载该类
类的初始化
主动引用的时候会触发类的初始化
主动引用包括
- 系统执行main方法的时候
- new一个实例的时候
- 调用类的静态方法和静态变量(除final)的时候
- 使用反射创建对象的时候
- 一个类父类未被初始化,先初始化父类
类的被动引用
- 访问一个静态域,只有真正生命这个域的类才会被初始化,例如子类调用父类的静态方法不会被初始化
- 创建数组的时候不会初始化类
- 使用常量的时候不会被初始化
反射获得类
Class clazz = Class.forName("com.jun.Persion");
Class clazz = Persion.class;
Class clazz = student.getClass();
Class clazz = Integer.TYPE;
Perison.class;//类
Comparable.class;//接口
Overide.class;//注解
//数组维度和类型相同,则为同一个class
int[].class;//一维数组
int[][].class;//二维数组
ElementType.class;//枚举
Integer.class;//基本类型
void.class;//void
Class.class;//Class
反射常用方法
Class clazz = Class.forName("com.jun.User");
//获得构造器
Constructor constructor = clazz.getDeclaredConstructor(int.calss,String.class);
User user = (User)constructor.newInstance(20,"Bob");
//获得方法
Method method = clazz.getDeclaredMethod("setName",String.class);
method.invoke(user,"Tom");
//获得字段
Filed name = clazz.getDeclaredFiled("name");
name.setAccessible(false);
name.set(user,"Test");
//获得注解
clazz.getAnnotation(TableName.class);
clazz.getDeclaredField("name").getgetAnnotation(Detail.class);