注解是向代码中添加信息的一种方法,并且在之后还可以使用这些数据
就比如这个方法是用来剥香蕉的,但是我们看就是一串代码,我们没办法在代码里写一段指令说“我这个程序是用来剥香蕉的”,当然除了注释。而这可以通过注解办到,在代码中以Java指令语言的形式化方法来为代码提供更多信息。
一、基本语法
1.定义注解
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);
}
}
这是个注解的简单应用,通过这些注解,我们在阅读代码的时候可以更清晰的获取更多信息
2.元注解
二、编写注解处理器
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语言之一,也正是因为有可以读取注解的方法,所以注解才强于直接注释。
在上面的例子中我们可以看出,可以将各个方法的注解信息读取出来
1.注解元素
就像之前的id和dicription一样,这叫做注解元素,可用类型如下:
2.默认值的限制
就是注解元素必须有一个确认的值,没有不行,空也不行,那假如就是空的就是不存在咋整呢。
所以我们只能定义一些特殊的值来解决
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface SimulatingNull{
public int id() default -1;
public String decription() default "";
}
3.生成外部文件
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;
}
这样就用一个注解就可以套上各种类型,不过这样就不能针对不同类型设计具有针对性的注解元素了
我们还可以为一个元素打上俩注解,这没什么,就是乱了点
4.注解不支持继承
不让继承,别逼逼
5.实现处理器
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语句。也就是说把注解信息提取了出来。
三、使用apt处理注解
说实话,没看懂
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
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。