侧边栏壁纸
博主头像
张种恩的技术小栈博主等级

行动起来,活在当下

  • 累计撰写 742 篇文章
  • 累计创建 64 个标签
  • 累计收到 39 条评论

目 录CONTENT

文章目录

Java中注解的使用

zze
zze
2018-12-25 / 0 评论 / 0 点赞 / 634 阅读 / 6893 字

不定期更新相关视频,抖音点击左上角加号后扫一扫右方侧边栏二维码关注我~正在更新《Shell其实很简单》系列

介绍

概述

注解和接口、类一样,都是属于数据类型。

注解可以在变量、方法、类之上加载。

注解可以有属性,也可以没有属性。

注解有作用范围(源码、编译、运行)。

  • 源码期间有效:@Author@See@Since
  • 编译期间有效:@Override@Deprecated@Suppresswarning
  • 运行期间有效:@Test

注解的作用

一般用作配置。

什么时候用注解来配置?

  • 如果配置信息不容易发生修改,例如 servlet 映射路径,这时候就可以使用注解形式配置。

使用

元注解

Java 提供元注解的目的就是让开发者自定义注解,元注解负责注解自定义注解。

@Target

@Target 用来说明自定义的注解可以用在什么地方。

ElementType 取值有:

  1. CONSTRUCTOR:用于描述构造器。
  2. FIELD:用于描述域 。
  3. LOCAL_VARIABLE:用于描述局部变量 。
  4. METHOD:用于描述方法 。
  5. PACKAGE:用于描述包 。
  6. PARAMETER:用于描述参数 。
  7. TYPE:用于描述类、接口(包括注解类型) 或enum声明。

例:

@Target(ElementType.FIELD)

@Retention

@Retention 用来描述自定义注解的生命周期。

RetentionPoicy 取值有:

  1. SOURCE:在源文件中有效。
  2. CLASS:在 class文件 中有效。
  3. RUNTIME:在运行时有效。

例:

@Retention(RetentionPolicy.RUNTIME)。

@Documented

@Documented 用于表示自定义注解可以被 javadoc 之类的工具文档化,没有成员。

@Inherited

@Inherited 元注解是一个标记注解,@Inherited 阐述了某个被标注的类型是被继承的。如果一个使用了 @Inherited 修饰的 annotation 类型被用于一个 class,则这个 annotation 将被用于该 class 的子类。

@Inherited annotation 类型是被标注过的 class 的子类所继承。类并不从它所实现的接口继承 annotation,方法并不从它所重载的方法继承 annotation。

@Inherited annotation 类型标注的 annotation 的 RetentionRetentionPolicy.RUNTIME,则反射 API 增强了这种继承性。如果我们使用 java.lang.reflect 去查询一个 @Inherited annotation 类型的 annotation 时,反射代码检查将展开工作:检查 class 和其父类,直到发现指定的 annotation 类型被发现,或者到达类继承结构的顶层。

自定义注解

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

import java.util.Date;

// 自定义一个注解
public @interface MyAnnotation01 {
    // 定义属性
    public String test();
    // 带默认值的属性
    public Class c() default Date.class;
}

注解中定义的属性支持的类型有:基本数据类型、String、Class、annotation(注解类型)、enum(枚举类型)以及以上类型的一维数组类型。
java 的基本数据类型有 8 种:byte(字节型)、short(短整型)、int(整型)、long(长整型)、float(单精度浮点型)、double(双精度浮点型)、boolean(布尔型)、char(字符型)。

对应包装类:java.lang.Bytejava.lang.Shortjava.lang.Integerjava.lang.Longjava.lang.Floatjava.lang.Doublejava.lang.Booleanjava.lang.Character

可分为四类:

  • 整型:byteshortintlong
  • 浮点型:floatdouble
  • 逻辑型:boolean
  • 字符型:char

示例

通过注解给字段赋值

// com.zze.annotation.StrField
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(value = ElementType.FIELD)
public @interface StrField{
    public String value();
}
// com.zze.annotation.IntField
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(value = ElementType.FIELD)
public @interface IntField{

    public int value();
}
// com.zze.bean.User
import com.zze.annotation.IntField;
import com.zze.annotation.StrField;

public class User {
    @StrField(value = "张三")
    private String name;
    @IntField(value = 18)
    private Integer age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
// com.zze.test.AnnoTest
import com.zze.annotation.IntField;
import com.zze.annotation.StrField;
import com.zze.bean.User;
import org.junit.Test;

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

@SuppressWarnings("all")
public class AnnoTest {
    @Test
    public void test1() throws Exception {
        // 实例化对象
        User user = new User();
        setValues(user);
        System.out.println(user);
        // User{name='张三', age=18}
    }

    /**
     * 通过对象类上的注解给对象字段赋值
     */
    private void setValues(User user) throws Exception {
        Class clazz = user.getClass();
        // 获取所有字段
        for (Field declaredField : clazz.getDeclaredFields()) {
            Object currentValue = null;
            // 如果当前字段上有 StrField 注解
            if (declaredField.isAnnotationPresent(StrField.class)) {
                StrField annotation = declaredField.getAnnotation(StrField.class);
                currentValue = annotation.value();
            }
            // 如果当前字段上有 StrField 注解
            if (declaredField.isAnnotationPresent(IntField.class)) {
                IntField annotation = declaredField.getAnnotation(IntField.class);
                currentValue = annotation.value();
            }
            // 获取字段名称
            String fieldName = declaredField.getName();
            // 因为字段时 private 的 不能直接访问赋值 所以要获取它的 set 方法
            // 拼接 set 方法名称
            String setterName = String.format("set%s", fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1));
            // 获取到当前字段的 set 方法
            Method setter = getMethodByName(setterName, clazz);
            // 通过当前遍历字段对应 set 方法给当前字段赋值
            setter.invoke(user, currentValue);
        }
    }

    /**
     * 根据方法名称获取方法对象
     *
     * @param name  方法名称
     * @param clazz 方法所在的类
     * @return 方法对象
     */
    private Method getMethodByName(String name, Class clazz) {
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
            if (name.equals(method.getName())) {
                return method;
            }
        }
        return null;
    }
}
0

评论区