Java基础:注解【详解】

一、注解

1.1注解的概念

注解(Annotation),也叫 元数据 (metadata)。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。

Java 语言中的类、 构造器、 方法、成员变量、局部变量、方法参数等都可以被注解进行标记,然后做特殊的处理。

1.2注解的应用

  1. 生成文档:java最早的提供的注解
  2. 编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】
  3. 代码分析:通过代码里标识的元数据对代码进行分析【使用反射】
  4. 替代配置文件:跟踪代码依赖性,实现替代配置文件功能,比较常见的是spring 2.5 开始的基于注解配置,作用就是减少配置

1.3注解的分类

1.3.1基本内置注解

@Override : 它的作用是对覆盖超类中方法的方法进行标记,如果被标记的方法并没有实际覆盖超类中的方法,则编译器会发出错误警告。

public class Parent {
    public Parent(){
        System.out.println("父亲构造器");
    }
    static {
        System.out.println("父亲静态块");
    }
    {
        System.out.println("父亲代码块");
    }
    public void test(){
        System.out.println("Parent");
    }
    
    public static void main(String[] args) {
        Parent parent = new Child();
        parent.test();
        /* 输出结果:
        父亲静态块
        儿子静态块
        父亲代码块
        父亲构造器
        父亲代码块
        儿子构造器
        Child
        */
    }
}

class Child extends Parent{
    public Child(){
        System.out.println("儿子构造器");
    }
    static {
        System.out.println("儿子静态块");
    }
    {
        System.out.println("父亲代码块");
    }
     /**
      *  放开下面的注释,编译时会告警
      */
    @Override
    public void test() {
        System.out.println("Child");
    }
}

@Deprecated : 它的作用是对不应该再使用的方法添加注解,当编程人员使用这些方法时,将会在编译时显示提示信息

@SuppressWarnings (“unchecked”): 用于关闭对类、方法、成员编译时产生的特定警告。

其参数有:

参数作用
deprecation使用了过时的类或方法时的警告
unchecked执行了未检查的转换时的警告
fallthrough当 switch 程序块直接通往下一种情况而没有 break 时的警告
path在类路径、源文件路径等中有不存在的路径时的警告
serial当在可序列化的类上缺少serialVersionUID 定义时的警告
finally任何 finally 子句不能正常完成时的警告
all关于以上所有情况的警告

@FunctionalInterface: Java8支持,标志一个匿名函数或者函数式接口。 有且仅有一个抽象方法,但是可以有多个非抽象方法的接口

1.3.2自定义注解

概念: 自己做一个注解来使用

格式:

public @interface 注解名称{
    public 属性类型 属性名称() default 默认值;
}

流程:

  1. 定义注解——相当于定义标记;
  2. 配置注解——把标记打在需要用到的程序代码中;
  3. 解析注解——在编译期或运行时检测到标记,并进行特殊操作。

注意:

  • 访问修饰符必须为public,不写默认为public;
  • 该元素的类型只能是一部分数据类型、String、Class、枚举类型、注解类型(体现了注解的嵌套效果)以及上述类型的一位数组;
  • 该元素的名称一般定义为名词,如果注解中只有一个元素,请把名字起为value(后面使用会带来便利操作);
  • ()不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法;
  • default代表默认值,值必须和第2点定义的类型一致;
  • 如果没有默认值,代表后续使用注解时必须给该类型元素赋值。

1.3.3元注解

概念: 修饰注解的注解

元注解功能描述
@Retention申明注解的生命周期
@Target约束自定义注解只能在哪些地方使用
@Inherited标注注解可以被继承类获取
@Repeatable表示注解可以重复使用。
@Documented生成文档信息的时候保留注解,对类作辅助说明
@Target(ElementType.FIELD)
/** 
可使用的值都在ElementType枚举类中,常用的值如下:
TYPE:类、接口
CONSTRUCTOR:构造器
FIFLD:成员变量
METHOD:成员方法
PARAMETER:方法参数
LOCAL_VARIABLE:局部变量
ANNOTATION_TYPE:注解类型
PACKAGE:包
*/

@Retention(RetentionPolicy.RUNTIME)
/**
可使用的值都在RetentionPolicy枚举类中,常用的值如下:
SOURCE:注解只作用在源码阶段,编译就丢弃,生成的字节码文件中不存在。
CLASS:注解只作用在源码阶段\字节码文件阶段,运行阶段(jvm加载)不存在(默认值)。
RUNTIME:注解作用在源码阶段\字节码文件阶段\运行阶段(开发常用)。
*/

1.4注解的解析

注解的解析就是判断类、成员变量等上面是否存在注解,存在注解就解析出内容。

注解的解析相关的接口:

Annotation: 注解的顶级接口,注解都是Annotation类型的对象;
AnnotatedElement:该接口定义了与注解解析相关的解析方法;

方法说明
Annotation[] getDeclaredAnnotations()获得当前对象上使用的所有注解,返回注解数组
T getDeclaredAnnotation(Class<T> annotationClass)根据注解类型获得对应注解对象
boolean isAnnotationPresent(Class<Annotation> annotationClass)判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
Method[] getDeclaredMethods()获取Class对象的所有方法
Field[] getDeclaredFields()获取Class对象的所有属性
Class<?>[] getDeclaredClasses()获取Class对象的所有Claas对象

所有的类成分Class, Method , Field , Constructor,都实现了AnnotatedElement接口他们都拥有解析注解的能力

解析注解的技巧:
注解在哪个成分上,我们就先拿哪个成分对象。

  • 注解作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解;
  • 注解作用在类上,则要该类的Class对象,再来拿上面的注解;
  • 注解作用在成员变量上,则要获得该成员变量对应的Field对象,再来拿上面的注解;

二、自定义注解

2.1概念

当我们理解了内置注解, 元注解和获取注解的反射接口后,我们便可以开始自定义注解了。

创建自定义注解和创建一个接口相似,但是注解的interface关键字需要以@符号开头,我们可以为注解声明方法。

格式:

// 元注解
public @interface 注解名称{
    // 属性列表
    public 属性类型 属性名称() default 默认值;
}

2.2自定义注解的使用

自定义注解:

import java.lang.annotation.*;

@Target({ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface DemoAnnotaion {
    String value() default "";
}

数据模型使用注解:

import com.shenxm.annotation.DemoAnnotaion;
import com.shenxm.common.PoBase;
import lombok.Data;

@Data
public class User extends PoBase {
    @DemoAnnotaion(value = "xiaoming")
    private String name;
    @DemoAnnotaion(value = "18")
    private String age;

    @DemoAnnotaion("22")
    public User setAge(String age) {
        this.age = age;
        return this;
    }
}

注解解析:

import com.shenxm.annotation.DemoAnnotaion;
import com.shenxm.po.User;
import org.junit.Test;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class DemoTest {
    @Test
    public void test1() {
        //反射获取Class对象
        User user = new User();
        Class<? extends User> userClazz = user.getClass();
        // 获取User类的所有方法和属性
        Method[] methods = userClazz.getMethods();
        Field[] declaredFields = userClazz.getDeclaredFields();
        try {
            // 遍历方法
            for (Method m : methods) {
                // 判断是否被注解标注的方法
                if (m.isAnnotationPresent(DemoAnnotaion.class)) {
                    //获取注解
                    DemoAnnotaion annotation = m.getAnnotation(DemoAnnotaion.class);
                    //调用这个方法
                    m.invoke(user, annotation.value());
                }
            }
            // 遍历属性
            for (Field f:declaredFields) {
                if (f.isAnnotationPresent(DemoAnnotaion.class)){
                    DemoAnnotaion annotation = f.getAnnotation(DemoAnnotaion.class);
                    // 启动访问
                    f.setAccessible(true);
                    // 为属性设置新值
                    f.set(user,annotation.value());
                }
            }
        } catch (Exception e) {
            System.out.println("调用异常");
        }
        //结果:User(name=xiaoming, age=18)
        System.out.println(user);
    }
}
  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值