Java中的註解

1、什麼是註解?

註解(也被稱爲 元數據)爲我們在代碼中添加信息提供了一種形式化的方法,使我們可以在稍後某個時刻非常方便地使用這些數據。

2、標準註解與元註解

Java內置了三種標準註解和四種元註解

3種標準註解(定義在java.lang中):

@Override  表示當前的方法定義將覆蓋超類中的方法。如果你不小心拼寫錯誤,或者方法簽名對不上覆蓋的方法,編譯器就會發出錯誤提示。

@Deprecated  如果程序員使用了註解爲它的元素,那麼編譯器會發出警告信息。

@SuppressWarning 關閉當前的編譯器警告信息。

4種元註解(元註解專職負責註解其他的註解)

@Target  表示該註解可以用於什麼地方。可能的ElementType參數包括:

CONSTRUCTOR:構造器的聲明

FIELD:域聲明(包括enum實例)

LOCAL_VARIABLE:局部變量聲明

METHOD:方法聲明

PACKAGE:包聲明

PARAMETER:參數聲明

TYPE:類、接口(包括註解類型)或enum聲明

@Retention 表示需要在什麼級別保存該註解信息。可選的RetentionPolicy參數包括:

SOURCE:註解將被編譯器丟棄

CLASS:註解在class文件中可用,但會被VM丟棄

RUNTIME:VM將在運行期也保留註解,因此可以通過反射機制讀取註解的信息

@Document 將此註解包含在Javadoc中

@Inherited 允許子類繼承父類中的註解

3、自定義一個註解

自定義一個簡單的註解(沒有元素的註解稱爲標記註解)

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {}
自定義一個包含元素的註解

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

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {

	public int id();
	
	public String description() default "no description";
}

4、使用自定義註解

import java.util.List;

import com.zhangmingji.annotation.UseCase;

public class PasswordUtils {

	@UseCase(id=47, description="password must contain at least one numeric")
	public boolean validatePassword(String password){
		return (password.matches("\\w*\\d\\w*"));
	}
	
	@UseCase(id=48)
	public String encryptPassword(String password){
		return new StringBuilder(password).reverse().toString();
	}
	
	@UseCase(id=49, description="New passwords can't equal previously used ones")
	public boolean checkForNewPassword(List<String> prePasswords, String password){
		return !prePasswords.contains(password);
	}
	
	
}
5、編寫註解處理器

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.zhangmingji.annotation.UseCase;
import com.zhangmingji.use.PasswordUtils;

public class UseCaseTracker {

	public static void trackUseCases(List<Integer> useCases, Class<?> cl){
		for(Method m : cl.getDeclaredMethods()){
			UseCase uc = m.getAnnotation(UseCase.class);
			if(uc != null){
				System.out.println("Found Use Case:" + uc.id() + " " + uc.description());
				useCases.remove(new Integer(uc.id()));
			}
		}
		for(int i : useCases){
			System.out.println("Warning: Missing use case-" + i);
		}
	}
	
	public static void main(String[] args) {
		List<Integer> useCases = new ArrayList<Integer>();
		Collections.addAll(useCases, 47, 48, 49, 50);
		trackUseCases(useCases, PasswordUtils.class);
	}
	
	
}

運行結果:

Found Use Case:47 password must contain at least one numeric
Found Use Case:48 no description
Found Use Case:49 New passwords can't equal previously used ones
Warning: Missing use case-50
6、註解元素

在前面我們已經定義了一個包含元素id、description的註解,

註解元素可用的類型如下:

所有基本類型(int,float,boolean

String

Class

enum

Annotation

以上類型的數組

如果你使用了其他類型,那麼編譯器就會報錯;也不允許使用任何包裝類型;註解也可以作爲基本元素類型,也就是說註解可以嵌套

7、默認值限制
(1)、元素不能有不確定的值。也就是說,元素必須要麼具有默認值,要麼使用註解時提供元素的值。

(2)、對於非基本類型的元素,無論在源代碼中聲明時,或是在註解接口中定義默認值時,都不能以null作爲其值。

(3)、註解不支持繼承。

8、通過註解生成建表語句

package com.zhangmingji.annotation;

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

@Target(ElementType.TYPE)//類、接口、或者ENUM聲明
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {

	public String name() default "";
}

package com.zhangmingji.annotation;

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 Constraints {

	boolean primaryKey() default false;
	boolean allowNull() default true;
	boolean unique() default false;
}

package com.zhangmingji.annotation;

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 SQLString {

	int value() default 0;
	String name() default "";
	Constraints constraints() default @Constraints;
}

package com.zhangmingji.annotation;

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 SQLInteger {

	String name() default "";
	Constraints constraints() default @Constraints;
}

使用以上自定義的註解

package com.zhangmingji.use;

import com.zhangmingji.annotation.Constraints;
import com.zhangmingji.annotation.DBTable;
import com.zhangmingji.annotation.SQLInteger;
import com.zhangmingji.annotation.SQLString;

@DBTable(name="MEMBER")
public class Member {

	@SQLString(30) String firstName;
	@SQLString(50) String lastName;
	@SQLInteger Integer age;
	@SQLString(value=30, constraints=@Constraints(primaryKey=true))
	String handle;
	static int memberCount;
	public String getHandle(){
		return this.handle;
	}
	
	public String getFirstName(){
		return this.firstName;
	}
	
	public String getLastName(){
		return this.lastName;
	}
	
	public String toString(){
		return handle;
	}
	
	public Integer getAge(){
		return age;
	}
}

實現處理器

package com.zhangmingji.process;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;

import com.zhangmingji.annotation.Constraints;
import com.zhangmingji.annotation.DBTable;
import com.zhangmingji.annotation.SQLInteger;
import com.zhangmingji.annotation.SQLString;

public class TableCreator {

	public static void main(String[] args) throws Exception {
		if(args.length < 1){
			System.out.println("arguments: anotationed classes");
			System.exit(0);
		}
		for(String className : args){
			Class<?> cl = Class.forName(className);
			DBTable dbTable = cl.getAnnotation(DBTable.class);
			if(null == dbTable){
				System.out.println("no DBTable anotations in class " + className);
				continue;
			}
			String tableName = dbTable.name();
			//如果名字爲空,則使用類名
			if(tableName.length() < 1){
				tableName =  cl.getName().toUpperCase();
			}
			List<String> columDefs = new ArrayList<String>();
			for(Field field : cl.getDeclaredFields()){
				String columName = null;
				Annotation[] anns = field.getDeclaredAnnotations();
				if(anns.length < 1){
					continue; //
				}
				if(anns[0] instanceof SQLInteger){
					SQLInteger sInt = (SQLInteger) anns[0];
					//如果沒有指定名稱,則使用屬性名稱
					if(sInt.name().length() < 1){
						columName = field.getName().toUpperCase();
					}else{
						columName = sInt.name();
					}
					columDefs.add(columName + " INT" + getConstraints(sInt.constraints()));
				}
				if(anns[0] instanceof SQLString){
					SQLString sString = (SQLString) anns[0];
					if(sString.name().length() < 1){
						columName = field.getName().toUpperCase();
					}else{
						columName = sString.name();
					}
					columDefs.add(columName + " VARCHAR(" + sString.value() + ")" 
					+ getConstraints(sString.constraints()));
				}
			}
			StringBuilder createCommand = new StringBuilder("CREATE TABLE " + tableName + "(");
			for(String columDef : columDefs){
				createCommand.append("\n " + columDef + "," );
			}
			String tableCreate = createCommand.substring(0, (createCommand.length() - 1)) + ");";
			System.out.println("Table create SQL for " + className + " is :\n" + tableCreate);
		}
	}
	
	/**
	 * 構造約束
	 * @param con
	 * @return
	 */
	public static String getConstraints(Constraints con){
		String contraints = "";
		if(!con.allowNull()){
			contraints += " NOT NULL";
		}
		if(con.primaryKey()){
			contraints += " PRIMARY KEY";
		}
		if(con.unique()){
			contraints += " UNIQUE";
		}
		return contraints;
	}
}

運行結果:

Table create SQL for com.zhangmingji.use.Member is :
CREATE TABLE MEMBER(
 FIRSTNAME VARCHAR(30),
 LASTNAME VARCHAR(50),
 AGE INT,
 HANDLE VARCHAR(30) PRIMARY KEY);

以上內容來自《Java編程思想》第四版,僅作爲學習和總結。











發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章