java中注解默认实现annotation接口,一般我们自定义注解的时候主要使用的是两个元注解(其他两个@Documented 与 @Inherited基本没怎么使用过)看下面
主要限制可以应用注解的java元素类型 ElementType.ANNOTATION_TYPE 可以应用于注解类型。 ElementType.CONSTRUCTOR 可以应用于构造函数。 ElementType.FIELD 可以应用于字段或属性。 ElementType.LOCAL_VARIABLE 可以应用于局部变量。 ElementType.METHOD 可以应用于方法级注解。 ElementType.PACKAGE 可以应用于包声明。 ElementType.PARAMETER 可以应用于方法的参数。 ElementType.TYPE 可以应用于类的任何元素。
RetentionPolicy.CLASS RetentionPolicy.SOURCE RetentionPolicy.RUNTIME
仅仅保留在源码中,被编译器忽略,主要应用场景是apt技术,在编译期能够获取注解与注解声明的类包括类中所有成员信息,一般用于生成额外的辅助类。还有语法检查,类似@IntDef这种
会被编译器保留,但是会被jvm忽略,用处主要是用在字节码增强技术,在编译出Class后,通过修改Class数据以实现修改代码逻辑目的。对于是否需要修改的区分或者修改为不同逻辑的判断可以使用注解。
用的比较多,主要是通过反射技术动态获取注解元素
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface lengthTest {
int max() default 0;
int min() default 0;
String dec() default "";
}
public class AnnLoginModel {
private int age;
@lengthTest(max = 10,min = 6,dec = "kkk")
private String desc;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
}
public static void vaild(Object o) throws Exception{
Class<?> ls = o.getClass();
Field[] fields = ls.getDeclaredFields();
for (Field field:fields) {
lengthTest lengthTest = field.getAnnotation(lengthTest.class);
if(lengthTest!=null){
if(field.getGenericType().toString().equals("class java.lang.String")){
field.setAccessible(true);
String i = (String) field.get(o);
if(i.length()>lengthTest.min()&&i.length()< lengthTest.max()){
System.out.print("没超过");
}else{
System.out.print("超过");
}
}
}
}
}
public static void main(String[] args) throws Exception {
AnnLoginModel annLoginModel = new AnnLoginModel();
annLoginModel.setAge(2);
annLoginModel.setDesc("傻子");
vaild(annLoginModel);
}
这是注解加反射进行参数校验的简单例子
反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和 方法;对于任意一个对象,都能够调用它的任意方法和属性;并且能改变它的属性。是Java被视为动态语言的关键。
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface ViewInject {
int value();
}
activity中
@ViewInject(R.id.bt)
Button bt;
@ViewInject(R.id.tv)
TextView tv;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_annotation);
MyViewInject.ViewInject(this);
}
public static void ViewInject(Activity activity) {
Class<? extends Activity> ls = activity.getClass();
for (Field field : ls.getDeclaredFields()) {
ViewInject an = field.getAnnotation(ViewInject.class);//判断是否是viewinject注解
if (an != null) {
try {
field.setAccessible(true);//设置访问权限,应许操作private的属性
Method method = ls.getDeclaredMethod("findViewById", int.class);//拿取activity的findviewbyid方法,当然你也可以直接使用ls.findviewbyid
View view = (View) method.invoke(activity, an.value());//method(ac,an.value)第一个参数在哪个对象上设置调用,第二个参数方法的参数
field.set(activity, view);//反射字段属性赋值
} catch (Exception e) {
}
}
}
简单例子
一般可以通过类名,对象获取
可以通过class对象的newinstance,或者构造方法constructor.newInstance 其他方法懒的介绍有点多
Method#invoke 需要进行自动拆装箱 反射需要按照名检索方法和参数,需要检查方法可见性参数一致性,编译器无法对动态调用的代码做优化,比如内联
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文系转载,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。