Java註解

一、註解的基本概念

註解是JDK1.5及以後版本引入的,它可以用於創建文檔,跟蹤代碼中的依賴性,甚至執行基本編譯時檢查。註解是以‘@註解名’在代碼中存在的,它可以聲明在包、類、字段、方法、局部變量、方法參數等的前面,用來對這些元素進行說明,註釋。(摘自百度百科
按照運行機制,註解可以分爲三類:1、源碼註解:即註解只在源代碼中存在,在編譯成.class文件後就不存在了;2、編譯時註解:即在源碼和編譯的.class文件中都存在,例如常見的JDK 註解@Override、@Deprecated、@SuppressWarings;3、運行時註解:即註解在運行時仍然存在,甚至可能會影響程序的運行邏輯,例如Spring框架中用到的@Autowired註解。
我們也可以按照來源來將註解劃分爲三類:1、來自JDK的註解,就比如前面提到的@Override、@Deprecated、@SuppressWarings;2、來自第三方框架的註解,例如Spring的@Autowired;3、當然還有我們自己定義的註解。
還有一種特殊的註解,元註解,就是指註解的註解,這在自定義註解時經常使用。

二、自定義註解

我們可以通過自定義註解來實現我們自己想要的功能,下面通過一個簡單的例子來講解一下自定義註解的一些知識,下面的代碼是一個簡單的自定義註解。
package com.imooc.annotation;

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

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

	String name();
	
	int age() default 18;
	
}
首先我們可以看到,我們是使用@interface關鍵字定義註解的,其中註解裏定義的類似於一個方法的例如String name();其實是註解的成員,註解的成員通常以無參無異常的方式聲明的,我們也可以用default關鍵字爲成員指定一個默認值。這裏需要注意的是註解的成員的類型是受限的,只能是基本數據類型或者String,Class,Annotation,Enumeration這幾種類型,如果一個註解只有一個成員,那麼這個成員就必須取名爲value(),在使用註解時可以不顯式聲明成員名稱和等於號(=)。註解也可以沒有成員,沒有成員的註解稱爲標識註解。
除了註解定義的成員,我們發現在註解定義上面還有幾個註解,這些註解就是元註解,下面來簡單分析以下這幾個元註解:@Target表示定義的註解的作用域,通常作用域有constructor(構造方法聲明),field(字段聲明),local_variable(局部變量聲明),method(方法聲明),package(包聲明),parameter(參數聲明),type(類,接口聲明);@Retention表示定義的註解的運行週期,主要包括source:只在源碼顯示,編譯時會丟棄,class:編譯時會記錄到class中,運行時忽略,runtime:運行時存在,可以通過反射讀取;@Inherited表示被註解可以被子類繼承;@Documented表示生成JavaDoc文檔時會將註解寫入文檔。
當我們自定義了一個註解後就可以使用這個註解了,使用註解的語法是:@註解名(成員名=成員值,成員名=成員值……)

三、解析註解

在我們自定義了註解之後,可以通過反射獲取類、方法或成員上運行時的註解信息,從而實現動態控制程序運行時邏輯的目的。下面通過一個實例來解析上面的例子中定義的註解。我們先定義一個類,類名爲Boy,在這個類上和類的方法上使用註解,代碼如下。
package com.imooc.annotation;

@Description(name="A Class boy", age=20)
public class Boy {

	@Override
	@Description(name="A Method boy", age=20)
	public String name() {
		return null;
	}

	@Override
	public int age() {
		return 0;
	}

}
然後我們再寫一個解析註解的類TestAnnotation,通過反射來獲取註解的信息。
package com.imooc.annotation;

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

public class TestAnnotation {

	public static void main(String[] args) {
		//1、獲取Class信息
		Class clazz = Boy.class;
		
		//2、通過反射判斷類上是否存在註解
		if(clazz.isAnnotationPresent(Description.class)) {
			//3、獲取到類上的註解
			Description desc  = (Description) clazz.getAnnotation(Description.class);
			//4、獲取類上註解的信息
			System.out.println("name=" + desc.name() + ",age=" + desc.age());
			
			//5、通過反射獲取類的方法
			Method[] methods = clazz.getMethods();
			for (Method method : methods) {
				//6、判斷方法上是否有註解
				if(method.isAnnotationPresent(Description.class)) {
					//7、獲取方法上的註解
					Description methodDesc = method.getAnnotation(Description.class);
					//8、獲取方法上註解的信息
					System.out.println("第一種方式獲得註解:name=" + methodDesc.name() + ",age=" + methodDesc.age());
				}
				
				//9、獲取方法上所有的註解信息
				Annotation[] anns = method.getAnnotations();
				for (Annotation annotation : anns) {
					//10、遍歷註解獲取對應的註解信息
					if(annotation instanceof Description) {
						Description methodDesc = (Description) annotation;
						System.out.println("第二種方式獲得註解:name=" + methodDesc.name() + ",age=" + methodDesc.age());
					}
				}
				
			}
			
		}
	}

}
運行程序,程序執行如下結果,說明我們自定義的註解解析成功了。
name=A Class boy,age=20
第一種方式獲得註解:name=A Method boy,age=20
第二種方式獲得註解:name=A Method boy,age=20
接下來我們思考一下,定義一個接口Person,然後讓Boy實現這個接口,然後在Person上使用註解,代碼如下:
package com.imooc.annotation;

@Description(name="A Class boy", age=20)
public interface Person {
	@Description(name="A Method boy", age=20)
	public String name();
	
	public int age();
	
}
package com.imooc.annotation;


public class Boy implements Person {

	@Override
	public String name() {
		return null;
	}

	@Override
	public int age() {
		return 0;
	}

}
這時再運行TestAnnotation,我們發現控制檯並沒有打印任何輸出,這說明@Inherited這個元註解對與接口的implements是不起作用的,那如果我們將接口Person改成抽象類,讓Boy繼承這個抽象類結果會是怎樣呢?
package com.imooc.annotation;

@Description(name="A Class boy", age=20)
public abstract class Person {
	@Description(name="A Method boy", age=20)
	public String name(){
		return null;
	}
	
	public int age(){
		return 0;
	}
	
}
package com.imooc.annotation;


public class Boy extends Person {

	@Override
	public String name() {
		return null;
	}

	@Override
	public int age() {
		return 0;
	}

}
運行程序,控制檯打印如下輸出。
name=A Class boy,age=20
這說明@Inherited這個元註解對繼承extends是起作用的,但是隻會繼承類上的註解,並不會繼承該類方法上的註解。

四、一個簡單實例的記錄

這裏簡單記錄一個註解實現的實例,主要用於根據數據庫表和表中的字段進行組合,自動生成相應的SQL,下面是代碼。
package com.imooc.annotation.test;

@Table("user")
public class UserBean {

	@Column("id")
	private int id;
	
	@Column("user_name")
	private String userName;
	
	@Column("nick_name")
	private String nickName;
	
	@Column("age")
	private int age;
	
	@Column("sex")
	private String sex;
	
	@Column("city")
	private String city;
	
	@Column("email")
	private String email;
	
	@Column("phone")
	private String phone;

	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 nickName) {
		this.nickName = nickName;
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getSex() {
		return sex;
	}

	public void setSex(String sex) {
		this.sex = sex;
	}

	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 getPhone() {
		return phone;
	}

	public void setPhone(String phone) {
		this.phone = phone;
	}
}
package com.imooc.annotation.test;

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

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

	String value();
	
}
package com.imooc.annotation.test;

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

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Column {

	String value();
	
}
package com.imooc.annotation.test;

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

public class SQLUtil {

	public static void main(String[] args) throws Exception {
		UserBean user = new UserBean();
		user.setId(1);
		user.setUserName("Jack");
		user.setEmail("[email protected],[email protected],[email protected]");
		
		System.out.println(generateSQL(user));
	}
	
	
	public static String generateSQL(Object obj) throws Exception {
		StringBuffer sb = new StringBuffer();
		
		Class clazz = obj.getClass();
		if(clazz.isAnnotationPresent(Table.class)) {
			Table table = (Table) clazz.getAnnotation(Table.class);
			sb.append("select * form ").append(table.value()).append(" where 1=1 ");
			
			Field[] fields = clazz.getDeclaredFields();
			for(Field field : fields) {
				if(field.isAnnotationPresent(Column.class)) {
					Column column = field.getAnnotation(Column.class);
					String columnName = column.value();
					
					String getMethodName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
					Method getMethod = clazz.getMethod(getMethodName);
					Object returnValue = getMethod.invoke(obj);
					
					if(returnValue instanceof String) {
						if(returnValue != null) {
							if(((String) returnValue).contains(",")) {
								String[] spiltStrs = ((String) returnValue).split(",");
								sb.append(" and " + columnName + " in(");
								
								for (String spiltStr : spiltStrs) {
									sb.append(" '" + spiltStr + "', ");
								}
								sb.append(") ");
							} else {
								sb.append(" and " + columnName + "='" + returnValue + "' ");
							}
						}
					}
					
					if(returnValue instanceof Integer) {
						if((int)returnValue != 0) {
							sb.append(" and " + columnName + "=" + returnValue + " ");
						}
					}
				}
			}
			
			
		}
			
		return sb.toString();
	}

}











發佈了69 篇原創文章 · 獲贊 85 · 訪問量 15萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章