Java註解詳解

轉載請標明出處:
blog.csdn.net/forezp/arti…
本文出自方誌朋的博客html

在使用SpringBoot做爲Web敏捷開發的框架以後,SpringBoot除了自動裝配配置的便捷以外,在不少時候須要基於註解來開發。註解不只增長了代碼的可讀性,還增長了開發的速度。這篇文章主要講述Java 註解。java

元註解

元註解用於註解其餘註解的。Java 5.0定義了4個標準的元註解,以下:git

  • @Target
  • @Retention
  • @Documented
  • Inherited

如今來講說這四個元註解有什麼做用。github

@Target

 @Target註解用於聲明註解的做用範圍,例如做用範圍爲類、接口、方法等。它的取值以及值所對應的範圍以下:sql

  • CONSTRUCTOR:用於描述構造器
  • FIELD:用於描述域
  • LOCAL_VARIABLE:用於描述局部變量
  • METHOD:用於描述方法
  • PACKAGE:用於描述包
  • PARAMETER:用於描述參數
  • TYPE:用於描述類、接口(包括註解類型) 或enum聲明

@Retention

該註解聲明瞭註解的生命週期,即註解在什麼範圍內有效。bash

  • SOURCE:在源文件中有效
  • CLASS:在class文件中有效
  • RUNTIME:在運行時有效(即運行時保留)

大多數註解都爲RUNTIMEapp

@Documented

是一個標記註解,有該註解的註解會在生成 java 文檔中保留。框架

@Inherited

該註解代表子類是有繼承了父類的註解。好比一個註解被該元註解修飾,而且該註解的做用在父類上,那麼子類有持有該註解。若是註解沒有被該元註解修飾,則子類不持有父類的註解。ui

自定義註解

在Java開發者,JDK自帶了一些註解,在第三方框架Spring 帶了大量的註解,這些註解稱爲第三方註解。在不少實際開發過程當中,咱們須要定義本身的註解。那麼如今以案例的方式來說解自定義註解。spa

在註解中,須要使用四種元註解來聲明註解的做用範圍、生命週期、繼承,是否生成文檔等。另外在註解中也能夠有本身的成員變量,若是一個註解沒有成員變量則稱爲標記註解。註解的成員變量,只支持原始類型、Class、Enumeration、Annoation。

如今定義一個@Writer註解,該註解被Retention、Documented、Inherited、Target修飾,代表該註解的做用範圍爲類、接口和方法,生命週期爲運行時、該註解生成文檔,而且子類可繼承該註解。該註解有2個成員變量,一個爲name一個爲 age,代碼以下:

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface Writer {

    String name();

    int age();

}複製代碼

那麼有了該註解,怎麼用呢?

該註解的做用範圍爲類、方法,寫一個WriterTest,代碼以下:

@Writer(name = "forezp", age = 12)
public class WriterTest {

    @Writer(name = "miya", age = 10)
    public void writeBlog() {
        System.out.println("writing blog");
    }

  }複製代碼

該類有了這個註解有何用?

通常來講,用該類修飾的類,須要經過反射來作一下邏輯的開發的工做,可普遍用於AOP、程序的配置等。如今寫一個方法經過反射來解析該註解:

public static void main(String[] args) throws ClassNotFoundException {
        Class c = Class.forName("com.forezp.annotation.WriterTest");
        if (c.isAnnotationPresent(Writer.class)) {
            Writer w = (Writer) c.getAnnotation(Writer.class);
            System.out.println("name:" + w.name() + " age:" + w.age());
        }
        Method[] methods = c.getMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(Writer.class)) {
                Writer w = method.getAnnotation(Writer.class);
                System.out.println("name:" + w.name() + " age:" + w.age());
            }
        }
    }複製代碼

這些代碼基本爲反射的內容,由於反射在另外一篇文章已經詳細講述過,再也不重複,運行該Main方法,控制檯打印出以下內容:

name:forezp age:12

name:miya age:10

案例實戰

有了上述的講解,你可能對註解有所瞭解,可是對註解的具體應用並非很深入。如今以一個案例來詳細講述。

你們都對ORM框架Mybitis都很是的熟悉,在這個框架中用了大量的註解。如今模仿這個框架,經過自定義註解,來解析sql 的查詢語句。實現過程大概以下:

  • 定義@Table @Colum註解
  • 定義一個實體User,定義一些基本的字段,並用註解修飾
  • 用User類new對象,給對象的某些字段賦值
  • 經過反射和註解來生成sql 的查詢語句

首先定義個一個Table註解,它的做用範圍爲類,代碼以下:

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
public @interface Table {
    String value() default "";
}複製代碼

定義一個Column註解,做用範圍爲字段,代碼以下:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface Column {
    String value();
}複製代碼

定義一個User類,在該類的加上@Table註解,在具體的字段上 @Column註解,代碼以下:

@Table("user")
public class User {
    @Column("id")
    private int id;
    @Column("name")
    private String name;
    @Column("age")
    private int age;
    @Column("address")
    private String address;
    ..//省略getter setter
   }複製代碼

寫一個生成sql語句的類,它是經過反射來獲取表名、字段名,加上判斷實體對象的字段值來生成 查詢的 sql 語句的。代碼以下:

public class GenUserSql {

    public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
        User u1 = new User();
        User u2 = new User();
        u1.setId(1);
        u2.setName("forezp");
        genSql(u2);
        genSql(u1);
    }

    private static void genSql(User user) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Class c = user.getClass();
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("select * from ");
        if (c.isAnnotationPresent(Table.class)) {
            Table table = (Table) c.getAnnotation(Table.class);
            String tableName = table.value();
            stringBuilder.append(tableName).append(" where 1=1 and ");
        }
        Field[] fields = c.getDeclaredFields();
        for (Field field : fields) {
            String columnName;
            if (field.isAnnotationPresent(Column.class)) {
                Column column = field.getAnnotation(Column.class);
                columnName = column.value();
            } else {
                continue;
            }
            String fieldName = field.getName();
            String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
                       Method method = c.getMethod(getMethodName);
            Object fieldValue = method.invoke(user);
            if (fieldValue == null || ((fieldValue instanceof Integer) && (Integer) fieldValue == 0)) {
                continue;
            }
            if (fieldValue instanceof Integer) {
                stringBuilder.append(columnName + "=" + fieldValue);
            }
            if (fieldValue instanceof String) {
                stringBuilder.append(columnName + "=" + "'" + fieldValue + "'");
            }

        }
        System.out.println(stringBuilder.toString());

    }
}複製代碼

運行程序,控制檯打印以下:

>

select * from user where 1=1 and name='forezp'

select * from user where 1=1 and id=1

參考資料

www.cnblogs.com/peida/archi…

慕課網視頻

源碼下載

github.com/forezp/java…

關注個人公衆號

精彩內容不能錯過!

forezp.jpg
forezp.jpg
相關文章
相關標籤/搜索