java自定义注解类
一、前言
今天阅读帆哥代码的时候,看到了之前没有见过的新东西, 比如 java 自定义注解类,如何获取注解,如何反射内部类,this$0 是什么意思? 于是乎,学习并整理了一下。
二、代码示例
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;
// 自定义注解类 @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @interface MyAnnotation {String name() default "hjzgg"; }public class Main {
public Main(Class cls) {
Field[] fields = cls.getDeclaredFields();
TestAnnotation obj = null;
try {
obj = (TestAnnotation)cls.getConstructors()[0].newInstance(this);// 获取内部类对象
} catch (Exception e) {
e.printStackTrace();
}
for(Field field : fields) {
System.out.println(field.getName() + " " + field.getType().getName());
if(!field.getName().equals("this$0")) {
MyAnnotation annotation = field.getAnnotation(MyAnnotation.class);// 获取注解类
String name = annotation.name();
field.setAccessible(true);
try {
switch(name) {
case "hjzgg":
switch(field.getType().getName()) {
case "int":
case "java.lang.Integer":
field.set(obj, 555);
break;
case "java.lang.String":
field.set(obj, "hehe");
break;
}
break;
case "lxkdd":
switch(field.getType().getName()) {
case "int":
case "java.lang.Integer":
field.set(obj, 555);
break;
case "java.lang.String":
field.set(obj, "hehe");
break;
}
break;
default:
break;
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
System.out.println(obj);
}</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span> main(String[] args) <span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> InstantiationException, IllegalAccessException { </span><span style="color: rgba(0, 0, 255, 1)">new</span> Main(TestAnnotation.<span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)">); } </span><span style="color: rgba(0, 0, 255, 1)">class</span><span style="color: rgba(0, 0, 0, 1)"> TestAnnotation{ </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> TestAnnotation(){} @MyAnnotation(name</span>="lxkdd"<span style="color: rgba(0, 0, 0, 1)">) </span><span style="color: rgba(0, 0, 255, 1)">private</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> x; @MyAnnotation </span><span style="color: rgba(0, 0, 255, 1)">private</span><span style="color: rgba(0, 0, 0, 1)"> String y; </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> getX() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> x; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span> setX(<span style="color: rgba(0, 0, 255, 1)">int</span><span style="color: rgba(0, 0, 0, 1)"> x) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.x =<span style="color: rgba(0, 0, 0, 1)"> x; } </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String getY() { </span><span style="color: rgba(0, 0, 255, 1)">return</span><span style="color: rgba(0, 0, 0, 1)"> y; } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> setY(String y) { </span><span style="color: rgba(0, 0, 255, 1)">this</span>.y =<span style="color: rgba(0, 0, 0, 1)"> y; } @Override </span><span style="color: rgba(0, 0, 255, 1)">public</span><span style="color: rgba(0, 0, 0, 1)"> String toString() { </span><span style="color: rgba(0, 0, 255, 1)">return</span> "x: " + x + ", y: " +<span style="color: rgba(0, 0, 0, 1)"> y; } }
}
三、代码分析
1. 如何编写自定义注解
public @interface MyAnnotation {String value() default "hahaha"; }
感觉等价于
public class MyAnnotation extends java.lang.annotation.Annotation{ private String value = "hahaha"; public void setValue(String value){ this.value = value; } public String getValue(){ return value; } }
自定义注解类规则
@interface 实际上是继承了 java.lang.annotation.Annotation, 所以定义 annotation 时不能继承其他 annotation 或 interface. java.lang.annotation.Retention 告诉编译器如何对待 Annotation, 使用 Retention 时, 需要提供 java.lang.annotation.RetentionPolicy 的枚举值.
public enum RetentionPolicy { SOURCE, // 编译器处理完 Annotation 后不存储在 class 中 CLASS, // 编译器把 Annotation 存储在 class 中,这是默认值 RUNTIME // 编译器把 Annotation 存储在 class 中,可以由虚拟机读取, 反射需要 }
java.lang.annotation.Target 告诉编译器 Annotation 使用在哪些地方, 使用需要指定 java.lang.annotation.ElementType 的枚举值.
public enum ElementType { TYPE, // 指定适用点为 class, interface, enum FIELD, // 指定适用点为 field METHOD, // 指定适用点为 method PARAMETER, // 指定适用点为 method 的 parameter CONSTRUCTOR, // 指定适用点为 constructor LOCAL_VARIABLE, // 指定使用点为 局部变量 ANNOTATION_TYPE, //指定适用点为 annotation 类型 PACKAGE // 指定适用点为 package }
java.lang.annotation.Documented 用于指定该 Annotation 是否可以写入 javadoc 中.
java.lang.annotation.Inherited 用于指定该 Annotation 用于父类时是否能够被子类继承.
示例
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;@Documented //这个 Annotation 可以被写入 javadoc
@Inherited //这个 Annotation 可以被继承
@Target({ElementType.CONSTRUCTOR,ElementType.METHOD}) //表示这个 Annotation 只能用于注释 构造子和方法
@Retention(RetentionPolicy.CLASS) //表示这个 Annotation 存入 class 但 vm 不读取
public @interface MyAnnotation {
String value() default "hahaha";
}
2. 如何获取自定义注解
java.lang.reflect.AnnotatedElement 接口提供了四个方法来访问 Annotation
public Annotation getAnnotation(Class annotationType); public Annotation[] getAnnotations(); public Annotation[] getDeclaredAnnotations(); public boolean isAnnotationPresent(Class annotationType);
来自:http://blog.csdn.net/foamflower/article/details/5946451
Class、Constructor、Field、Method、Package 等都实现了该接口, 可以通过这些方法访问 Annotation 信息, 前提是要访问的 Annotation 指定 Retention 为 RUNTIME.
Java 内置的 annotation 有 Override Deprecated SuppressWarnings.
Override 只用于方法, 它指明注释的方法重写父类的方法, 如果不是, 则编译器报错.
Deprecated 指明该方法不建议使用.
SuppressWarnings 告诉编译器: 我知道我的代码没问题.
3.this$0 是什么意思?
public class Outer {//this$0 public class FirstInner {//this$1 public class SecondInner {//this$2 public class ThirdInner { } } }
}
说一个场景:当我们拿到了一个内部类的对象 Inner,但是又想获取其对应的外部类 Outer,那么就可以通过 this$0 来获取。this$0 就是内部类所自动保留的一个指向所在外部类的引用。
//通过工具获取到 Inner 实例对象 Outer.Inner inner = getInner(); //获取内部类 Inner 的一个字段 this$0 信息 //this$0 特指该内部类所在的外部类的引用, 不需要手动定义, 编译时自动加上 Filed outerField = inner.getClass().getDeclaredField("this$0"); //this$0 是私有的, 提升访问权限 outerField.setAccessible(true); //拿到该字段上的实例值 Outer outer = (Outer)outerField.get(inner);
4.java 如何反射内部类
Class<?> cls = Class.forName("package.OuterClass$InnerClass"); or Class<?> cls = OuterClass.InnerClass.class;
(1)OuterClass.InnerClass obj = (OuterClass.InnerClass)cls.getConstructors()[0].newInstance(new OuterClass());
(2)OuterClass.InnerClass obj = (OuterClass.InnerClass)cls.getConstructor(OuterClass.class).newInstance(new OuterClass());
由此可见,内部类的无参构造器在通过反射机制获取时,要指定其父类参数才可以获得,否则将报如下异常:
java.lang.NoSuchMethodException: com.hjzgg.OuterClass$InnerClass.<init>() at java.lang.Class.getConstructor0(Class.java:3082) at java.lang.Class.getConstructor(Class.java:1825)