Java注解,其实就这么简单?

image-20200523101659154

一、认识注解

谈到注解可能有的小伙伴比较陌生,在实际的工作中自己定义很少去定义注解,其实在Java 的知识体系当中,注解是一个很重要的概念。

比如我们在实际开发中用到的一些框架 Spring, Mybatis, SpringBoot等等都会用到注解,诸如@Component,@RestController,@RequestMapping,也许有的小伙伴会说不了解这些也能做开发,无所谓呀,我个人觉得在技术这条路想走的更远,我们要知其然,知其所依然,才能在技术这条路上走的更远。

Java中的注解是JDK 1.5之后引入的,有些小伙伴比较陌生,其实注解(@interface)和类(class)接口是一样的,只不过我们实际的开发中用的比较多而已。

注解的定义,是通过@interface关键词

public @interface AnnotationTest {
}

那么我们这么使用自定义的注解呢?

@AnnotationTest
public class ClientTest {
}

我们在类(ClientTest)上方添加自定义的注解(@AnnotationTest)就OK了,换一种思路其实我们完全可以把注解理解成一种标签,加在类上就是对程序作出解释说明。

标签:就比如我们在超市买商品,各类不同的商品都贴有不同的价格,对商品的一种说明。

Annotation在哪里使用呢?

可以用在package, class, method, field等上面,相当于给它们添加了额外的辅助信 息,我们可以通过反射机制编程实现对这些元数据的访问。

二、什么是元注解

元注解其实就是一种基本注解,它能够应用到其他注解上面,那上面提到的标签为例,元注解 可以理解为一种比较特殊的注解,他的作用给我们普通注解(自定义注解)作出解释说明的。.

元注解包括:

@Retention、@Documented、@Target、@Inherited、@Repeatable

@Retention(时间周期)

用于描述注解的时间周期(标签贴的时间长短),表示需要在什么级别保存该注解,即保留的时间长短。取值类型(RetentionPolicy)有以下几种:
  SOURCE:在源文件中有效 (即源文件保留,在编译器进行编译时被丢弃)
  CLASS:在class文件中有效(即注解只被保留到编译进行的时候,它并不会被加载到 JVM 中,)
  RUNTIME:在运行时有效 (注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们)

代码实例:

@Retention(RetentionPolicy.RUNTIME)
public @interface AnnotationTest {
}

@Documented

用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,它的作用是能够将注解中的元素包含到 Javadoc 中去。它是一个标记注解,没有成员。

@Target(应用范围)

可以理解为目标对象能够应用的范围(package, class, method, field),比如标签,标签的分类不同贴的商品位置也不同。

ElementType的取值有以下几种,常用的 ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举

ANNOTATION_TYPE 可以给一个注解进行注解

CONSTRUCTOR 可以给构造方法进行注解

FIELD 可以给属性进行注解

LOCAL_VARIABLE 可以给局部变量进行注解

METHOD 可以给方法进行注解

PACKAGE 可以给一个包进行注解

PARAMETER 可以给一个方法内的参数进行注解

TYPE 可以给一个类型进行注解,比如类、接口、枚举

@Target(ElementType.TYPE)
public @interface AnnotationTest {
}

@Inherited

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

代码实例;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface AnnotationTest {

}

@AnnotationTest
public class ClientTest {
}
//子类也拥有
class B extends ClientTest{

}

@Repeatable

表面的意思是可重复的意思,代码实例如下:。

@Repeatable(Persons.class)
public @interface Person {
    String role () default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Persons {
    Person[]  value();
}
@Person(role = "牛人")
@Person(role = "超人")
public class ClientTest {
}

说明,@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。

什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。

Persons,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable 注解过的注解数组

三、自定义注解

注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型

成员变量值是value(),注解使用的时候可以省略

代码实例:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface AnnotationTest {
   String value();
}
@AnnotationTest("aa")
public class ClientTest {
}

在调用注解的时候,可以忽略value 直接赋值即可。

注解成员变量数组

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Inherited
public @interface AnnotationTest {
   String name();
   String [] user() ;
}
@AnnotationTest(name = "张三",user = {"aa","bb"})
public class ClientTest {
}

成员变量不为value的时候,调用的时候就待按照上面的形式。

注解的成员变量也可以定义默认值

public @interface AnnotationTest {
   String [] user() default "aa";
}

注意在Java 中给我定义好的注解

@Deprecated, 方法过期

@Override, 重写方法

@SuppressWarnings,代码警告

四、如何解析注解

讲到这里,我们会定义一个基本的注解了,那么我们如何获取我们自定好的注解呢?

这里我们就涉及到Java中的非常重要的原理:Java 的反射机制,不了解反射机制的小伙们可以产考这篇文章:

JAVA反射机制,这里就不一一讲解了。

来我们现在自定一个一个注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface TableStudent {
    String value();
}

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface tableFiled {
    String columnName();
    String type();
    int  length();

}
@TableStudent("tb_student")
public class Student {
    @tableFiled(columnName = "id",type = "int",length = 10)
    private int id;
    @tableFiled(columnName = "name",type = "vacher",length = 10)
    private String name;

    public Student() {
    }

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

说明我们定义TableStudent注解使用的范围为类,tableFiled这个注解只能用在属性上面,这两个注解应用在Student实体类上面,看起来是不是有一种似曾相识的感觉,在Hibernate 框架中对象和数据库表的映射关系的时候就是这样写,大家明白了吧。

解析注解

public class Client {
    public static void main(String[] args) {
        Class c = null;
        try {
            c = Class.forName("annotation.Student");
            Annotation[] annotations = c.getAnnotations();
            for (Annotation annotation : annotations) {
                System.out.println(annotation);
            }
            Field[] fields = c.getDeclaredFields();
            for (Field field : fields) {
                for (Annotation annotation : field.getAnnotations()) {
                    System.out.println(annotation);
                }
            }
            //获得类的指定注解
            TableStudent tableStudent = (TableStudent) c.getAnnotation(TableStudent.class);
            System.out.println(tableStudent.value());
            //获得方法得指定注解
            Field fieldName = c.getDeclaredField("name");
            tableFiled tableFiled = (tableFiled) fieldName.getAnnotation(tableFiled.class);
            System.out.println(tableFiled.columnName() + tableFiled.type() + tableFiled.length());

        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

获取注解的方式是用到了反射机制的原理,这段代码就是如何通过反射获取注解。

今天就和大家讲到这里,喜欢我的小伙伴们,动动你的小手点个赞呗。

欢迎大家关注我的公众号:阿福聊编程,长期更新Java各种技术文章

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值