注解和反射
注解(Annotation)
什么是注解
注释是给人看的,注解是给机器看的
注解的作用
- 不是程序本身,但是可以对程序做出解释
- 可以被其他程序读取(比如: 编译器)
注解的格式
@注解名
Annotation的使用位置
package,class,method,field
内置注解
@override 重写
@deprecated 表示不推荐使用
@suppressWarning() 正压注解
元注解(meta-annotation)
作用
负责解释其他注解的注解
标准注解(四个)
@target 目标
@retention 表示注解的级别,
@Document 将会生成在javadoc当中
@inherited 子类可以继承本类注解
自定义注解可以有参数
参数类型 +参数名();
参数类型 + 参数名() default 默认值;
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface MyAnnotation02 {
String name() default "";
}
name为注解的参数名 ,default 后面的是默认值,如果我们不设置默认值,则使用注解额时候必须传参
反射
类加载
同一个字节码文件在运行过程中只会加载一次。通过下面三种方式获取的类对象都是一个对象。
获取类对象的三种方式
Class.forName("全类名");
类名.class;
对象.getClass();
第一种多用于 配置文件,将类名定义在配置文件中。读取文件,加载类
第二种多用于参数的传递
第三种多用于 对象的传递
什么时候进行类的初始化
类的主动引用
- 虚拟机启动,先初始化main方法所在的类
- new 一个对象
- 调用静态成员,(除final之外的常量)和静态方法
- 通过java.ang.reflect 包进行反射调用
- 当初始化一个类的时候如果父类没有被初始化,则先初始化其父类
类的被动引用(不会引发类的初始化)
- 当访问一个静态时,只有真正声明这个域的类才会被初始化。
- 如:当通过自雷引用父类的静态变量,不会导致子类初始化
- 当通过数组定义类的引用,不会触发类的初始化
- 引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常量池中了)
类加载器
-
引导类加载器(java的核心加载器)
- 名称: rt.jar 根加载器
- 位置:直接存在于jre文件夹下面
- 特点: 无法获取 通过C++编写的
- 作用: 用于装载核心类库
- 我们用的所有的基础类都在下面,
- lang包
- util包
- swing包
- ...
-
扩展加载器
-
名称: ext
-
位置: jre 下面的ext文件夹下面
-
特点: 目前未知(是我不知道,不是没有作用)
-
作用: 负责jre/lib/ext目录下的jar包或者-D java.ext.dirs 指定目录显得jar包装入工作库
-
获取:
-
ClassLoader.getSystemClassLoader().getParent();
-
-
-
系统加载器(用户类加载器)
-
名称: systemClassLoader (用户的类加载器)
-
位置: 当前工程下面
-
特点: 加载该工程的class文件
-
作用: 负责java -classpath 或 -D java.class.path所指的目录下的类与jar包装入工作,是最常用的加载器
-
获取:
-
ClassLoader.getSystemClassLoader();
-
-
-
获取类加载器可以加载的路径
-
String properties = System.getProperty("java.class.path"); String replace = properties.replace(";", "\n"); System.out.println(replace);
-
获取类名
Class a = Class.forName("com.ziop.relfect.User");
User user=new User;
a = user.getclass();
//获得类的名字
System.out.printin(a.getname());//获得包名+类名
System.out.println(a.getsimplename());//获得类名
获取属性名
a.getFields(); // 只能获取public 的属性
a.getFields("name"); // 获取指定的属性
a.getDeclaredFields(); //获取全部的属性 包括private
a.getDeclaredFields("name");
获取方法
a.getMethods(); //获得本类及其父类的所有方法 不包括私有
a.getDeclaredMethods(); //获得本类的所有方法 包括私有的
a.getMethods("getTest",); //第二个参数及其以后的参数,用以判断重载的方法
a.setDeclaredMethods("setTest",String.class);
获取构造器
a.getConstructors();
a.getDeclaredConstructors(); // 同上
a.getDeclaredConstructors(String.class,int.class); // 获取指定有参构造
动态创建对象
//创建无参构造器的对象
Class a = Class.forName("com.ziop.relfect.User");
User user = (User)a.newInstance();
// 创建有参的对象
Constructor constructor = a.getDeclaredConstructors(String.class,int.class); // 获取指定有参构造
User user2 = (User)constructor.newInstance("ziop",2021,20);
//通过反射调用普通方法
User user3 = (User)a.newInstance();
//获取一个普通方法
Method setName = a.setDeclaredMethods("setTest",String.class);
setName.invoke(user3,"ziop"); //invoke : 激活函数
//通过反射操作属性
User user4 = (User)a.newInstance();
Field name = a.getFeclaredField("name");
//如果属性是私有的,则直接设置会出错,提示访问不了,同过关闭程序的安全检测则可以更改
name.setAccessible(true); // 设置安全检测关闭
name.set(user4,"ziop")
关闭安全检测可以提高执行效率(但是不推荐使用)
name.setAccessible(true); // 设置安全检测关闭
获取泛型类型
method.getGenericParamaterTypes(); 获取参数类型
如果想要获取泛型里面的类型,则需要判断他是否属于一个参数化类型,如果是的话则提取出来
method.getgenericReturnType(); //获取返回值的泛型
反射操作注解
Class a = Class.forName("com.ziop.relfect.User");
a.getAnnotations(); //获取所有的注解
Ziop ziop = (Ziop)a.getAnnotations(ziop.class) // 获取指定的注解
String value = ziop.value(); // 获取指定的注解的值 value是 ziop注解中的一个字段