1 - 自定义注解
public @interface MyAnnotation {
}
2 - 使用
1.使用的语法格式:@类型名
2.可以出现在类上,属性上,方法上,变量上,注解上
3 - 常见注解
Override
只能注解方法,是给编译器参考的,和运行阶段无关,编译器看到这个注解会检查,如果不是重写父类的方法,会报错.就是个标识,内部 无代码
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
Deprecated
表示被修饰的元素过时,告诉程序员别用了
源码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
4 - 元注解
Target
@Target(ElementTypr.METHOD)
被修饰的注解只能出现在方法上
源码
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
Retention
@Retention(RetentionPolicy.SOURCE)
表示被修饰的注解只被保留在java源文件中
@Retention(RetentionPolicy.CLASS)
被保存在class文件中
@Retention(RetentionPolicy.RUNTIME)
保存在class文件中,并且可以被反射机制读取到
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
5 - 注解中的属性
注解中可以定义属性
数据类型 属性名()
public @interface MyAnnotation {
String name();
}
如果一个注解中有属性,使用该注解的时候必须给注解的
属性赋值,否则报错
@MyAnnotation(name="haha")
private static void dosome() {
}
default可以给属性设置默认值,如果有默认值可以不用赋值
String name() default "";
如果属性名是value,且注解中只有一个属性,那么value=可以省略
public @interface MyAnnotation {
String value() ;
}
@MyAnnotation("haha")
private static void dosome() {
}
多个属性,中间用,隔开
@MyAnnotation(value="haha",name="zhangsan")
private static void dosome() {
}
如果属性是一个数组或枚举:
public @interface MyAnnotation {
String[] value1();
Season value2();
}
//数组只有一个值,大括号可以省略
@MyAnnotation(value1={"haha","hehe"},value2=Season.SPRING)
private static void dosome() {
}
6 - 反射注解
创建一个注解
//该注解只能标注类
@Target(ElementType.TYPE)
//保留在class文件且可以被反射
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
String value();
}
给一个类加上注解
@MyAnnotation("hehe")
public class AnnotationTest {
public static void main(String[] args) {
dosome();
}
@MyAnnotation("haha")
private static void dosome() {
}
}
判断有无注解
isAnnotationPresent()
public static void main(String[] args) {
Class anno = Class.forName("javase.reflect.AnnotationTest");
//判断类上有无注解
if(anno.isAnnotationPresent(MyAnnotation.class)){
//获取注解
MyAnnotation myanno = (MyAnnotation) anno.getAnnotation(MyAnnotation.class);
System.out.println("类上的注解对象是:"+myanno);
}
//获取方法上的注解
Method method = anno.getDeclaredMethod("dosome");
if(method.isAnnotationPresent(MyAnnotation.class)){
MyAnnotation myanno2 = (MyAnnotation) method.getAnnotation(MyAnnotation.class);
System.out.println("方法上的注解对象是:"+myanno2);
}
}
调用对象注解的属性
String value = myanno2.value();
System.out.println(value);
7 - 注解在开发中的应用举例
需求:
有一个注解叫@ID
只能出现在类上,当类上有这个注解的时候,
这个类必须有个int类型的id属性,否则报错
@ID
public class User {
int id;
String name;
}
//自定义异常,没有id属性的时候报错
public class HaveNoIDException extends RuntimeException {
public HaveNoIDException() {
}
public HaveNoIDException(String message) {
super(message);
}
}
/*判断类上有无ID注解,有的话看有无int类型的id属性
如果没有,抛异常*/
public static void main(String[] args) throws ClassNotFoundException {
Class user = Class.forName("javase.reflect.User");
boolean flag = false;
if(user.isAnnotationPresent(ID.class)){
//有无id属性
Field[] fields = user.getDeclaredFields();
for (Field field:fields
) {
if("id".equals(field.getName()) && "int".equals(field.getType().getSimpleName())){
flag=true;
}
}
if(!flag){
throw new HaveNoIDException("没有id属性");
}
}
}