面试官问我注解怎么使用?我这样告诉他

上次面试官问我注解,怎么自定义注解?我告诉他我不会

就这样等我再去查校招进度的时候
在这里插入图片描述

俺发奋图强,通过一天的学习,终于明白注解。

  1. 自定义注解的使用!
  2. 通过注解我们能干什么?
  3. 注解究竟有什么好处?

话不多说,直奔主题!

自定义注解的创建

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;


@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface AutoWired {
    //自动注入注解
    Class className();//获取class对象
    String name();
    int age();
}

乍一看您可能就有三个问题
1.@Retention@Target是啥呀?
答:这两个也是注解,是为了注解自定义注解的注解(中文八级hahahaha)
在这里插入图片描述
我们称注解自定义注解的注解为元注解,你可以理解为注解是一个标签,而元注解是给这些标签打标签的。

2.元注解有什么用呀?
答:只有两个比较重要和常用的元注解,就是上面两个,分别介绍一下他们的作用

@Target:指明我们的自定义注解可以修饰的范围,如类,方法,变量
@Retention:指明自定义注解存在的范围,可以指定为SOURCE,CLASS,RUNTIME;
SOURCE表明注解只在.java文件中存在,CLASS表明注解在.class文件中存在,而RUNTIME表示在运行时,会把自定义注解加载到虚拟机中。

3.className(),name(),age()是啥呀
答:可以理解为属性,并且可以定义默认值。有了这些属性,我们在使用注解时可以赋值。

    @AutoWired(className = Person.class,name = "Yang",age=20)
    public static Person person1;
    @AutoWired(className = Person.class,name = "Zhang",age=20)
    public static Person person2;

相比大家已经明白了基本使用了(估计有人想打死我)
在这里插入图片描述

通过注解我们能干什么?

1.通过注解我们能够减少重复性的代码,让代码的可读性更好。
2.现在很多框架中都有自定义的注解,比如在Spring中有自动注入,也是通过注解实现的,在Android中,为了避免重复的findviewById可以使用自定义注解,那么下面我们来演示如何在Java中通过注解实现自动注入,通过注解实现findviewById的自动完成。

在这里插入图片描述

实现自动注入


import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
//自定义注解,三个属性,class对象
public @interface AutoWired {
    //自动注入注解
    Class className();//获取class对象
    String name();//姓名
    int age();//年龄
}

import java.lang.reflect.Field;
//我们知道静态代码块属于类,所以他会被先执行,我们在静态代码块中通过反射获取了Student类中定义的所有的成员变量(两个Person),然后分别给他们赋值,值也是从注解中获取的age和name.
public class Student{
    static{
       Field[] fields = Student.class.getDeclaredFields();
       for (int i=0;i<fields.length;i++){
           AutoWired  auto = fields[i].getAnnotation(AutoWired.class);
           Class cl = auto.className();//获取class对象,根据class对象给Person初始化
           String name = auto.name();
           int age = auto.age();
           try {
               Field field = fields[i];
               field.setAccessible(true);//暴力访问,取消age的私有权限。让对象可以访问
               Object obj = cl.newInstance();
               Person p = new Person(name,age);
               field.set(obj, p);//设置对象中,私有变道量的值
           } catch (InstantiationException e) {
               e.printStackTrace();
           } catch (IllegalAccessException e) {
               e.printStackTrace();
           }

       }
    }

    @AutoWired(className = Person.class,name = "Yang",age=20)
    public static Person person1;
    @AutoWired(className = Person.class,name = "Zhang",age=20)
    public static Person person2;

    public static void main(String[] args) {
    //从main方法中看,我们没有任何new,就能够获取到对象的属性,这和自动注入类似, 
        System.out.println(person1.getName()+"------"+person1.getAge()+"\n");
        System.out.println(person2.getName()+"------"+person2.getAge()+"\n");

        //自动注入
    }


}

实现不实用findviewById就指定绑定ID的功能

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FindView {
    int resId();//我们只要输入id,就能帮我们自动的绑定
}


import androidx.appcompat.app.AppCompatActivity;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.TextView;

import com.example.annimation.FindView;

import java.lang.reflect.Field;

public class FIndViewActivity extends AppCompatActivity {

    @FindView(resId = R.id.tv_name1)
    TextView tv_name1;
    @FindView(resId = R.id.tv_name2)
    TextView tv_name2;
    @FindView(resId = R.id.tv_name3)
    TextView tv_name3;
    @FindView(resId = R.id.tv_name4)
    TextView tv_name4;
    @FindView(resId = R.id.tv_name5)
    TextView tv_name5;
    @FindView(resId = R.id.tv_name6)
    TextView tv_name6;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_find_view);
        //onCreate中我们通过一个函数解决findviewbyId的问题
        bindView(this);
    }

    public static void bindView(Activity activity) {
        Class classObj = activity.getClass();
        Field [] fields = classObj.getDeclaredFields();

        for (int i = 0; i < fields.length; i++) {
            Field field = fields[i];
            if (field.isAnnotationPresent(FindView.class)) {
                FindView findView = field.getAnnotation(FindView.class);
                int resId = findView.resId();
                View view = activity.findViewById(resId);
                field.setAccessible(true);//私有类型必须要设置
                Class<?> targetType = field.getType();//成员变量的类型,如TextView
                Class<?> viewType = view.getClass();//获取包名
                if (!targetType.isAssignableFrom(viewType)) {
                    continue;
                }
                try {
                    field.set(activity, view);//通过set设置
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

}

大功告成,现在你对注解是不是又多了一点了解呢?如果大家还像了解注解的细节,请查阅其他资料。
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_43927892/article/details/105790328