1.使用IntDef代替枚举
枚举一直不被Android中推荐使用.因为枚举中的每一个值在枚举类中都是一个对象.使用枚举值会比整型消耗的更多的内存.但有时我们又要限制取某些特定的值.intDef和StringDef两个魔术变量注解来替换枚举.厉害了,我的哥.
步骤:
- 声明一些必要的int(或者float,String等)常量
- 声明一个注解ThemeStyle
- 使用@intDef修饰ThemeStyle,参数设置为待枚举的集合
- 使用@Retention(Retention.SOURCE)指定注解仅存在于源码中,不加入到class文件中
具体使用:
public static final int STYLE_V1 = 0; // 单排排版
public static final int STYLE_V2 = 1; // 双排排版
@IntDef({STYLE_V1,STYLE_V2})
@Retention(RetentionPolicy.SOURCE)
public @interface ThemeStyle{
}
//这样外部调用的时候只能传ThemeStyle.STYLE_V1,或者ThemeStyle.STYLE_V2.否则编译报错
public static void setStyle(Context context, @ThemeStyle int style) {
...
}
2.几种Threading注解
@UiThread UI线程
@MainThread 主线程
@WorkerThread 子线程
@BinderThread 绑定线程
3.Value Constraints注解: @Size,@IntRange@FloatRange
private void test(@IntRange(from=0,to=100)int a){
}
//举例
@Size(min=1)集合长度最小为1,即不能为空
@Size(max=100)String最大只能有100个字符
@size(2)数组只能有两个元素
4.@Permissions注解:@RequiresPermission
- 单一权限
@RequiresPermission(Manifest.permission.INTERNET)
public void loadData(){
...
}
- 需要任意一个
@RequiresPermission(anyOf={Manifest.permission.INTERNET,...})
public void loadData(){
...
}
- 同时需要多个
@RequiresPermission(allOf={Manifest.permission.INTERNET,...})
public void loadData(){
...
}
5.@CallSuper
允许子类重写的方法,但是又需要在重写的时候调用自己的方法.为避免子类完全重写不调用自己的方法可用这个注解
@CallSuper
protected void onCreate(@nullable){
doSoming()
}
6.@Keep
指出一个方法在被混淆时被保留
7.@VisibleForTesting
注解一个类,方法,变量表示有更广的可见性,使代码可以被测试
注解
@Retention、@Documented、@Target、@Inherited、@Repeatable
- @Retention
- RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
- RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中。
- RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。
- @Target
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给一个类型进行注解,比如类、接口、枚举
-
注解的属性也叫做成员变量。注解只有成员变量,没有方法。
注解的成员变量在注解的定义中以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface TestAnnotation { public int id() default -1; public String msg() default "Hi"; }
-
如果一个注解内仅仅只有一个名字为 value 的属性时,应用这个注解时可以直接接属性值填写到括号内。
@Check("hi") int a;
-
是一个注解没有任何属性。比如
public @interface Perform {}
那么在应用这个注解的时候,括号都可以省略。
@Perform public void testMethod(){}
java预置的注解
-
@Deprecated
过时的方法、过时的类、过时的成员变量
-
@Override
-
@SuppressWarnings
阻止警告的意思
@SuppressWarnings("deprecation") public void test1(){ Hero hero = new Hero(); hero.say(); hero.speak(); }
-
FunctionalInterface
函数式接口注解.是一个具有一个方法的普通接口
注解与反射
-
注解通过反射获取。首先可以通过 Class 对象的 isAnnotationPresent() 方法判断它是否应用了某个注解
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
-
然后通过 getAnnotation() 方法来获取 Annotation 对象
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
或者是getAnnotations() 方法
public Annotation[] getAnnotations() {}
前一种方法返回指定类型的注解,后一种方法返回注解到这个元素上的所有注解
-
如果获取到的 Annotation 如果不为 null,则就可以调用它们的属性方法了
@TestAnnotation public class Test { @Check("hi") int a; @Perform public void testMethod() { } @SuppressWarnings("deprecation") public void test1() { Hero hero = new Hero(); hero.say(); hero.speak(); } public static void main(String[] args) { boolean hasAnnotation = Test.class.isAnnotationPresent(TestAnnotation.class); if (hasAnnotation) { //获取类的注解 TestAnnotation testAnnotation = Test.class.getAnnotation(TestAnnotation.class); System.out.println("id:" + testAnnotation.id()); System.out.println("msg:" + testAnnotation.msg()); } try { Field a = Test.class.getDeclaredField("a"); a.setAccessible(true); //获取一个成员变量上的注解 Check check = a.getAnnotation(Check.class); if (check != null) { System.out.println("check value:" + check.value()); } Method testMethod = Test.class.getDeclaredMethod("testMethod"); if (testMethod != null) { // 获取方法中的注解 Annotation[] nas = testMethod.getAnnotations(); for (int i = 0; i < nas.length; i++) { System.out.println("method testMethod annotation:" + nas[i].annotationType().getSimpleName()); } } } catch (NoSuchFieldException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } } }
-
如果一个注解要在运行时被成功提取,那么 @Retention(RetentionPolicy.RUNTIME) 是必须的
使用场景
- 当开发者使用了Annotation 修饰了类、方法、Field 等成员之后,这些 Annotation 不会自己生效,必须由开发者提供相应的代码来提取并处理 Annotation 信息。这些处理提取和处理 Annotation 的代码统称为 APT(Annotation Processing Tool)。
总结
- 如果注解难于理解,你就把它类同于标签,标签为了解释事物,注解为了解释代码。
- 注解的基本语法,创建如同接口,但是多了个 @ 符号。
- 注解的元注解。
- 注解的属性。
- 注解主要给编译器及工具类型的软件用的。
- 注解的提取需要借助于 Java 的反射技术,反射比较慢慢,所以注解使用时也需要谨慎计较时间成本
保持求知欲,保持赤子心(*╯3╰)mua.