一、註解
簡介:註解(Annotation)是java5引入的一種代理輔助工具,它的核心作用是對類、方法】變量、參數和包進行標註,通過反射來訪問這些標註信息,以此在運行時改變所註解對象的行爲。java中的註解由內置註解和元註解組成。
元註解:元註解只要包括四個,用來修飾註解的作用。
- @Retention定義註解的生命週期:【source -> class -> runtime】主要是作用在runtime時。
- @Documented文檔註解,會被javadoc工具文檔化
- @Inherited是否讓子類繼承該註解
- @Target描述了註解的應用範圍。
- type:表示可以用來修飾類、接口、註解類型或枚舉類型
- PACKAGE:可以用來修飾包
- PARAMETER:可以用來修飾參數
- ANNOTATION_TYPE:可以用來修飾註解類型
- METHOD:可以用來修飾方法
- FIELD:可以用來修飾屬性(包括枚舉常量)
- CONSTRUCTOR:可以用來修飾構造器
- LOCAL_VARIABLE:可用來修飾局部變量
自定義一個註解示例:
/**
* 自定義註解
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String name();
}
二、反射
簡介:在運行狀態中,對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱爲Java語言的反射。
反射的優缺點:
- 通過反射可以使程序代碼訪問裝載到JVM中的類的內部信息,獲取已裝載類的屬性信息,獲取已轉載類的方法,獲取已裝載類的構造方法信息
- 反射提高了java程序的靈活性和擴展性,降低耦合性,提高自適應能力。
- 反射會對性能造成一定的影響,同時讓代碼的可讀性變低。
常用的反射API:
方法名 | 返回值 | 參數描述 |
Class.forName(String) | 獲取類的元信息 | 當前類文件的具體位置 |
類.getClass() | 獲取類的元信息 | 無 |
class.getDeclaredFields() | 獲取當前類中的所有屬性 | 無 |
setAccessible(true) | 設置當前屬性爲可見 | true或者false |
getMethods() | 獲取類所有方法 | 無 |
invoke(obj) | 通過反射執行方法 | 類的元信息 |
getAnnotation | 獲取註解 | 需要獲取的註解的Class |
代碼示例:
public static void main(String[] args) throws Exception {
Person p = new Person();
p.setName("hdd");
p.setAge(18);
// 1.通過對象哪去反射對象
Class<? extends Person> aClass = p.getClass();
// 2.通過全類名拿取反射對象
Class<?> aClass1 = Class.forName("com.study.cache.java.reflection.Person");
System.out.println(aClass);
System.out.println(aClass1);
// 獲取類中所有屬性
Field[] fields = aClass1.getDeclaredFields();
for (Field field : fields) {
// 相當於設置了屬性可見和可操作
field.setAccessible(true);
// 獲取字段名稱
String name = field.getName();
// 獲取對應字段設置的值
Object o = field.get(p);
System.out.println(name);
System.out.println(o);
}
// 獲取類中所有方法
Method[] methods = aClass1.getMethods();
for (Method method : methods) {
// 獲取方法名稱
String name = method.getName();
// 調用指定的方法
if (method.getName().equals("testString")) {
Object returnString = method.invoke(p, new String("hello world"));
System.out.println(returnString);
}
}
// 獲取類中註解的方法
Study annotation = aClass1.getAnnotation(Study.class);
String value = annotation.value();
System.out.println(value);
}
三、反射和註解組合使用
通過反射加註解我們來實現自定義sql的編寫:代碼示例如下
定義我們對應的兩個註解:
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {
String value() default "";
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Table {
String name();
}
在用來定一個Person對象,對應字段和註解使用位置如下:
@Table(name = "person")
public class Person {
private String name;
private int age;
@Column(value = "id_card")
private String idCard;
// 省略get/set方法
}
定一個生成sql的util
public class SqlUtil {
public static String createSql(Object o) throws IllegalAccessException {
Class<?> aClass = o.getClass();
StringBuffer sb = new StringBuffer();
StringBuffer whereSql = new StringBuffer();
sb.append("select ");
Field[] declaredFields = aClass.getDeclaredFields();
for (Field field : declaredFields) {
field.setAccessible(true);
Column column = field.getAnnotation(Column.class);
String name = field.getName();
if (column != null) {
String value = column.value();
sb.append(value + ",");
} else {
sb.append(name + ",");
}
Object o1 = field.get(o);
if (o1 instanceof String) {
if (Objects.nonNull(o1)) {
whereSql.append("and ").append(name).append("=").append(o1);
}
} else if (o1 instanceof Integer) {
if ((Integer)o1 != 0) {
whereSql.append("and ").append(name).append("=").append(o1);
}
}
}
sb.deleteCharAt(sb.length() - 1);
sb.append(" from ");
Table annotation = aClass.getAnnotation(Table.class);
String name = annotation.name();
sb.append(name).append(" where 1=1 ");
sb.append(whereSql);
return sb.toString();
}
}
自定義測試類
public static void main(String[] args) throws Exception {
Person person = new Person();
person.setName("hdd");
String sql = SqlUtil.createSql(person);
System.out.println(sql);
}
輸出結果爲:
select name,age,id_card from person where 1=1 and name=hdd