java注解

1.基本概念

注解是元数据的一种形式,提供有关与程序但不属于程序本身的数据
注解对于他们注解的代码没有直接的影响

java中所有的注解默认实现Annotation接口
package java.lang.annotation; 
	public interface Annotation { 
	boolean equals(Object obj); 
	int hashCode(); 
	String toString(); 
	Class<? extends Annotation> annotationType(); 
}

2.基本使用

(1)申明一个注解

public @interface Lance{ }

(2)传递参数

允许在定义注解时设定参数	->	若设定了参数,在使用注解时可以传递参数
//注解
@Target({ElementType.TYPE,ElementType.FIELD}) 
@Retention(RetentionPolicy.SOURCE) 
public @interface Lance { 
	String value(); //无默认值 
	int age() default 1; //有默认值 
}
//使用
@Lance("帅") //如果只存在value元素需要传值的情况,则可以省略:元素名= 
@Lance(value="帅",age = 2) 
int i;

3.元注解

定义注解时,注解类也能够被其他注解所注解
可以定义在注解上的注解即为元注解

一般情况下使用到的有
@Target	限制此注解可以注解在什么位置
@Retention 指定注解的存储方式

@Target
在这里插入图片描述
@Rentention
在这里插入图片描述

@Rentention中 
Source  < Class < Runtime

实例
在这里插入图片描述

4.应用场景

4.1 Resource

可以使用在IDE语法检查、APT技术
APT

Anotation Processor Tools -- 注解处理器

编写好的java文件(源代码)需要经过javac的编译(字节码)
注解处理器是javac自带的一个工具,用来在编译时期扫描注解处理信息
注册的注解处理器由javac自动调用,并将注解处理器传给APT处理

注解处理器是对注解应用最为广泛的场景

实例1使用注解IntDef限制入参

有这样一个元注解

@Retention(SOURCE)  
@Target({ANNOTATION_TYPE})//标记这是一个元注解 
public @interface IntDef { 
	int[] value() default {}; 
	boolean flag() default false; 
	boolean open() default false; 
}
IntDef的意义在于可以取代枚举类,实现限制方法入参

因为在Java中枚举Enum是 一个单例类的静态成员变量
但是经过javac编译后	->	
’实质是	所有静态成员变量都会变成单例类全部加载进内存中
比常量多5~10倍内存

IntDef注解可以取代枚举类,优化性能
public class TestIntDef {

    //第一种方式 静态成员变量
    //缺点    ->  可以随便传参 什么样的int数据都能传,但是我只要0或者1
    private static int mCurrentDay_int;
    private static final int SUNDAT = 0;
    private static final int MONDAY = 1;

    public static void setmCurrentDay_int(int currentDay){
        mCurrentDay_int = currentDay;
    }
    
    
    //第二种方式 枚举类
    //缺点    ->  消耗内存
    private static Weekday mCurrentDay_enum;
    enum Weekday{
        SUNDAY,
        MONDAY
    }
    
    public static void setmCurrentDay_enum(Weekday currentDay){
        mCurrentDay_enum = currentDay;
    }
    
    //第三种方式 保留在源码级别的注解
    @annotation private static int mCurrentDay_annotation;  //不标记会报错

    public static void setmCurrentDay_annotation(@annotation int currentDay){
        mCurrentDay_annotation = currentDay;
    }
    

    public static void main(String[] args) {
        setmCurrentDay_int(123);
        setmCurrentDay_enum(Weekday.SUNDAY);
//        setmCurrentDay_annotation(123);
        setmCurrentDay_annotation(1);
    }


}

实例2使用注解实现自动获取Intent里获取信息

//注解
@Target(ElementType.FIELD)              //使用在字段或者属性上
@Retention(RetentionPolicy.RUNTIME)     //保留到JVM级别
public @interface Autowired {
    String value() default "";
}
//注解解析
public class AutoWiredUtils {

    public static void AutoWriedMethod(Activity activity){  //传进来一个Activity
        //通过Activity得到Class
        Class<? extends Activity> aClass = activity.getClass();
        //判空
        Intent intent = activity.getIntent();
        Bundle extras = intent.getExtras();
        if (extras == null){
            return;
        }


        //获得某个类的所有声明的字段,即包括public、private和proteced,但是不包括父类的申明字段
        Field[] declaredFields = aClass.getDeclaredFields();
//      获得某个类的所有的公共(public)的字段,包括父类中的字段
//      aClass.getField("111");

        //遍历所有字段
        for (Field field : declaredFields) {
            //如果有AutoWried注解

            if (field.isAnnotationPresent(Autowired.class)){
                //得到注解
                Autowired annotation = field.getAnnotation(Autowired.class);
                 //得到属性值    ->  如果注解的值为空 就使用字段名
//                             ->  如果注解的值不为空 就使用注解的默认值
                String value = TextUtils.isEmpty(annotation.value()) ? field.getName() : annotation.value();

                if (extras.containsKey(value)){
                    //得到intent对象
                    Object o = extras.get(value);

                    //获得当前field的类型  ->  Parcelable数组类型不能直接设置,其他的都可以

                    //返回数组中元素的Class对象,如果不是Class对象 或者不是数组 那么返回null
                    Class<?> componentType = field.getType().getComponentType();

                    //如果是数组并实现了Parcelable接口 -》  只有实现了Parcelable接口的数组才要特殊处理!
                    if (field.getType().isArray() && Parcelable.class.isAssignableFrom(componentType)){
                        //强转为数组类型
                        Object[] objs = (Object[]) o;
                        创建对应类型的数组并由objs拷贝   ->  将objs数组拷贝到(Class<? extends Object[]>) field.getType()类型的数组
                        Object[] objects = Arrays.copyOf(objs, objs.length, (Class<? extends Object[]>) field.getType());
                        o = objects;
                    }

                    //设置权限
                    field.setAccessible(true);
                    try {
                        field.set(activity,o);
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}
//Activity1 传参
public class OneActivity extends AppCompatActivity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_one);

        Intent intent = new Intent(this,TwoActivity.class)
                .putExtra("intExtra",111)
                .putExtra("stringExtra","sss")
                .putExtra("arrIntExtra",new int[]{1,2,3})
                .putExtra("arrStringExtra",new String[]{"a","b","c"})
                .putExtra("arrSerializable",new UserSerializable[]{new UserSerializable("Jack")})
                .putExtra("UserSerializable",new UserSerializable("Ross"))
                .putExtra("arrParcelable",new UserParcelable[]{new UserParcelable(18)})
                .putExtra("UserParcelable",new UserParcelable(20));

        startActivity(intent);
    }
}
//Activity2获取参数
public class TwoActivity extends AppCompatActivity {

    @Autowired
    private int intExtra;
    @Autowired("stringExtra")
    private String stringExtra;
    @Autowired
    private int[] arrIntExtra;
    @Autowired
    private String[] arrStringExtra;
    @Autowired
    private UserSerializable[] arrSerializable;
    @Autowired
    private UserSerializable UserSerializable;
    @Autowired
    private UserParcelable[] arrParcelable;
    @Autowired
    private UserParcelable UserParcelable;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_two);
        AutoWiredUtils.AutoWriedMethod(this);

//        intExtra = getIntent().getIntExtra("int", 000);
//        stringExtra = getIntent().getStringExtra("String");

//        Log.d("jiang",String.valueOf(intExtra));
//        Log.d("jiang",String.valueOf(stringExtra));
//        Log.d("jiang", String.valueOf(arrIntExtra[0]));
//        Log.d("jiang", String.valueOf(arrStringExtra[2]));
//        Log.d("jiang", String.valueOf(arrSerializable[0].name));
//        Log.d("jiang", String.valueOf(UserSerializable.name));
//        Log.d("jiang", String.valueOf(arrParcelable[0].age));
//        Log.d("jiang", String.valueOf(UserParcelable.age));
    }

}

实例3使用注解实现自动FindViewById

@Target(ElementType.FIELD)              //注解在字段或者属性上
@Retention(RetentionPolicy.RUNTIME)     //保留至JVM级别
public @interface injectView {
    @IdRes int value(); //@IdRes元注解 ->  限制只能传入资源id
}
public class injectUtils {

    public static void injectView(Activity activity){   //传入一个Activity
        //通过Activity得到class文件
        Class<? extends Activity> aClass = activity.getClass();
//        aClass.getField();            获得自己+父类的成员(不包括private)
//        aClass.getDeclaredField();    只能获得自己的成员(不包括父类)

//        aClass.getSuperclass().getDeclaredField() 得到父类的私有成员

        //获得子类所有的成员
        Field[] declaredFields = aClass.getDeclaredFields();
        //遍历所有成员
        for (Field field : declaredFields) {
            //判断属性是否有此注解标签
            if (field.isAnnotationPresent(injectView.class)){
                //获得注解对象
                injectView inject = field.getAnnotation(injectView.class);
                //获得注解的属性值
                int idRes = inject.value();
                //找到view        findViewById()方法就是activity的
                View view = activity.findViewById(idRes);
                //反射设置属性的值
                field.setAccessible(true);   //设置可访问权限,设置允许操作private属性
                try {
                    field.set(activity,view);
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }

    }
}
public class MainActivity extends AppCompatActivity {

    @injectView(R.id.textView)
    TextView textView;  //默认是private的

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        injectUtils.injectView(this);
        Log.d("jiang", "onCreate: " + textView.getText());
        textView.setText("jylnbbbbb");
        Log.d("jiang", "onCreate: " + textView.getText());
    }
}

4.2 Class

定义为Class的注解会保留在class文件中,但是会被虚拟机忽略
完全适合用与字节码增强技术,如AspectJ、热修复Roubust

字节码增强技术即为,直接修改字节码Class文件以达到修改代码执行逻辑的目的

实例

在程序中有多处需要进行是否登录的判断

在这里插入图片描述

如果使用普通的编程方式,需要在多处编写冗余的if-else判断
此时可以借助AOP面向切面编程思想,将代码所有功能点分为:需要登录\不需要

在这里插入图片描述

jumpA方法需要具备登陆信息,而@Login注解被设置为class(保留到字节码时期)
因此我们能在该类字节码上获得注解信息
在操作字节码时,就能够根据方法是否具备该注解来修改加入if-else判断

在这里插入图片描述

结合参数能实现更为丰富的场景如:运行期权限判定

4.3 Runtime

结合反射技术获取注解中的信息
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值