注解

一、什么是注解
注解就是代码中的特殊标记,这些标记可以在编译、类加载、运行时被读取,并执行相应的处理。

二、注解的作用
1.编写文档:通过代码里标识的元数据生成doc文档
2.代码分析:使用反射可以通过代码里的元数据进行分析
3.编译检查:通过代码标识的元数据可以让编译器实现最基本的编译检查,ex:@Override

三、最常见的注解
1.@Override
@Override的的作用会告诉编译器这个方法是不是重写父类的,可以帮我们避免一些低级的错误,例如,当我们重写equals()方法的时候,并用上了@Override,如果equals拼写错误,那么就会提示该方法不是重写方法。

2.@Deprecated
过时注解,当我们做java设计的时候,可能有的方法设计的并不是很理想,但为了兼容以前的程序又不能把它删除,那么就可以使用@Deprecated标识,当有人使用这个方法的时候,编译器就会提示这是一个过时的方法(方法名上出现横杠)

3.@SuppressWarning
抑制编译警告注解,可以用来让编译器不给予警告

4.@SafeVarargs
堆污染警告,当把不是泛型的集合赋值一个泛型的集合时候,编译器会警告,这个注解也是用来抑制编译器警告的

5.@Functionallnterface
用来指定该接口是函数式接口

四、自定义注解

1.定义一个注解
在这里插入图片描述
注意:定义的成员变量只能是String、数组、Class、枚举、注解等类型

2.使用定义好的注解
在这里插入图片描述
注意:注解拥有什么样的属性,在修饰的时候就要给出相应的值

3.默认值
在定义注解属性的时候可以定义一个默认值,那么在使用的时候可以不用给出具体的值。
在这里插入图片描述
在这里插入图片描述

4.注解属性value
当注解上只有一个属性,且属性命名为value,那么在使用的时候可以直接赋值。
在这里插入图片描述
在这里插入图片描述
五、元注解
概念:元注解就是描述注解的注解
种类:
1.@Target
用于指定注解的使用范围,例如
ElementType.TYPE 仅用于类、接口、枚举
ElementType.FIELD 仅用于属性
ElementType.METHOD 仅用于方法(非构造方法)
ElementType.CONSTRUCTOR 仅用于构造方法
ElementType.PARAMETER 仅用于方法的参数
ElementType.LOCAL_VARIABLE 仅用于局部变量
ElementType.ANNOTATION_TYPE 仅用于注解
ElementType.PACKAGE 仅用于包

当使用在注解上使用@Target(ElementType.METHOD)时,表示只能在方法上使用此注解,用在其他地方会报错。
在这里插入图片描述
在这里插入图片描述
2.@Retention
用于指定注解在什么阶段有效,(编译,.class,运行)
RetentionPolicy.SOURCE 仅源文件(.java)阶段有效。
RetentionPolicy.CLASS 源文件(.java)阶段以及字节码文件阶
段(.class)有效。
RetentionPolicy.RUNTIME 源文件、字节码以及运行时都有效。

3.@Documented ------几乎不用
当你用@Documented修饰一个方法、类、包、属性等的时候。通过javadoc命令
生成API文档时,注解也会生成到文档中。默认(不写@Documented时)不会把
注解生成到文档中。

4.@Inherited-------几乎不用
它比较复杂,一旦用了这个注解修饰类。这个类的子类会继承父类的属性和方法。

六、将注解注入到方法上

public class Test1 {
    private String name;
    private String age; 
    @MyAnnotation(name = "张三", age = "90")
    public void add(String name,String age){
        this.name=name;
        this.age=age;
    }

    public String getName() {
        return name;
    }

    public String getAge() {
        return age;
    }

    public static void main(String[] args) {
        try {
            //通过反射得出该方法
            Class  clazz=Test1.class;
            Method method=clazz.getMethod("add",String.class,String.class);
            //获取方法上注解的成员
            MyAnnotation annotation=method.getAnnotation(MyAnnotation.class);
            String name=annotation.name();
            String age=annotation.age();
            //将注解上的信息注入到方法上
            Object o=clazz.newInstance();
            method.invoke(o,name,age);
            //验证是否注入成功
            Test1 test1=(Test1)o;
            System.out.println(test1.getName());
            System.out.println(test1.getAge());
        } catch (Exception e) {
            e.printStackTrace();
        }

    }
}

运行结果:

张三
90

Process finished with exit code 0

七、将对象注入方法上
1.建立一个Person类,并设置get和set方法

public class Person {
    private String name;
    private String age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }
}

2.设计获取Person实例的类PersonDAO,并在set方法上使用定义好的注解

public class PersonDAO {
    private Person person;

    public Person getPerson() {
        return person;
    }
    @MyAnnotation(name = "张三",age ="100")
    public void setPerson(Person person) {
        this.person = person;
    }
}

3.设计一个对象注入的方法

public class Main {
    public static PersonDAO injectTools() {
        PersonDAO  personDAO=new PersonDAO();
        try {
            //使用PropertyDescriptor来获取想要注入的属性
            PropertyDescriptor descriptor = new PropertyDescriptor("person", PersonDAO.class);
            //得到注入属性的对象
            Person person = (Person) descriptor.getPropertyType().newInstance();
            //获取该属性的写方法【setPerson()】
            Method method = descriptor.getWriteMethod();
            //得到写方法上面的注解
            MyAnnotation annotation = method.getAnnotation(MyAnnotation.class);
            //得到注解里具体的信息
            Method[] methods = annotation.getClass().getMethods();
            //遍历注解信息,将注解信息注入到person对象上
            for (Method m : methods) {
                //得到注解的名字【name或者age】
               String name=m.getName();
                try {
                    //假设有与之对应的set方法
                    PropertyDescriptor descriptor1=new PropertyDescriptor(name,Person.class);
                    //得到写方法【setName()或者setAge】
                    Method method1=descriptor1.getWriteMethod();
                    //得到注解的值
                    Object o=m.invoke(annotation,null);
                    //调用Person对象的set方法,将注解上的信息填进去
                    method1.invoke(person,o);
                    //如果没有对应的set方法,会捕获异常,直接跳过,继续遍历
                } catch (IntrospectionException e) {
                    continue;
                }
            }
            //将填充完的person,赋值给PersonDAO对象
            method.invoke(personDAO,person);
            //返回填充完毕的personDAO
            return personDAO;
            } catch(Exception e){
                e.printStackTrace();
            }
        return personDAO;
        }


    public static void main(String[] args) {
        PersonDAO personDAO=injectTools();;
        String name=personDAO.getPerson().getName();
        String age=personDAO.getPerson().getAge();
        System.out.printf("姓名:%s\n年龄:%s\n",name,age);
    }
}

运行结果:

姓名:张三
年龄:100

Process finished with exit code 0

八、将对象注入到成员成员变量上

 public static PersonDAO injectTools2(){
            PersonDAO personDAO=new PersonDAO();
            try {
                Field field=PersonDAO.class.getDeclaredField("person");
                Person person=(Person)field.getType().newInstance();
                MyAnnotation annotation=field.getAnnotation(MyAnnotation.class);
                Method[] methods=annotation.getClass().getMethods();
                for(Method m:methods){
                    String name=m.getName();
                    try {
                        PropertyDescriptor descriptor=new PropertyDescriptor(name,Person.class);
                        Method method=descriptor.getWriteMethod();
                        Object o=m.invoke(annotation,null);
                        method.invoke(person,o);
                    } catch (Exception e) {
                        continue;
                    }
                }
                field.setAccessible(true);
                field.set(personDAO,person);
                return personDAO;
            } catch (Exception e) {
                e.printStackTrace();
            }
            return personDAO;
        }

九、注解的应用场景
开发servlet时,可以免去配置XML文件,例如:(@WebServlet)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值