《Java基础知识》Java注解"@"详解

Java 注解含义:

Java 注解,顾名思义,注解, 就是对某一事物进行添加注释说明,会存放一些信息,这些信息可能对以后某个时段来说是很有用处的。
Java 注解又叫 java 标注,java 提供了一套机制,使得我们可以对方法、类、参数、包、域以及变量等添加标准 (即附上某些信息)。且在以后某个时段通过反射将标注的信息提取出来以供使用。

 

样例(实现一个自己的注解):

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

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

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = {ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFieldAnnotaion {
String value();
String type();
String lengths();
}

import java.io.Serializable;

@MyAnnotaion("student")
public class Student implements Serializable {

</span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">final</span> <span style="color: rgba(0, 0, 255, 1)">long</span> serialVersionUID = 1L<span style="color: rgba(0, 0, 0, 1)">;

@MyFieldAnnotaion(value </span>= "1",type = "int",lengths = "10"<span style="color: rgba(0, 0, 0, 1)">)
String id;
@MyFieldAnnotaion(value </span>= "蕾蕾",type = "String" ,lengths = "200"<span style="color: rgba(0, 0, 0, 1)">)
String name;

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getId() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setId(String id) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.id =<span style="color: rgba(0, 0, 0, 1)"> id;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getName() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> name;
}

</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setName(String name) {
    </span><span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
}

@Override
</span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String toString() {
    </span><span style="color: rgba(0, 0, 255, 1)">return</span> "Student{" +
            "id='" + id + '\'' +
            ", name='" + name + '\'' +
            '}'<span style="color: rgba(0, 0, 0, 1)">;
}

}

import org.apache.poi.ss.formula.functions.T;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;

/**

  • 通过反射获取注解
    */
    public class AnnotaionDemo {
    public static void main(String[] args) throws Exception {
    Class
    <T> clazz = (Class<T>) Class.forName("demo.knowledgepoints.annotation.Student");
    //判断注解是否存在
    if(clazz.isAnnotationPresent(MyAnnotaion.class)){
    System.out.println(
    "存在注解:MyAnnotaion");
    }

     </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取注解列表</span>
     Annotation[] annotaions =<span style="color: rgba(0, 0, 0, 1)"> clazz.getAnnotations();
     </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; annotaions.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
         System.out.println(</span>"注解:"+<span style="color: rgba(0, 0, 0, 1)">annotaions[i]);
     }
    
     </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取注解内容</span>
     MyAnnotaion myAnnotaion = clazz.getAnnotation(MyAnnotaion.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">) ;
     System.out.println(</span>"注解的值为:"+<span style="color: rgba(0, 0, 0, 1)">myAnnotaion.value());
    
     </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取方法上的注解内容</span>
     Field field = clazz.getDeclaredField("id"<span style="color: rgba(0, 0, 0, 1)">);
    
     </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方法上注解是否存在</span>
     field.isAnnotationPresent(MyFieldAnnotaion.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
     </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">方法注解列表</span>
    

field.getAnnotations();

    </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取方法上的注解内容</span>
    MyFieldAnnotaion myFieldAnnotaion = field.getAnnotation(MyFieldAnnotaion.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
    System.out.println(</span>"value:"+myFieldAnnotaion.value()+"; type:"+myFieldAnnotaion.type()+"; lengths:"+<span style="color: rgba(0, 0, 0, 1)">myFieldAnnotaion.lengths());
}

}

运行结果:

根据这个案例:

1. 注解实现需要关键字:@interface;

2. 在注解上我们还使用了注解 @Target,@Retention。这些被称为元注解,

   Java 中元注解有四个: @Retention @Target @Document @Inherited;

   @Retention:注解的保留位置

        @Retention(RetentionPolicy.SOURCE)   // 注解仅存在于源码中,在 class 字节码文件中不包含

     @Retention(RetentionPolicy.CLASS)     // 默认的保留策略,注解会在 class 字节码文件中存在,但运行时无法获得,

     @Retention(RetentionPolicy.RUNTIME)  // 注解会在 class 字节码文件中存在,在运行时可以通过反射获取到

    @Target: 注解的作用目标

        @Target(ElementType.TYPE)   // 接口、类、枚举

        @Target(ElementType.FIELD) // 字段、枚举的常量

        @Target(ElementType.METHOD) // 方法

        @Target(ElementType.PARAMETER) // 方法参数

        @Target(ElementType.CONSTRUCTOR)  // 构造函数

        @Target(ElementType.LOCAL_VARIABLE)// 局部变量

        @Target(ElementType.ANNOTATION_TYPE)// 注解

        @Target(ElementType.PACKAGE) /// 包

    @Document:说明该注解将被包含在 javadoc 中

    @Inherited:说明子类可以继承父类中的该注解

3. 直接里面可以写方法:String value(); 

   外部使用注解可以将值写入,后续可以拿到该值进行使用。

可以提供默认值: String value() default "花花";   

 

修改 AnnotaionDemo 的方法实现一个常用功能,通过注解将值注入实体类中: 

import org.apache.poi.ss.formula.functions.T;

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

/**

  • 通过反射获取注解
    */
    public class AnnotaionDemo {
    public static void main(String[] args) throws Exception {
    Student student
    = (Student) getbean("demo.knowledgepoints.annotation.Student");
    System.out.println(student);
    }

    public static Object getbean(String className) throws Exception{
    Class
    <T> clazz = (Class<T>)Class.forName(className);
    //判断注解是否存在 (该注解被当成标记使用)
    if(!clazz.isAnnotationPresent(MyAnnotaion.class)){
    throw new Exception("该类缺失注解“MyAnnotaion”,不能通过反射获取 bean");
    }

     </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">创建实体类</span>
     Object object =<span style="color: rgba(0, 0, 0, 1)"> clazz.newInstance();
    
     Field[] fields </span>=<span style="color: rgba(0, 0, 0, 1)"> clazz.getDeclaredFields();
     </span><span style="color: rgba(0, 0, 255, 1)">for</span> (<span style="color: rgba(0, 0, 255, 1)">int</span> i = 0; i &lt; fields.length; i++<span style="color: rgba(0, 0, 0, 1)">) {
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取字段名</span>
         String name =<span style="color: rgba(0, 0, 0, 1)"> fields[i].getName();
    
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">过滤序列</span>
         <span style="color: rgba(0, 0, 255, 1)">if</span> (name.equals("serialVersionUID"<span style="color: rgba(0, 0, 0, 1)">)) {
             </span><span style="color: rgba(0, 0, 255, 1)">continue</span><span style="color: rgba(0, 0, 0, 1)">;
         }
    
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">组装SET方法</span>
         Class&lt;?&gt; type =<span style="color: rgba(0, 0, 0, 1)"> clazz.getDeclaredField(name).getType();
    
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 首字母大写</span>
         String replace = name.substring(0, 1<span style="color: rgba(0, 0, 0, 1)">).toUpperCase()
                 </span>+ name.substring(1<span style="color: rgba(0, 0, 0, 1)">);
         Method setMethod </span>= clazz.getMethod("set" +<span style="color: rgba(0, 0, 0, 1)"> replace, type);
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">获取字段值</span>
         Field field =<span style="color: rgba(0, 0, 0, 1)"> clazz.getDeclaredField(name);
         MyFieldAnnotaion myFieldAnnotaion </span>= field.getAnnotation(MyFieldAnnotaion.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">);
         String value </span>=<span style="color: rgba(0, 0, 0, 1)"> myFieldAnnotaion.value();
         </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">执行set方法</span>
         <span style="color: rgba(0, 0, 255, 1)">if</span> (value != <span style="color: rgba(0, 0, 255, 1)">null</span> &amp;&amp; !""<span style="color: rgba(0, 0, 0, 1)">.equals(value)) {
             </span><span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> ---判断读取数据的类型(判断部分类型)</span>
             <span style="color: rgba(0, 0, 255, 1)">if</span> (type.isAssignableFrom(String.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)) {
                 setMethod.invoke(object, value);
             } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (type.isAssignableFrom(<span style="color: rgba(0, 0, 255, 1)">int</span>.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
                     </span>|| type.isAssignableFrom(Integer.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)) {
                 setMethod.invoke(object, Integer.parseInt(value));
             } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (type.isAssignableFrom(Double.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
                     </span>|| type.isAssignableFrom(<span style="color: rgba(0, 0, 255, 1)">double</span>.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)) {
                 setMethod.invoke(object, Double.parseDouble(value));
             } </span><span style="color: rgba(0, 0, 255, 1)">else</span> <span style="color: rgba(0, 0, 255, 1)">if</span> (type.isAssignableFrom(Boolean.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)
                     </span>|| type.isAssignableFrom(<span style="color: rgba(0, 0, 255, 1)">boolean</span>.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">)) {
                 setMethod.invoke(object, Boolean.parseBoolean(value));
             }
         }
     }
     </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> object;
    

    }
    }

运行结果:

案例中使用了反射:反射详解:https://www.cnblogs.com/jssj/p/11723910.html

总结语:注解功能在框架开发中被广泛使用:例如 Spring,MyBatis 等。注解的出现大大的减少了开发工作中的开发工作量。