## Java專題十八:注解
[TOC]
### 18.1. 元注解
| 所在包 | 類名 | 描述 |
| --- | --- | --- |
| java.lang | `Override` | 表示此方法是重寫的,如果父類或接口中不含該方法,則編譯報錯|
| java.lang| `Deprecated` |表示方法已過時,不鼓勵使用,因為方法是危險的或者有其它更好的方法選擇,在程序中使用該方法,會報編譯警告|
| java.lang | `SuppressWarnings` |告訴編譯器忽略掉注解中聲明的警告|
| java.lang.annotation | `Documented` |表示可以包含在javadoc等工具生成的文檔中|
| java.lang.annotation | `Inherited` |表示注解類型會被繼承到子類中|
| java.lang.annotation | `Retention` |表示注解類型要保留多久,取值于枚舉類`java.lang.annotation.RetentionPolicy`|
| java.lang.annotation | `Target` |表示注解適用那種Java成員,取值于枚舉類`java.lang.annotation.ElementType`|
| java.lang.annotation | `Native` |表示一個字段定義常量值引用自native代碼,1.8新增|
| java.lang.annotation | `Repeatable` |表示注解可以聲明多次的,1.8新增|
枚舉類`java.lang.annotation.RetentionPolicy`:
~~~
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
~~~
枚舉類`java.lang.annotation.ElementType`:
~~~
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
~~~
### 18.2. 自定義注解
> 假設我們設計一個數據庫Helper類,用于JDBC插入數據,實現類似mybatis的ORM模型
首先定義2個注解,注解`Table`標識數據庫中表,適用于`TYPE`類上,注解`Column`標識數據庫中的列,適用于`FIELD`字段上
~~~
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Table {
String value();
}
~~~
~~~
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Column {
String value();
}
~~~
現在有2個`javabean`類,`Student`類和`Book`類
因為數據庫中的字段與我們實體類中字段名字可能不一致,因此我們使用注解標識實體類與數據庫中相關字段的對應關系
~~~
@Table("student")
public class Student {
@Column(value = "std_id")
int id;
@Column(value = "std_name")
String 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;
}
}
~~~
~~~
@Table("book")
public class Book {
@Column("book_name")
String name;
@Column("book_author")
String author;
@Column("price")
int price;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author = author;
}
public int getPrice() {
return price;
}
public void setPrice(int price) {
this.price = price;
}
}
~~~
使用反射獲取字段的值,使用注解獲取數據庫中字段的名字,拼接SQL語句
~~~
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
public class SQLHelper<T> {
final Logger logger = Logger.getLogger(SQLHelper.class.getName());
public int insert(T t){
if (null == t){
throw new NullPointerException();
}
StringBuilder builder = new StringBuilder();
Class cls = t.getClass();
Table table = (Table)cls.getAnnotation(Table.class);
String tableName = table.value();
Field[] fields = cls.getDeclaredFields();
if (0 == fields.length) {
throw new NullPointerException("No Field");
} else if (1 == fields.length) {
String columnName = fields[0].getAnnotation(Column.class).value();
Object columnValue = null;
try{
columnValue = fields[0].get(t);
if (columnValue instanceof String){
columnValue = "\"" + columnValue + "\"";
}
}catch (IllegalAccessException e){
columnValue = "NULL";
}
builder.append("INSERT INTO ").append(tableName)
.append(" (").append(columnName).append(") ")
.append("VALUES(").append(columnValue).append(");");
} else {
StringBuilder columnNames = new StringBuilder();
StringBuilder columnValues = new StringBuilder();
for (int i = 0; i < fields.length; i++) {
Column column = fields[i].getAnnotation(Column.class);
if (null == column)
throw new NullPointerException("Unknown Column");
if (i != fields.length - 1) {
columnNames.append(column.value()).append(", ");
Object columnValue = null;
try{
columnValue = fields[i].get(t);
if (columnValue instanceof String){
columnValue = "\"" + columnValue + "\"";
}
}catch (IllegalAccessException e){
columnValue = "NULL";
}
columnValues.append(columnValue).append(", ");
}
else {
columnNames.append(column.value());
Object columnValue = null;
try{
columnValue = fields[i].get(t);
if (columnValue instanceof String){
columnValue = "\"" + columnValue + "\"";
}
}catch (IllegalAccessException e){
columnValue = "NULL";
}
columnValues.append(columnValue);
}
}
builder.append("INSERT INTO ").append(tableName)
.append("(").append(columnNames).append(") ")
.append("VALUES(").append(columnValues).append(");");
}
return insert0(builder.toString());
}
private int insert0(String sql){
logger.log(Level.INFO, sql);
//System.out.println(sql);
return 1;
}
}
~~~
使用如下代碼驗證:
~~~
Book book0 = new Book();
book0.setName("Thinking in java");
book0.setAuthor("Json");
book0.setPrice(80);
new SQLHelper<Book>().insert(book0);
Student student = new Student();
student.setId(1637);
student.setName("Tom");
new SQLHelper<Student>().insert(student);
~~~
輸出:
```
四月 14, 2020 1:24:08 上午 SQLHelper insert0
信息: INSERT INTO book(book_name, book_author, price) VALUES("Thinking in java", "Json", 80);
四月 14, 2020 1:24:08 上午 SQLHelper insert0
信息: INSERT INTO student(std_id, std_name) VALUES(1637, "Tom");
```
- JavaCook
- Java專題零:類的繼承
- Java專題一:數據類型
- Java專題二:相等與比較
- Java專題三:集合
- Java專題四:異常
- Java專題五:遍歷與迭代
- Java專題六:運算符
- Java專題七:正則表達式
- Java專題八:泛型
- Java專題九:反射
- Java專題九(1):反射
- Java專題九(2):動態代理
- Java專題十:日期與時間
- Java專題十一:IO與NIO
- Java專題十一(1):IO
- Java專題十一(2):NIO
- Java專題十二:網絡
- Java專題十三:并發編程
- Java專題十三(1):線程與線程池
- Java專題十三(2):線程安全與同步
- Java專題十三(3):內存模型、volatile、ThreadLocal
- Java專題十四:JDBC
- Java專題十五:日志
- Java專題十六:定時任務
- Java專題十七:JavaMail
- Java專題十八:注解
- Java專題十九:淺拷貝與深拷貝
- Java專題二十:設計模式
- Java專題二十一:序列化與反序列化
- 附加專題一:MySQL
- MySQL專題零:簡介
- MySQL專題一:安裝與連接
- MySQL專題二:DDL與DML語法
- MySQL專題三:工作原理
- MySQL專題四:InnoDB存儲引擎
- MySQL專題五:sql優化
- MySQL專題六:數據類型
- 附加專題二:Mybatis
- Mybatis專題零:簡介
- Mybatis專題一:配置文件
- Mybatis專題二:映射文件
- Mybatis專題三:動態SQL
- Mybatis專題四:源碼解析
- 附加專題三:Web編程
- Web專題零:HTTP協議
- Web專題一:Servlet
- Web專題二:Cookie與Session
- 附加專題四:Redis
- Redis專題一:數據類型
- Redis專題二:事務
- Redis專題三:key的過期
- Redis專題四:消息隊列
- Redis專題五:持久化