注解
- 作用:
- 不是程序本身,可对程序做出解释
- 可以被其他程序读取(如:编译器)
- 可附加在package,class,method,field等上面,相当于给他们添加额外辅助信息
- 可通过反射机制编程实现访问
内置注解
常见的:
都定义在java.lang包下
- @Override
- @Deprecated
- @SuppressWarning:用来抑制编译时的警告,但后面括号中需要参数
元注解
- 作用就是负责注解其他注解
- Java定义了4个标准的meta-annotation类型,用来对其他annotation类型做说明(@Target @Document @Inherited @Retention)
- @Target:描述注解使用范围
- @Retention:需要在什么级别保存该注释信息,用于描述注解的生命周期 SOURCE< CLASS < RUNTIME
只有在运行时注解还有效,这样才能读取到 - @Document:说明该注解将被包含在javadoc中
- @Inherited:说明子类可以继承父类中的该注解
例:@Target注解源码
package java.lang.annotation;
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
//表示该注解的参数
ElementType[] value();
}
public enum ElementType {
//可在类上起作用
TYPE,
//在一个字段上起作用
FIELD,
//可在方法上起作用
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
RetentionPolicy也是枚举类
自定义注解
- 格式 public @interface 注解名
- 其中每个方法实际上声明了一个配置参数
- 方法名称就是参数名称
- 返回值类型就是参数类型(返回值只能是基本类型,Class,String ,enum)
- 可以通过default来声明参数默认值
- 如果只有一个参数成员,一般参数名为value(value才可以省略参数名,直接赋值)
- 注解元素必须要有值,定义注解元素时,经常使用空字符串,0作默认值
反射
允许对构造方法,成员变量,成员方法的信息进行编程访问
idea的自动提示功能就是用反射来实现的
其中红色的为获取,蓝色的为解剖操作,获取字段,构造方法,成员方法是从class文件中获取的,所以首先要获取class对象
获取class对象
以下三种方式获得的class对象,为同一个
-
//使用全类名 Class.forName("全类名"); //使用的最多 //在就源代码阶段可以使用, .java --> .class期间
-
Student.class(); //一般当做参数进行传递 //加载阶段就可以使用 获取到字节码文件后将其加载进内存
-
Student s = new Student(); s.getClass(); //当我们已经有了这个类的对象时才可以使用 //到运行阶段才可以使用 创建对象后
获取构造方法
Class c1 = Class.forName("reflect.Student");
//获取所有公共构造方法
Constructor[] constructors = c1.getConstructors();
for (Constructor c : constructors) {
System.out.println(c);
}
System.out.println("----------");
//获取任意权限构造方法
Constructor[] con = c1.getDeclaredConstructors();
for (Constructor c: con) {
System.out.println(c);
}
System.out.println("-----------");
//获取单个公共构造方法
Constructor constructor = c1.getConstructor(int.class,String.class);
System.out.println(constructor);
System.out.println("--------------");
//获取单个任意权限构造方法
Constructor declaredConstructor = c1.getDeclaredConstructor(int.class);
System.out.println(declaredConstructor);
使用通过反射获得的构造方法创建对象
//括号中的参数要与使用的构造方法相对应
//若权限不够,可以暴力反射
con.setAccessible(true); //临时取消权限校验
Student s = (Student) con.newInstance(12, "lisi");
获取成员变量
Class<?> cl = Class.forName("reflect.Student");
Field[] fields = cl.getDeclaredFields();
for (Field f : fields) {
System.out.println(f);
}
//获取指定字段(任意权限)
Field age = cl.getDeclaredField("age");
System.out.println(age);
获取成员变量信息
//获取字段权限
int modifiers = age.getModifiers();
System.out.println(modifiers);
//获取字段数据类型
Class<?> type = age.getType();
System.out.println(type);
//获取字段名
String name = age.getName();
System.out.println(name);
//获取成员变量记录的值
//如果访问成员变量的权限不够,可以暴力反射
Student stu = new Student("李四");
stu.setAge(78);
age.setAccessible(true);
Object o = age.get(stu);
System.out.println(o);
//修改成员变量记录的值
age.set(stu,13);
Object o1 = age.get(stu);
System.out.println(o1);
获取成员方法
Class<?> cl = Class.forName("reflect.Student");
//获取指定方法,参数1:方法名 后面的参数:方法形参(用来区别重载方法)
Method method = cl.getDeclaredMethod("eat", String.class);
System.out.println(method);
执行获取到的方法
/**
* 执行当前方法 invoke
* 参数1:执行方法的对象
* 参数2:调用方法传递的参数
* 返回值:没有就不用获取
*/
Student stu = new Student();
method.setAccessible(true);
method.invoke(stu,"zhouzhou");
作用
- 获取一个类里面所有的信息,获取到了之后,再执行其他的业务逻辑
- 结合配置文件,动态的创建对象并调用方法