注解:Java SE 5.0 版本中开始引入的概念,注解和class,interface一样也是一种Java类型,声明注解是通过@interface来声明的.
public @interface TestAnnotation {
}
注解的功能:主要是起到标签说明的作用,可以作用与类名,方法,成员变量,参数,私有变量等.但是它不影响所注解部分的代码功能.
那它存在的意义是什么,一个是编译器管理使用,一个是运行期通过反射获取注解,进行注解说明要操作的其他业务处理
注解是一系列元数据,它提供数据用来解释程序代码,但是注解并非是所解释的代码本身的一部分。注解对于代码的运行效果没有直接影响。
注解有许多用处,主要如下:
- 提供信息给编译器: 编译器可以利用注解来探测错误和警告信息
- 编译阶段时的处理: 软件工具可以用来利用注解信息来生成代码、Html文档或者做其它相应处理。
- 运行时的处理: 某些注解可以在程序运行的时候接受代码的提取
对于注解首先我们要知道它是干嘛的,从上面我们基本也了解了,其次我们自己如何定义使用它,
在自己定义的时候我们得知道它的格式,上面已说,其次得知道元注解,这个是用来说明注解的基本使用规则的.
该博客写的很详细:https://blog.csdn.net/briblue/article/details/73824058
元注解:有 @Retention、@Documented、@Target、@Inherited、@Repeatable 5 种。下面来介绍:
Retention 的英文意为保留期的意思。当 @Retention 应用到一个注解上的时候,它解释说明了这个注解的的存活时间。
它的取值如下:
- RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
- RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
- RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
我们可以这样的方式来加深理解,@Retention 去给一张标签解释的时候,它指定了这张标签张贴的时间。@Retention 相当于给一张标签上面盖了一张时间戳,时间戳指明了标签张贴的时间周期。
@Retention(RetentionPolicy.RUNTIME)
public @interface TestAnnotation {
}
上面的代码中,我们指定 TestAnnotation 可以在程序运行周期被获取到,因此它的生命周期非常的长。
顾名思义,这个元注解肯定是和文档有关。它的作用是能够将注解中的元素包含到 Javadoc 中去。
Target 是目标的意思,@Target 指定了注解运用的地方。
你可以这样理解,当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。
类比到标签,原本标签是你想张贴到哪个地方就到哪个地方,但是因为 @Target 的存在,它张贴的地方就非常具体了,比如只能张贴到方法上、类上、方法参数上等等。@Target 有下面的取值
Inherited 是继承的意思,但是它并不是说注解本身可以继承,而是说如果一个超类被 @Inherited 注解过的注解进行注解的话,那么如果它的子类没有被任何注解应用的话,那么这个子类就继承了超类的注解。
说的比较抽象。代码来解释。
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@interface Test {}
@Test
public class A {}
public class B extends A {}
注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。
可以这样理解:
老子非常有钱,所以人们给他贴了一张标签叫做富豪。
老子的儿子长大后,只要没有和老子断绝父子关系,虽然别人没有给他贴标签,但是他自然也是富豪。
老子的孙子长大了,自然也是富豪。
这就是人们口中戏称的富一代,富二代,富三代。虽然叫法不同,好像好多个标签,但其实事情的本质也就是他们有一张共同的标签,也就是老子身上的那张富豪的标签。
Repeatable 自然是可重复的意思。@Repeatable 是 Java 1.8 才加进来的,所以算是一个新的特性。
什么样的注解会多次应用呢?通常是注解的值可以同时取多个。
举个例子,一个人他既是程序员又是产品经理,同时他还是个画家。
@interface Persons {
Person[] value();
}
@Repeatable(Persons.class)
@interface Person{
String role default "";
}
@Person(role="artist")
@Person(role="coder")
@Person(role="PM")
public class SuperMan{
}
注意上面的代码,@Repeatable 注解了 Person。而 @Repeatable 后面括号中的类相当于一个容器注解。
什么是容器注解呢?就是用来存放其它注解的地方。它本身也是一个注解。
我们再看看代码中的相关容器注解。
@interface Persons {
Person[] value();
}
按照规定,它里面必须要有一个 value 的属性,属性类型是一个被 @Repeatable 注解过的注解数组,注意它是数组。
如果不好理解的话,可以这样理解。Persons 是一张总的标签,上面贴满了 Person 这种同类型但内容不一样的标签。把 Persons 给一个 SuperMan 贴上,相当于同时给他贴了程序员、产品经理、画家的标签。
我们可能对于 @Person(role=”PM”) 括号里面的内容感兴趣,它其实就是给 Person 这个注解的 role 属性赋值为 PM ,大家不明白正常,马上就讲到注解的属性这一块。
了解到元注解后,我们就可以通过元注解来给自定义的注解进行注解说明使用了
举例:spring的service注解:
@Target({ java.lang.annotation.ElementType.TYPE }):说明该注解可以给一个类型进行注解,比如类、接口、枚举
@Retention(RetentionPolicy.RUNTIME):说明该注解在运行时可以被使用,有效
@Documented:说明该注解在Javadoc中被说明
@Component:该注解是spring框架的注解不是元注解,但该注解的@Target类型是ElementType.TYPE,所以它可以注解一个类型包括注解在其他注解上
@Target({ java.lang.annotation.ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Service {
public abstract String value();
}
学注解一是要会用Java中已经有的注解,而是根据业务需求自定义注解.现在好多框架都支持使用注解,自己在用的spring框架中注解用的就比较多.自定义注解好多都是在运行中可以使用的.自己在工作做也可以自定义框架使用.
自己定义一个可以给属性定义的注解,但该类的实体类字段为空时给它设定初始值
该自定义注解:@Retention(RetentionPolicy.RUNTIME)和@Target({ElementType.FIELD})是最主要的,另外两个可以不用
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target({ElementType.FIELD})
@Inherited
public @interface NameTation {
int value() default 1;//成员变量在该案例中是没有使用的
Class> Link();//成员变量在该案例中是没有使用的
Type type();//成员变量
}
定义实体类:
package app.annotation;
import java.util.Date;
import org.springframework.beans.factory.annotation.Autowired;
public class Person {
@NameTation(value=7,Link=Person.class,type=Type.STRING)
String name;
@NameTation(value=7,Link=Person.class,type=Type.INT)
int age;
@NameTation(value=7,Link=Person.class,type=Type.CHAR)
char sex;
@NameTation(value=7,Link=Person.class,type=Type.DOUBLE)
double height;
@NameTation(value=7,Link=Person.class,type=Type.STRING)
String interstValue;
@NameTation(value=7,Link=Person.class,type=Type.OBJECT)
Object obj;
@NameTation(value=7,Link=Person.class,type=Type.DATE)
Date date;
@NameTation(value=7,Link=Person.class,type=Type.BOOLEAN)
boolean bool;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getHeight() {
return height;
}
public void setHeight(double height) {
this.height = height;
}
public String getInterstValue() {
return interstValue;
}
public void setInterstValue(String interstValue) {
this.interstValue = interstValue;
}
public Object getObj() {
return obj;
}
public void setObj(Object obj) {
this.obj = obj;
}
public Date getDate() {
return date;
}
public void setDate(Date date) {
this.date = date;
}
public void taget(){
System.out.println("woshi fanfa");
}
}
枚举类:
public enum Type {
STRING(1),INT(1),DOUBLE(1),CHAR(1),DATE(1),
FLOAT(1),BYTE(1),SHORT(1),LONG(1),BOOLEAN(1),OBJECT(1);
private int type;
Type(int type){
this.type=type;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
public static Object charge(Type t){
switch (t) {
case STRING:
return "哈哈哈";
case INT:
return 1;
case DOUBLE:
return 1.0;
case CHAR:
return '1';
case DATE:
return new Date();
case FLOAT:
return 1f;
case BYTE:
return 1;
case SHORT:
return 1;
case BOOLEAN:
return false;
case LONG:
return 1;
default:
return new Object();
}
}
}
测试类使用:
public static void main(String[] args) throws IllegalArgumentException, IllegalAccessException, InstantiationException {
Class cls=Person.class;//通过反射获取到class
Person newInstance = cls.newInstance();//用class新建一个对象
newInstance.setName("Lily");//赋值
Field[] fields = cls.getDeclaredFields();//获取class的所有字段
for(Field field:fields){
Object object = field.get(newInstance);//获取该字段在对象中的值
NameTation annotation = field.getAnnotation(NameTation.class);
boolean annotationPresent = field.isAnnotationPresent(NameTation.class);
//判断是否为空且是否该字段被注解 if(annotationPresent && annotation!=null&&object==null){
Object charge = Type.charge(annotation.type());//校验该字段的类型并返回相应的初始值
field.set(newInstance, charge);//给字段赋值
System.out.println("name:"+field.getName()+"------"+charge);
}else{
System.out.println("不为空"+field.getName()+object);
}
}