做帮助手册的网站,电子商务公司名字,在线域名ip查询,wordpress手机页面底部导航转载自 Java和Android中的注解1.引言
从JDK1.5开始#xff0c;引入了注解类Annotation#xff0c;Annotation其实是一种接口#xff0c;可以作用于类、方法、属性等等 #xff0c;它可以通过反射机制来访问annotation信息#xff0c;获取所加上注解信息#xff0c;做相应…转载自 Java和Android中的注解1.引言
从JDK1.5开始引入了注解类AnnotationAnnotation其实是一种接口可以作用于类、方法、属性等等 它可以通过反射机制来访问annotation信息获取所加上注解信息做相应的操作。相当于给相关的作用对象打上“tag”使用方便作用广泛。
2.java.lang中的注解在java.lang中用到三种注解类即常用到的Deprecated,Override和SuppressWarnings.2.1 Deprecated 过时在使用Eclipse或AS编写程序过程中有一些方法编写出来之后被画上了中划线表示该方法已过时建议使用新的一些方法代替。 如viewPager.setOnPageChangeListener()方法在安卓API23中已过时在源代码中的该方法上赫然多了一个注解Deprecated可使用addOnPageChangeListener()方法代替。 如果使用javac命令编译会弹出”注意使用或覆盖了已过时的API“2.2 Override 复写这是开发过程中最常遇到的注解了表示复写父类中的方法。如果方法上有这条注解但没有重写父类方法则会生成一条错误消息。这个注解有效地保证了方法一定会被复写。比如开发过程中手动在子类中复写父类方法只正确写出了方法名称未写正确方法的参数则相当于方法的重载并不是复写。这种问题如果在功能上有错误产生在检查过程中是很难找到的。使用Override注解有效地表明此方法是复写父类的方法不会产生手动的错误问题。2.3 SuppressWarnings 阻止警告阻止了弹出的警告比如屏蔽对上述过时的提示可在调用setOnPageChangeListener()方法之上加上SuppressWarnings(deprecation)这样虽然在IDE中仍以中划线的形式表示但如果使用javac命令就不再提示警告。
3.元注解那么以上的注解类的源码又是什么样的呢打开Override发现其代码如下
Target(ElementType.METHOD)
Retention(RetentionPolicy.SOURCE)
public interface Override {
}
这里可以发现注解类的定义方法以及注解类上所加的注解——元注解。元注解有四个位于java.lang.annotation包中DocumentedInheritedRetentionTarget3.1Target表示注解作用的目标。
Documented
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.ANNOTATION_TYPE)
public interface Target { ElementType[] value();
}
注解可以作用的目标由枚举类ElementType决定可作用于类、方法、属性等数组表示注解可以有多个作用域。
public enum ElementType { TYPE,// 类、接口、注解类型或枚举 FIELD, //属性 METHOD, //方法 PARAMETER,// 用于描述参数 CONSTRUCTOR,//构造方法 LOCAL_VARIABLE,//局部变量 ANNOTATION_TYPE,//注解类 PACKAGE //包
}
注解作用于类时定义Target(ElementType.TYPE)ElementType .TYPE表示类型Class,Interface等都实现了java中的Type接口因此ElementType.TYPE 表示注解作用于这些类并不是单纯的Class类3.2Retention表示注解的作用时段
Documented
Retention(RetentionPolicy.RUNTIME)
Target(ElementType.ANNOTATION_TYPE)
public interface Retention { RetentionPolicy value();
}
由此可见Retention定义的是RetentionPolicy类型的数据RetentionPolicy是一个枚举类型包括SOURCE,CLASS,RUNTIME三个类型。表示注解保留的阶段。SOURCE表示注解只在源文件中保留CLASS表示注解保留到.class文件中RUNTIME表示注解一直保留到内存中类加载器把.class文件加载到内存中产生的字节码中要保留注解信息。可想而知Override仅在写代码时用到其Retention中的值为RetentionPolicy.SOURCESuppressWarnings也只是编译器使用的保留到SOURCE阶段。而Deprecated在内存中也需要保留编译器需要得知方法是否过时从加载到内存中的二进制文件中获取因而要保留到RUNTIME阶段3.3Documented
注解只是一个标记的话那么使用javadoc生成文档时这些注解都不会存在于文档中要使注解在文档中也存在就可以在使用了注解的作用对象上加上Documented这个注解。javadoc所生成的文档就会带上注解信息。3.4Inherited
该注解表示子类可以集成加载父类上的注解。但要注意1.注解定义在类上面子类是可以继承该注解2.注解定义在方法上面子类也可以继承该注解但是如果子类复写了父类中定义了注解的方法那么子类将无法继承该方法的注解也就是说子类在复写父类中被Inherited标注的方法时会将该方法上面的注解覆盖掉3.Interface的实现类implements实现无法继承接口中所定义的被Inherited标注的注解4.注解的参数
在注解后为注解增加参数如上述的Retention、Target后的括号中就是注解的参数。参数的类型支持基本数据类型、String类型、Class类型、enum类型、Annotation类型以及上述所有类型的数组。当注解只有一个参数时可以用value作为参数名称在使用参数时只用在括号中写参数的值而不用写参数名称。若存在多个参数时需写上对应的参数名并赋值如Subscribe(tagxx)若参数为数组类型则需赋值形如Target({ElementType.TYPE,ElementType.METHOD})5.自定义注解
从上面的注解中也大致看到了注解的定义方式。1.使用interface定义一个注解类其内部自行继承了Annotation类。2.在该类中定义注解的参数定义方式很像方法。3.注解元素必须有确定的值要么在定义注解的默认值中指定要么在使用注解时指定非基本类型的注解元素的值不可为null。因此, 使用空字符串或0作为默认值是一种常用的做法。定义一些特殊的值例如空字符串或者负数表示某个元素不存在参数设置默认值时后面跟上default即可设置默认值。4.当注解的参数只有一个时建议用value作为参数名这样在使用注解时可以直接写参数的值接下来自定义一个注解类Documented
Target(ElementType.TYPE)
Retention(RetentionPolicy.RUNTIME)
public interface Car{ String name() default ; int number() default -1;
}
再定义一个类去使用这个注解Car(name好车,number666)
public class CarBMW(){ }
那么如何获取这些注解值呢有如下的方法if(CarBMW.class.isAnnotationPresent(Car.class)){//判断CarBMW类是否有注解类Car Car carAnnotation(Car)CarBMW.class.getAnnotation(Car.class);//获取注解实例对象 Log.v(Shawn,carAnnotation.name());//获取name参数的值 Log.v(Shawn,carAnnotation.number());//获取number参数的值
}
5.1 JAVA8中注解的补充
在JAVA8中增加了TypeAnnotation在 Java 8 之前的版本中只能允许在声明式前使用 Annotation。而在 Java 8 版本中Annotation 可以被用在任何使用 Type 的地方例如初始化对象时 (new)对象类型转化时。
//初始化对象时
String myString new NotNull String();
//对象类型转化时
myString (NonNull String) str;
这点上有点类似Android中的注解使用。而ElementType中增加了俩个值ElementType.
T
YPE_PARAMETER
和ElementType.
TYPE_USE正是为此功能实现而产生的。ElementType.
TYPE_PARAMETER表示这个 Annotation 可以用在 Type 的声明式前而 ElementType
.TYPE_USE
表示这个 Annotation 可以用在所有使用 Type 的地方如泛型类型转换等。Type Annotation 也可以通过设置 Retention 在编译后保留在 class 文件中RetentionPolicy.CLASS或者运行时可访问RetentionPolicy.RUNTIME。但是与之前不同的是Type Annotation 有两个新的特性在本地变量上的 Annotation 可以保留在 class 文件中以及泛型类型可以被保留甚至在运行时被访问。此外JAVA8中还增加了一个特性RepeatingAnnotation允许为同一个声明式或者类型加上相同的 Annotation。例如一个类可以被两个人使用
Worker(roleXiaoMing)
Worker(roleXiaoHong)
public class Person { ...
}
需要需要重复标注特性的 Annotation 前加上 Repeatable 标签
Repeatable(Workers.class)
public interface Worker{ String role();
}
Repeatable 标签后括号中的值即为指定的 Container Annotation 的类型。在这个例子中Container Annotation 的类型是 WorkersJava 编译器会把重复的 Worker 对象保存在 Workers中。Workers中必须定义返回数组类型的value()方法。数组中元素的类型必须为对应的 Repeating Annotation 类型。具体示例如下
public interface Workers{ Worker[] value();
}
获取注解的方法有两种
一种方式是用过 上述的的 getAnnotations(ClassT) 方法一次性返回 Repeating Annotation。
另一种方式是通过 AnnotatedElement 接口的 getAnnotationByType(ClassT) 首先获得 Container Annotation然后再通过 Container Annotation 的 value 方法获得 Repeating Annotation。
Workers workers Person.class.getAnnotation(Workers.class);
Worker[] workers2 Person.class.getAnnotationsByType(Worker.class);
以上关于JAVA8中的注解参考
http://www.ibm.com/developerworks/cn/java/j-lo-java8annotation/index.html6.Android中的注解
6.1两个常见的注解
Android从API16引入了annotation包包括两个注解TargetApi和SuppressLintTargetApi (Build.VERSION_CODES.XX)用于屏蔽某一新api中才能使用的方法报的lint检查出现的错误。SuppressLint(NewApi) 屏蔽一切新api中才能使用的方法报的android lint错误当然这两个注解的作用仅仅是屏蔽lint错误在方法中还要判断版本做不同的操作比如if (Build.VERSION.SDK_INT Build.VERSION_CODES.XX) { //高于XX版本进行的操作
} else { //低于XX版本进行的操作
} 6.2Android中用到的注解
API19引入了很多注解起初是以jar包形式引入的放在SDK目录下sdk\extras\android\m2repository\com\android\support\support-annotations\在API21之后直接放入了annotation包中Android中的注解分为八类在API23中有42个注解类6.2.1 CallSuper
要求方法必须调用父类方法可想而知Activity的onCreate()方法有此注解标识。6.2.2 NonNull和Nullable
定义一个变量或对象可以为空或不可为空用在方法上表示方法可否返回空。6.2.3 资源类注解
AnimatorRes,AnimRes,AnyRes,ArrayRes,AttrRes, BoolRes, ColorRes, DimensRes, DrawableRes, FractionRes, IdRes, IntegerRes, InterpolatorRes, LayoutRes, MenuRes, PluralsRes, RawRes, StringRes, StyleableRes,StyleRes, TransitionRes, XmlRes这部分注解是非常有实用性的有22个用法如getDrawable(DrawableRes int id) //getDrawable方法限定了传入的参数必须是Drawable资源文件
另外还有个ColorInt限制传入Hex颜色值。在开发过程中需要传入某种资源文件时用此类注解是很有限制作用的做法。6.2.4IdDef和StringDef
提到最常用的Toast在API21之前一般可以这么写Toast.makeText(context, msg, 0).show();但是21之后0突然被划红线了查看源码发现之前是这么写的public static final int LENGTH_SHORT 0;
public static final int LENGTH_LONG 1;
makeText方法中单纯地写着int duration参数而21之后成了这样IntDef({LENGTH_SHORT, LENGTH_LONG})
Retention(RetentionPolicy.SOURCE)
public interface Duration {}
在makeText的duration参数之前加上了注解Duration这就要求传入Duration中的值才不会报警告。可以想象IntDef和String Def中放入了一个value数组。在开发中这两个注解就可以用来限制枚举值了。6.2.5 范围约束FloatRange、IntRange和Size
前两个限制了数字的范围比如可以用来限制传入参数值的范围Size可以用来限定集合的大小或者限定字符串的长度还可以做其他限制1.限制最小最大数量Size(min1,max10 )2.数量必须是2的倍数偶数: Size(multiple2)6.2.6 进程类注解
UiThread,BinderThread,MainThread,WorkerThread用来限定方法或类在指定的线程类型中被调用比如 AsyncTask中的方法就有如下的限定WorkerThread
protected abstract Result doInBackground(Params... params){ //doInBackground
}
MainThread
protected void onProgressUpdate(Progress... values) { //onProgressUpdate
} 6.2.7CheckResult
该注解意味着需要对方法的返回值进行处理例如有个方法为CheckResult
public boolean checkValid(String value){ return TextUtils.isEmpty(value);
}
当调用者直接调用checkValid(abc);时会报错这意味着需要对方法的返回值进行处理无论返回true或false需要进行后续操作不能单单调用一句checkValid(abc);6.2.8 权限注解RequiresPermission
如果方法的调用需要权限可以加这个注解当需要几个权限中的一个时使用anyOf如 RequiresPermission(anyOf { Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION})若需要多个权限使用allOf如 RequiresPermission(allOf { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE})若需要单独的标注读和写的权限访问所以可以用Read或者Write标注每一个权限需求6.2.9 SdkConstant
表示一个常量字段应该被输出在SDK工具中使用例如添加一个自定义的ActionSdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
public static final String ACTION_MY_TEST android.intent.action.MY_TEST;
则可以这样使用Intent myTest new Intent(Intent.ACTION_MY_TEST);
mContext.sendBroadcast(myTest); 6.2.10Widget
用于类的注解表示该类是自定义的Widget类此外还有两个注解即上述的TargetApi和SuppressLint不再赘述。7.总结
综上注解部分就介绍完了。注解在开发过程中有很强的实用性使用注解可以明确开发过程中的一些数据类型还可以对一些数据进行限制从而提高开发效率。