开始时间:2021-02-21
注解
注解在Java中有,在Python中也有类似的,可以参考一下装饰器部分的注解
自定义注解
package BUPT20210222;
public @interface MyAnnotation {
}
[修饰符列表] @interface 注解类型名
Override注解
属于标志性注解,给编译器做参考
package BUPT20210222;
public class AnnotationTest {
//@Override就是自带的一种注解
//起到的作用是监督重写的方法是否是父类的方法
//如果不是就会报错,
//属于标志性注解,给编译器做参考
@Override
public String toString() {
return "AnnotationTest{}";
}
}
Override源代码如下
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
可以观察到这个注解的注解,说明了注解只能用在方法上
不能用在类上
元注解
注解的注解被称为元注解
常见的元注解就是Target和Retention
Target标明注解能标在哪些地方上
Retention标明注解最终保存在哪些地方(Java源文件或者其他什么地方)
Deprecated注解
Deprecated注解用于标明已经过时的用法
以以下代码为例,当加了这个注解后
调用方法就会多一个横线
package BUPT20210222;
public class AnnotationTest02 {
public static void main(String[] args) {
doSome();
AnnotationTest02 annotationTest02 = new AnnotationTest02();
annotationTest02.doOther();
}
@Deprecated
private static void doSome() {
System.out.println("do Sth");
}
@Deprecated
public void doOther() {
System.out.println("do Other!");
}
}
如果是在其他类调用方法,那么在代码本身上也会增加横线
注解中定义属性
package BUPT20210222;
public @interface MyAnnotation {
//这里的name()不是方法是属性
//要求使用这个注解的时候一定要在括号里协商
//(name="XXX")这种格式,否则就要报错
//有多个注解,就用逗号隔开,加了default默认值的话,可以不写
String name();
String color();
int age() default 21;
}
package BUPT20210222;
public class AnnotationTest03 {
public static void main(String[] args) {
@MyAnnotation(name = "这是一个name()要求的格式",color = "红色")
AnnotationTest02 annotationTest02 = new AnnotationTest02();
annotationTest02.doOther();
}
}
特殊情况,属性名为 “value”
package BUPT20210222;
public @interface MyAnnotation2 {
String value();
}
当属性名为Value时,不需要写 value=
但只能有这一个属性,不能再加其他属性了,加了就不行了。
但加了的属性提供了默认值,只用value属性时也可以用
Deprecated的源码分析
现在来回顾一下Deprecated的源码
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
public @interface Deprecated {
首先看@Retention
里面没有加name=的格式,说明了定义的是value属性
进入源码看一看
public @interface Retention {
/**
* Returns the retention policy.
* @return the retention policy
*/
RetentionPolicy value();
}
采用了.RUNTIME的形式,说明使用的是一个枚举类型
SOURCE不会在编译中保留下来
Class会被记录在字节码文件中
RUNTIME可以被编译器记录下来并且放虚拟机,同时可以被反射
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
再看
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, MODULE, PARAMETER, TYPE})
可以看出value是一个数组,并且每个数组元素都是枚举
为了方便,将源码中的注释删掉了
public @interface Target {
ElementType[] value();
}
public enum ElementType {
/** Class, interface (including annotation type), enum, or record
* declaration */
TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE, TYPE_PARAMETER, TYPE_USE, MODULE,
@jdk.internal.PreviewFeature(feature=jdk.internal.PreviewFeature.Feature.RECORDS,
essentialAPI=true)
RECORD_COMPONENT;
}
反射注解
package BUPT20210222;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//只允许注解标注类和方法
@Target({ElementType.METHOD, ElementType.TYPE})
//允许注解被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation03 {
}
获取类上面的注解
首先写注解的时候就要允许被反射,用Runtime
package BUPT20210222;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//允许注解被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation03 {
String value();
String name() default "zhangsai";
}
package BUPT20210222;
//将注解写在类上
@MyAnnotation03("123")
public class AnnotationTest03 {
public static void main(String[] args) throws Exception {
//反射获取该类
Class c = Class.forName("BUPT20210222.AnnotationTest03");
if (c.isAnnotationPresent(MyAnnotation03.class)) {
//要加一个强制转型
MyAnnotation03 myAnnotation03 = (MyAnnotation03) c.getAnnotation(MyAnnotation03.class);
//可以直接读取属性
System.out.println(myAnnotation03.name());
}
}
}
获取方法上面的注解
首先要获取类,才能进一步获取方法
package BUPT20210222;
import java.lang.reflect.Method;
public class AnnotationTest03 {
//将注解写在方法上
@MyAnnotation03("abc")
private static void doSome() {
}
public static void main(String[] args) throws Exception {
//反射获取该类
Class c = Class.forName("BUPT20210222.AnnotationTest03");
//多一个步骤,先获取类,再获取方法
Method method = c.getDeclaredMethod("doSome");
if (method.isAnnotationPresent(MyAnnotation03.class)) {
//要加一个强制转型
MyAnnotation03 myAnnotation03 = (MyAnnotation03) method.getAnnotation(MyAnnotation03.class);
//可以直接读取属性
System.out.println(myAnnotation03.value());
}
}
}
注解在反射中的一个应用
假设,需要一个注解来标记类,被标注的类必须有一个int类型的id属性,如果没有就报异常
先定义该注解
package BUPT20210222;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//该注解只能出现在类上面
@Target(ElementType.TYPE)
//该注解可以被反射机制读取到
@Retention(RetentionPolicy.RUNTIME)
@interface MustHasIdPropertyAnnotation {
}
然后定义用户类User
package BUPT20210222;
@MustHasIdPropertyAnnotation
//加了这个注解,就必须把下面的int id写上`在这里插入代码片`
public class User {
int id;
String name;
String password;
}
定义异常类
package BUPT20210222;
public class HasNotIdPropertyException extends Exception {
public HasNotIdPropertyException(String s) {
super(s);
}
public HasNotIdPropertyException() {
}
}
写一个测试类
package BUPT20210222;
import java.lang.reflect.Field;
public class Test {
public static void main(String[] args) throws Exception {
Class userClass = Class.forName("BUPT20210222.User");
boolean isOk = false;//给一个默认标记
//首先判断用户类上面是否有这个注解
if (userClass.isAnnotationPresent(MustHasIdPropertyAnnotation.class)) {
//读取类中的所有字段
Field[] fields = userClass.getDeclaredFields();
//如果字段中有int id,就把标记改为true
for (Field field : fields) {
if ("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())) {
isOk = true;
break;
}
}
//判断是否合法
if (!isOk) {
throw new HasNotIdPropertyException("报异常");
}
}
}
}
结束时间 2021-02-22