jdk自帶的註解:
@Override 覆蓋父類方法
@Override
public String name() {
return null;
}
當發現父類的方法定義的有些問題,但是又不能刪除,因爲有些地方還在
調用這個接口則:
@Deprecated 表示方法已經過時
父類中設置方法過時:
@Deprecated
public void sing();
@Suppvisewarnings 忽視方法過時的警告
當測試類調用時,會出現方法過時的警告,點擊感嘆號,添加忽視過時:
@SuppressWarnings("deprecation")
public void sing(){
Person p = new child();
p.sing();
}
2、常見的第三方註解:
Spring :
@Autowired
@Service
@Repository
Mybatis :
@InterProvider
@UpdateProvider
@Options
3、註解的分類:
-->源碼註解
註解只在源碼中存在,編譯成.class文件就沒了
-->編譯時註解
註解在源碼和.class文件中存在
例如:@Override告訴編譯器覆蓋父類方法,然後進行編譯
-->運行時註解
註解在運行階段還起作用,影響運行邏輯
例如:@Autowired運行時把成員變量裝配進來
元註解:給註解進行的註解
4、自定義註解:
聲明:
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Description{// 使用@interface關鍵字定義注
解
String desc();//成員以無參無異常方式聲明
String author();
int age() default 18;//可以用default爲成員指定一個默認值
}
元註解:
//註解作用域(構造方法、局部變量、方法聲明、包聲明類接口等)
@Target({ElementType.METHOD,ElementType.TYPE})
//註解的生命週期(源碼、編譯時、運行時)
@Retention(RetentionPolicy.RUNTIME)
//表示註解允許子類繼承
@Inherited
//表示生成javadoc時會包含註解
@Documented
使用自定義註解:
@Description(desc="zy",author="boy",age=18)
public String eyeColor(){
return "red";
}
這樣,@Description註解就在eyeColor()方法上使用5、解析註解:
通過反射獲取類、函數或成員上的運行時註解信息,從而動態控制程序
運行的邏輯.
//1、使用類加載器加載類
try {
Class c = Class.forName
("com.ann.test.child");
//2、找到類上面的註解(判斷指定類上是否存
在Description這個註解)
boolean isExist = c.isAnnotationPresent
(Description.class);
if(isExist){
//3、拿到註解實例
Description d = (Description)
c.getAnnotation(Description.class);
System.out.println(d.value());
}
//4、找到方法上的註解
//首先遍歷所有的方法
Method[] ms = c.getMethods();
for (Method m : ms) {
//判斷是否有註解
boolean isMExist =
m.isAnnotationPresent(Description.class);
if (isMExist) {
//如果存在則使用註解
Description md =
(Description)m.getAnnotation(Description.class);
System.out.println
(md.value());
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
註解的繼承:
父類中添加註解,子類中刪除原有註解
此時還是用上面的解析方式對子類進行註解解析
此時運行不輸出任何東西
原因是: @Inherited對於接口繼承不起作用所以要把Person改爲類,而不是接口
child類中改爲extends
運行 --> 打印出類上的註解,而不打印方法上的註解
所以註解只繼承類上的註解,而不繼承方法上的註解
6、項目實現:
需求:對象設置好要查詢的條件,調用query()後返回對應的sql語句
Filter.java類:(對應了數據庫表中各個字段)
package com.zy.test;
@Table("user")
public class Filter {
@Column("id")
private int id;
@Column("user_name")
private String userName;
@Column("nick_name")
private String nickName;
@Column("age")
private int age;
@Column("city")
private String city;
@Column("email")
private String email;
@Column("mobile")
private String mobile;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getNickName() {
return nickName;
}
public void setNickName(String nickNameString) {
this.nickName = nickNameString;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getEmail() {
return email;
}
public void setEmail(String email) {
this.email = email;
}
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
}
Test實現類:(實現配置好查詢條件,調用query返回sql)
package com.zy.test;
public class Test {
public static void main(String[] args) {
Filter f1 = new Filter();
f1.setId(10);//查詢id爲10的用戶
Filter f2 = new Filter();
f2.setUserName("lucy");//模糊查詢用戶名爲lucy的用
戶
Filter f3 = new Filter();
f3.setEmail
("[email protected],[email protected],[email protected]");//查詢郵箱爲其中任意一個
的用戶
//調用query進行查詢
String sql1 = query(f1);
String sql2 = query(f2);
String sql3 = query(f3);
System.out.println(sql1);
System.out.println(sql2);
System.out.println(sql3);
}
private static String query(Filter f){
return null;
}
}
對Filter類進行添加@Table和@Column兩個註解之後,接下來對這兩個註解
進行定義:(這裏定義註解將對象與數據庫中的表對應起來)
Table.java:(設置一個參數爲表名,作用域爲類或接口)
Column.java:(設置一個參數爲列名,作用域爲參數)
package com.zy.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String value();
}
package com.zy.test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value();
}
Test.java中query()方法的實現:(注意這裏字段值有String和int類型,所以要定義爲 Object類型)
package com.zy.test;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Iterator;
public class Test {
public static void main(String[] args) {
Filter f1 = new Filter();
f1.setId(10);//查詢id爲10的用戶
Filter f2 = new Filter();
f2.setUserName("lucy");//查詢用戶名爲lucy的用戶
f2.setAge(19);
Filter f3 = new Filter();
f3.setEmail
("[email protected],[email protected],[email protected]");//查詢郵箱爲其中任意一個
的用戶
//調用query進行查詢
String sql1 = query(f1);
String sql2 = query(f2);
String sql3 = query(f3);
System.out.println(sql1);
System.out.println(sql2);
System.out.println(sql3);
}
private static String query(Filter f){
StringBuilder sb = new StringBuilder();
//1、獲取到class
Class c = f.getClass();
//2.通過註解獲取到table的名字
boolean exists = c.isAnnotationPresent
(Table.class);
if (!exists) {
return null;
}
Table t = (Table)c.getAnnotation(Table.class);
String tableName = t.value();
sb.append("select * from ").append
(tableName).append(" where 1=1 ");
//遍歷所有的字段
Field[] fArray = c.getDeclaredFields();
for (Field field : fArray) {
//4.處理每個字段對應的sql
//4.1 拿到字段名
boolean fExists = field.isAnnotationPresent
(Column.class);
if (!fExists) {//如果不是數據庫字段
continue;
}
Column column = (Column)field.getAnnotation
(Column.class);
String columnNameString = column.value();
//4.2 拿到字段的值(通過反射取得get方法的名字,然
後通過反射區調用這個方法,就取得字段值)
String filedName = field.getName();
//把get加上字段名首字母大寫
filedName.substring(0, 1).toUpperCase(),把首字母之後的名字內容拼
裝上filedName.substring(1),就拼裝成get方法
String getMethodName = "get" +
filedName.substring(0, 1).toUpperCase() + filedName.substring(1);
//通過反射獲取對應方法
Object fieldValue = null;
try {
Method getMethod = c.getMethod
(getMethodName);
//反射調用此方法後獲得字段值
fieldValue = getMethod.invoke(f);
} catch (Exception e) {
e.printStackTrace();
}
//拼裝sql
//如果字段值爲空或者字段值在int類型時爲0
fieldValue instanceof Integer && (Integer)fieldValue == 0,將不作
處理
if (fieldValue == null || (fieldValue instanceof
Integer && (Integer)fieldValue == 0)) {
continue;
}
sb.append("and ").append(filedName);
if (fieldValue instanceof String) {
//如果是包含三個郵箱的查詢,即包含逗號
if (((String) fieldValue).contains(","))
{
String[] value =
((String) fieldValue).split(",");
sb.append("in(");
for (String v : value) {
sb.append
("'").append(v).append("'").append(",");
}
//把最後一個逗號刪掉
sb.deleteCharAt
(sb.length()-1);
sb.append(")");
}else{
sb.append("=").append
("'").append(fieldValue).append("'");
}
}
else if (fieldValue instanceof Integer) {
sb.append("=").append
(fieldValue);
}
}
return sb.toString();
}
}
現在如果有第二張表(Department.java),也需要這樣的方式進行sql生成
則只需要在對應對象中添加@Table和@Column註解即可
Department.java:
package com.zy.test;
@Table("department")
public class Department {
@Column("id")
private int id;
@Column("name")
private String name;
@Column("leader")
private String leader;
@Column("number")
private int number;
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;
}
public String getLeader() {
return leader;
}
public void setLeader(String leader) {
this.leader = leader;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
}
只需要把query()方法中參數改爲Object,這樣就所有對象添加了註解的都有效了
Department d = new Department();
d.setId(1);
d.setLeader("kkk");
d.setNumber(111);
System.out.println(query(d));