JAVA注解

1.注解定义

也叫元数据,一种代码级别的说明,可以声明在包、类、字段、方法、局部变量、方法参数上,对这些元素进行说明,注释。

2.作用:

a.编写文档:通过代码里标识的元数据生成文档【生成javadoc文档】
例如@param,@author,@version
b.代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
c.编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
例如@Override覆盖重写,@Deprecated标记已过时,@SuppressWarnings压制警告,@FunctionalInterface (java8支持)标识一个匿名函数或函数式接口
d.跟踪代码依赖性:实现替代配置文件功能,比较常见的是spring 2.5 开始的基于注解配置,作用就是减少配置;

3.注解分类

3.1 JAVA自带的标准注解

3.1.1 @Override

如果试图使用 @Override 标记一个实际上并没有覆写父类的方法时,java 编译器会告警。

class Parent {
  public void test() {
  }
}


class Child extends Parent  {
   /**
         *  放开下面的注释,编译时会告警
         */
       /*
  @Override
  public void test() {
  }
*/
}
3.1.2 @Deprecated

用于标明被修饰的类或类成员、类方法已经废弃、过时,不建议使用。

@Deprecated
class TestClass {
  // do something
}

image.png

3.1.3 @SuppressWarnings

用于关闭对类、方法、成员编译时产生的特定警告。
抑制单类型警告

@SuppressWarnings("unchecked")  
public void addItems(String item){  
  @SuppressWarnings("rawtypes")  
   List items = new ArrayList();  
   items.add(item);  
}

抑制多类型警告

@SuppressWarnings(value={"unchecked", "rawtypes"})  
public void addItems(String item){  
   List items = new ArrayList();  
   items.add(item);  
}
3.1.4 @FunctionalInterface

用于指示被修饰的接口是函数式接口,在 JDK8 引入

@FunctionalInterface
public interface UserService {


void getUser(Long userId);
 

// 默认方法,可以用多个默认方法
public default void setUser() {
}

// 静态方法
public static void saveUser() {
}
@Override
// 覆盖Object中的equals方法
public boolean equals(Object obj);
}

函数式接口,也就是只有一个抽象方法的接口。上面的代码只有一个抽象方法getUser,不会报错,再增加一个抽象方法后就会报错,如下图:
image.png

3.2 元注解

注解注解的注解

3.2.1 @Retention

用来定义该注解在哪一个级别可用,在源代码中(SOURCE)、类文件中(CLASS)或者运行时(RUNTIME)
Retention源代码:
image.png
翻译指示带注释接口的注释要保留多长时间。如果注释接口声明上不存在Retention注释,则保留策略默认为RetentionPolicy.CLASS。

只有当元注释接口直接用于注释时,保留元注释才有效。如果元注释接口被用作另一个注释接口中的成员接口,则没有任何效果。
REtentionPolicy源代码
image.png
翻译SOURCE:注释将由编译器丢弃。
CLASS:注释将由编译器记录在类文件中,但不需要在运行时由VM保留。这是默认行为。
RUNTIME:注释由编译器记录在类文件中,并在运行时由VM保留,因此可以反射式读取。

3.2.2 @Documented

生成文档信息的时候保留注解,对类作辅助说明

@Documented
public @interface DocumentedMy {
    String value() default "这是一个自定义类";
}
@DocumentedMy
public class MyTest1 {
    public String getStr() {
        return "123";
    }
}

生成javadoc效果
image.png

3.2.3 @Target

用于描述注解的使用范围(即:被描述的注解可以用在什么地方)
image.png
image.png
image.png

public class MyInterface2 <@TypeParam T>{
 
    @Not long lon;
 
    @Test
    public <@TypeParam T extends Integer> void Test2(@Not String str){
        @Not boolean boo;
    }
 
    @Test
    public <@TypeParam T extends Integer> void Test1(){
 
    }
 
}
 
/**
 * jdk8为@Target元注解新增了两种类型:TYPE_PARAMETER   TYPE.USE
 * TYPE_PARAMETER:表示该注解能写在类型参数的声明语句中,泛型   例如:<@TypeParam T>
 * TYPE.USE:表示可以在任何用到类型的地方使用
 *
 **/
@Target(ElementType.TYPE_PARAMETER)
@interface TypeParam{
 
}
 
@Target(ElementType.TYPE_USE)
@interface Not{
 
}

![1D9U~%04NN}SUA8@E`)Z~5.png
标记了package的注解,并不是直接在类中的package上添加注解,而是在pakage-info中进行添加
image.png

3.2.4 @Inherited

说明子类可以继承父类中的该注解
表示自动继承注解类型。 如果注解类型声明中存在 @Inherited 元注解,则注解所修饰类的所有子类都将会继承此注解。
注解zhujie被@Inherited修饰
image.png
test类上添加该注解
image.png
test1类继承test类
image.png
然后获取test1类上的注解zhujie,发现可以获取到,说明test类上的注解zhujie被继承到test1类上了
image.png

3.2.5 @Repeatable

表示注解可以重复使用。
如果注解没有@Repeatable,在同一个地方使用相同的注解会报错,有了此元注解注解的注解,就可以在同一个地方使用相同的注解。
image.png
使用示例

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Values.class)
public @interface Value {
    String value() default "value";
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Values {
    Value[] value();
}

同一个地方使用相同注解就不会报错了
image.png
会将这两个value注解装进Values集合中。
一些约束:
1.@Repeatable 所声明的注解,其元注解@Target的使用范围要比@Repeatable的值声明的注解中的@Target的范围要大或相同,否则编译器错误,显示@Repeatable值所声明的注解的元注解@Target不是@Repeatable声明的注解的@Target的子集
image.png
2.@Repeatable注解声明的注解的元注解@Retention的周期要比@Repeatable的值指向的注解的@Retention得周期要小或相同。
image.png

3.3 自定义注解

3.3.1 格式

元注解:
pubulic @interface 注解名称{
属性
}

3.3.2 属性

即接口中的抽象方法
要求
第一,在定义注解时,不能继承其他的注解或接口。
第二,只能用 public 或 默认(default) 这两个访问权修饰.例如,String value();这里把方法设为 defaul 默认类型;
第三,参数成员只能用基本类型 byte,short,char,int,long,float,double,boolean 八种基本数据类型 和 String,Enum,Class,annotations 等数据类型,以及这一些类型的数组.例如,String value();这里的参数成员就为String;
第四,如果只有一个参数成员,最好把参数名称设为"value",这样在使用注解时就可以从
value = “XXX” 省略为 “XXX”。
image.pngimage.png
第五,定义了属性,在使用时需要给属性赋值,定义属性时可以使用default进行赋值
image.png

3.3.3 在程序中使用(解析)注解

1.获取注解存在的类的class对象

a.Class.forName(String className),多用于配置文件,将全类名写在配置文件中,读取配置文件生成Class对象。
b.类名.class,多用于参数传递,比如需要传递某个类的Class对象。
c.对象.getClass
2.根据注解所在位置(类,方法,变量),通过反射获取该对象
1.获取构造器image.png
构造器作用:通过构造器创建对象
如果是获取的私有构造器,那么使用该构造器创建对象前需要使用暴力反射,即构造器.setAccessible(ture)
image.png
2.获取成员变量
getFields()
getField(String name)
getDeclaredFields()
getDeclaredField(String name)
成员变量作用:通过成员变量取值与赋值
注意:成员变量不能孤立存在,需要有对象依托!
如果是私有变量在赋值之前也需要进行暴力反射
image.png
3.获取成员方法
image.png
成员方法作用:通过成员方法运行方法
注意:成员方法执行时也需要对象进行依托!
方法也需要和对象进行绑定,如果是私有方法也需要setAccessible(ture)来暴力反射
image.png
3.使用对象.getAnnotation()获取注解对象
4.使用注解对象的抽象方法获取注解配置的属性值
image.png

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值