注解是向代码中添加信息的一种方法,而且在以后还可使用这些数据
就好比这个方法是用来剥香蕉的,可是咱们看就是一串代码,咱们没办法在代码里写一段指令说“我这个程序是用来剥香蕉的”,固然除了注释。而这能够经过注解办到,在代码中以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