註解是向代碼中添加信息的一種方法,而且在以後還可使用這些數據
就好比這個方法是用來剝香蕉的,可是咱們看就是一串代碼,咱們沒辦法在代碼裏寫一段指令說「我這個程序是用來剝香蕉的」,固然除了註釋。而這能夠經過註解辦到,在代碼中以Java指令語言的形式化方法來爲代碼提供更多信息。java
package tij.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class AnnotationTest { } class Testable { void execute() { System.out.println("Executing..."); } @Test void testExecute() { execute(); } } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface Test {}
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface UseCase { public int id(); public String description() default "no description"; } class PasswordUtils { @UseCase(id = 47, description = "Passwords 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> prevPasswords, String password) { return !prevPasswords.contains(password); } }
這是個註解的簡單應用,經過這些註解,咱們在閱讀代碼的時候能夠更清晰的獲取更多信息數據庫
package tij.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class AnnotationTest { 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); } } @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface UseCase { public int id(); public String description() default "no description"; } class PasswordUtils { @UseCase(id = 47, description = "Passwords 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> prevPasswords, String password) { return !prevPasswords.contains(password); } }
由於註解是Java語言之一,也正是由於有能夠讀取註解的方法,因此註解才強於直接註釋。
在上面的例子中咱們能夠看出,能夠將各個方法的註解信息讀取出來app
就像以前的id和dicription同樣,這叫作註解元素,可用類型以下:ide
就是註解元素必須有一個確認的值,沒有不行,空也不行,那假如就是空的就是不存在咋整呢。
因此咱們只能定義一些特殊的值來解決單元測試
@Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @interface SimulatingNull{ public int id() default -1; public String decription() default ""; }
package tij.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class AnnotationTest { public static void main(String[] args) {} } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface DBTable { public String name() default ""; } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface Constraints { boolean primaryKey() default false; boolean allowNull() default true; boolean unique() default false; } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface SQLString { int value() default 0; String name() default ""; Constraints constraints() default @Constraints; } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface SQLInteger { String name() default ""; Constraints constraints() default @Constraints; } @DBTable(name = "MEMBER") class Member { @SQLString(30) String firstName; @SQLString(50) String lastName; @SQLString Integer age; @SQLString(value = 30, constraints = @Constraints(primaryKey = true)) String handle; static int memberCount; public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public Integer getAge() { return age; } public String getHandle() { return handle; } public String toString() { return handle; } }
其實這段代碼很好的舉了個註解運用的例子,
@Target(ElementType.TYPE)這個東西告訴編譯器,這條註解要用在類聲明上,就像DBTable同樣,這個註解放在了class Member以前
@Target(ElementType.FIELD)這個東西告訴編譯器,這條註解要放在域聲明以前。
另外,若是隻有一個名字叫作value的元素須要賦值的時候,就不須要「key=value」這種賦值,不用key,默認的。
不過,爲了每一個類型都設計一個註解未免太麻煩了,咱們能夠這麼作測試
enum Type{ String,Integer,Float; } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface TableColumn { Type type() default Type.String; Constraints constraints() default @Constraints; }
這樣就用一個註解就能夠套上各類類型,不過這樣就不能針對不一樣類型設計具備針對性的註解元素了ui
咱們還能夠爲一個元素打上倆註解,這沒什麼,就是亂了點this
不讓繼承,別逼逼spa
package tij.annotation; import java.lang.annotation.Annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.List; public class AnnotationTest { public static void main(String[] args) { DBTable dbTable = Member.class.getAnnotation(DBTable.class); String tableName = dbTable.name(); List<String> columnDefs = new ArrayList<String>(); for (Field field : Member.class.getFields()) { System.out.println(field.getName()); String columnName = 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) columnName = field.getName(); else columnName = sInt.name(); columnDefs.add(columnName + " INT" + getConstraints(sInt.constraints())); } if (anns[0] instanceof SQLString) { SQLString sString = (SQLString) anns[0]; if (sString.name().length() < 1) columnName = field.getName(); else columnName = sString.name(); columnDefs.add(columnName + " VARCHAR(" + sString.value() + ")" + getConstraints(sString.constraints())); } } StringBuilder createCommand = new StringBuilder( "CREATE TABLE " + tableName + "("); for (String columnDef : columnDefs) { createCommand.append("\n\t" + columnDef + ","); } String tableCreate = createCommand.substring(0, createCommand.length() - 1) + ");"; System.out.println("Table Creation SQL for" + Member.class + " is:\n" + tableCreate); } private static String getConstraints(Constraints con) { String constraints = ""; if (!con.allowNull()) constraints += " NOT NULL "; if (con.primaryKey()) constraints += " PRIMARY KEY "; if (con.unique()) constraints += " UNIQUE "; return constraints; } } @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @interface DBTable { public String name() default ""; } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface Constraints { boolean primaryKey() default false; boolean allowNull() default true; boolean unique() default false; } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface SQLString { int value() default 0; String name() default ""; Constraints constraints() default @Constraints; } @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface SQLInteger { String name() default ""; Constraints constraints() default @Constraints; } @DBTable(name = "MEMBER") class Member { @SQLString(30) public String firstName; @SQLString(50) public String lastName; @SQLString public Integer age; @SQLString(value = 30, constraints = @Constraints(primaryKey = true)) public String handle; static int memberCount; public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public Integer getAge() { return age; } public String getHandle() { return handle; } public String toString() { return handle; } }
這段代碼超棒,實際的告訴你這些註解到底怎麼用,有什麼用。有註解的說明這個成員變量是一個列名,而後根據註解信息來生成相應的SQL語句。也就是說把註解信息提取了出來。設計
說實話,沒看懂
package tij.annotation; import java.io.IOException; import java.io.PrintWriter; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Set; import com.sun.mirror.apt.AnnotationProcessor; import com.sun.mirror.apt.AnnotationProcessorEnvironment; import com.sun.mirror.apt.AnnotationProcessorFactory; import com.sun.mirror.declaration.AnnotationTypeDeclaration; import com.sun.mirror.declaration.MethodDeclaration; import com.sun.mirror.declaration.ParameterDeclaration; import com.sun.mirror.declaration.TypeDeclaration; public class AnnotationTest { public static void main(String[] args) {} } @ExtractInterface("IMultipier") class Multiplier { public int multiply(int x, int y) { int total = 0; for (int i = 0; i < x; i++) { total = add(total, y); } return total; } private int add(int x, int y) { return x + y; } public static void main(String[] args) { Multiplier m = new Multiplier(); System.out.println("11*16=" + m.multiply(11, 16)); } } @Target(ElementType.TYPE) @Retention(RetentionPolicy.SOURCE) @interface ExtractInterface { public String value(); } class InterfaceExtractorProcessor implements AnnotationProcessor { private final AnnotationProcessorEnvironment env; private ArrayList<MethodDeclaration> interfaceMethods = new ArrayList<MethodDeclaration>(); public InterfaceExtractorProcessor(AnnotationProcessorEnvironment env) { this.env = env; } @Override public void process() { for (TypeDeclaration typeDec1 : env.getSpecifiedTypeDeclarations()) { ExtractInterface annot = typeDec1 .getAnnotation(ExtractInterface.class); if (annot == null) break; for (MethodDeclaration m : typeDec1.getMethods()) if (m.getModifiers().contains(Modifier.STATIC) && !(m.getModifiers().contains(Modifier.STATIC))) interfaceMethods.add(m); if (interfaceMethods.size() > 0) { try { PrintWriter writer = env.getFiler() .createSourceFile(annot.value()); writer.println("package" + typeDec1.getPackage().getQualifiedName() + ";"); writer.println("public interface " + annot.value() + " {"); for (MethodDeclaration m : interfaceMethods) { writer.print(" public "); writer.print(m.getReturnType() + " "); writer.print(m.getSimpleName() + " ("); int i = 0; for (ParameterDeclaration parm : m.getParameters()) { writer.print(parm.getType() + " " + parm.getSimpleName()); if (++i < m.getParameters().size()) writer.print(", "); } writer.println(");"); } writer.println("}"); writer.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } } } } } class InterfaceExtractorProcessorFactory implements AnnotationProcessorFactory { @Override public AnnotationProcessor getProcessorFor( Set<AnnotationTypeDeclaration> atds, AnnotationProcessorEnvironment env) { return new InterfaceExtractorProcessor(env); } @Override public Collection<String> supportedAnnotationTypes() { return Collections.singleton("annotations.ExtractInterface"); } @Override public Collection<String> supportedOptions() { return Collections.emptySet(); } }
QNMLGB的不看了老子
end