注解(Annotation)+ 总结

A.java

public class A {
    void show(){
        
    }
}

B.java

@SuppressWarnings(value = {"unused","rawtypes","unchecked"})
public class B extends A{
    // unused
    int age = 18;

    // rawtypes
    List list = new ArrayList<>();

    @Override
    public void show(){
        // unchecked
        list.add("hello");
    }

    @Deprecated
    public void print(){
        
    }
}
	从Java7开始,额外增加了3个注解:
	@SafeVarargs - Java7开始支持,忽略任何使用参数为泛型遍历的方法或构造函数调用产生的警告
public class D {
    public static void main(String[] args) {
        List<String> list1 = Arrays.asList("one","two");
        List<String> list2 = Arrays.asList("three","four");
        show(list1,list2);
    }
    @SafeVarargs // 其实并不安全!
    static void show(List<String>...stringLists){
        Object[] array = stringLists;
        List<Integer> tmList = Arrays.asList(42,56);
        // tmList是一个List对象(类型已经擦除),赋值给Object类型
        // 的对象是允许的(向上塑性),能够编译通过
        array[0] = tmList;
        String s = stringLists[0].get(0); // 运行时抛出ClassCastException!
    }
}
	@Functionallnterface - java8开始支持,标识一个匿名函数或函数式式接口。
@FunctionalInterface
public interface C {
    void pf();
}

内置注解描述

1、@Deprecated		-- @Deprecated  所标注内容,不再被建议使用。
2、@Override		-- @Override 只能标注方法,表示该方法覆盖父类中的方法。
3、@SuppressWarnings  -- @SuppressWarnings 所标注内容产生的警告,编译器会对这些警告保持静默。
4、@FunctionalInterface
5、@SafeVarargs

元注解

我们自定义注解类时,使用的注解,声明注解类时使用的注解。

1、@Documented		-- @Documented 所标注内容,恶意出现在javadoc中。
2、@Inherited		-- @Inherited 只能被用来标注“Annotation类型”,它所标注的
Annotation具有继承性。
3、@Retention		-- @Retention 只能被用来标注“Annatation类型”,而且它
被用来指定Annotation的RetentionPolicy属性。
4、@Target			-- @Target 只能被用来标注“Annotation类型”,而且它被用
来指定Annotation的ElementType属性。

在这里插入图片描述

	元注解:注解的注解,用来定义注解类时使用的注解。

在这里插入图片描述

1、@Retention  -  标识这个注解怎么保存,是只在代码中,还是编入class文件中,或者是在运行时可以
通过反射访问。
2、@Documented  -  标记这些注解是否包含再用户文档中出现(javadoc)。
3、@Target  -  标记这个注解应该是哪种Java成员。
4、@Inherited  -  标记这个注解是继承于哪个注解类(默认 注解并没有继承于任何子类)。
5、@Repeatable  -  Java 8 开始支持,标识某注解可以在同一个声明上使用多次。

Documented

该注解是一个标注注解,主要是为了进行javadoc生成代码的时候,显示注解内容。

注解的定义:

1、@Documented
2、@Retention(RetentionPolicy.RUNTIME)
3、@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

案例

public @interface E {
    /*
    *  test测试方法
    * */
    int test();
}
使用javadoc编译java文档
1 javadoc -encoding uft-8 -d jc E.java #生成的文档有注解显示
2
3 javadoc -encoding utf-8 -d jc E.java #将@Documented注释,没有使用注解的

Retention

@Retention注解接口,可以理解该接口的生命周期,也就是在运行时保留该注解多少时间。

该注解接口定义为:

1 @Documented
2 @Retention(RetentionPolicy.RUNTIME)
3 @Target(ElementType.ANNOTATION_TYPE)
public @interface Retention
对于 java.lang.annotation.RetentionPolicy 枚举类的定义

在这里插入图片描述

	也就是说对于Retention 注解的接口参数就三个,分别是:RetentionPolicy.Class,RetentionPolicy.RUNTIME 
以及 RetentionPolicy.SOURCE。如果注解接口不包含该注解,则默认的策略是:RetentionPolicy.Class
	RetentionPolicy.Class:编译器将把注释记录在class文件中。当运行java程序时,JVM不在保留注释,这是默认值。
	RetentionPolicy.RUNTIME:表一起将把注释记录在class文件中。当运行Java程序时,JVM也会保留注释,程序可以通过反射获取该注释。
	RetentionPolicy.SOURCE:注释仅存在于源码中,在class字节码文件中不包含。
1 import static java.lang.annotation.RetentionPolicy.RUNTIME;
2 /* RUNTIME 运行时,可以反射调用>CLASS类上>SOURCE 源码上 */
3 @Retention(RUNTIME)

Target

对于@Target注解接口,是注解接口的上下文,注解对象所在的位置
1 @Documented
2 @Retention(RetentionPolicy.RUNTIME)
3 @Target(ElementType.ANNOTATION_TYPE)
public @interface Target
1 @Target 也是用于修饰一个Annotation定义,它用于指定被修饰Annotation能用于修饰那些程序元素。
@Target Annotation也包含一个名为value的成员变量,该成员变量只能是如下几个:
2
3 ElementType.ANNOTATION_TYPE:指定该策略的Annotation只能修饰Annotation。
4 ElementType.CONSTRUCTOR:指定该策略的Annotation能修饰的构造器。
5 ElementType.FIELD:指定该策略的Annotation只能修饰成员变量。
6 ElementType.LOCAL_VARIABLE:指定该策略的Annotation只能修饰局部变量。
7 ElementType.METHOD:指定该策略的Annotation只能修饰方法。
8 ElementType.PACKAGE:指定该策略的Annotation只能修饰包定义。
9 ElementType.PARAMETER:指定该策略的Annotation可以修饰参数。
10 ElementType.TYPE:指定该策略的Annotation可以修饰类、接口(包括注释类型)或枚举定义。
	对于ElementType枚举类型,主要提供了Java程序中可能出现的注解的语法位置的简单分类,这些
常量主要是在@Target注解中使用,用来指定在代码的那个位置添加注解。根据@Target的定义,可
以看到该值是数组,所以可以设置多个值,例如上面代码中的:

Target(ElementType.ANNOTATION_TYPE)

举个Java中的例子 @Override 其中它的定义是:
1 @Target(ElementType.METHOD)
2 @Retention(RetentionPolicy.SOURCE)
3 public @interface Override {
4 }
	根据上面的解释,就很容易理解该注解,该注解的注解位置是方法,并且
注解的生命周期也就是保留时间是源码,也就是只有在源码中存在。如果该
注解注解到类上,会有如下的错误信息。

Inherited

	对于@Inherited注解接口,表示带有该注解的带有继承功能,如果在注解接口的生命中存在继承的
元注解,并且用户在类生命上查询注解接口,而类声明没有针对该接口的注解,则该类的超类将自动
查询该注解接口。此过程将向上重复进行,直到找到此接口的注解,或者达到了类层次接口的顶部。
如果没有超类具有次接口的注释,则查询将指示所讨论的类没有此类注解。
	也就是说此类注解主要是为了让子类进行继承。
	需要注意此注解只能用于类上,而不能用于方法和属性上。还需要注意的是,这个元注解只会导致
从超类继承注解,已经实现的接口上对于注解是无效的。
1 Documented
2 @Retention(RetentionPolicy.RUNTIME)
3 @Target(ElementType.ANNOTATION_TYPE)
4 public @interface Inherited {
5 }

对于 @Native 和 @Repeatable 是从 Java 1.8 新增加的元注解。

Repeatable

注释接口 java.lang.annotation.Repeatable 用于指示它(元)注释其声明的注释接口时可重复的。@Repeatable的值表示可重复注解接口的包含注解接口。定义为:

1 @Documented
2 @Retention(RetentionPolicy.RUNTIME)
3 @Target(ElementTye.ANNOTATION_TYPE)
4 public @interface Repeatable

Native

	表示可以从本机代码引用定义常量值的字段。注解可以用作生成本机头文件的工具的提示,
以确定是否需要头文件,如果需要,应包含哪些声明。

该注解的定义为:

1 @Documented
2 @Target(ElementType.FIELD)
3 @Retention(RetnetionPolicy.SOURCE)
4 public @interface Native {
5 }

自定义注解

public class AnnDemo {
    public static void main(String[] args) throws Exception{
        // 正射
        Lisi li = new Lisi();

        // 反射
        // Class<Lisi> c1 = Lisi.class;
        // Class<?> c2 = Lisi.class;
        // Class c3 = li.getClass();
        // Class<?> c4 = Class.forName("com.nnzb.day02.Lisi");

        // System.out.println(c1);
        // System.out.println(c2);
        // System.out.println(c2 == c1); // true
        // System.out.println(c3 == c2);// true
        // System.out.println(c4);
        // System.out.println(c4 == c3);// true

        // 利用反射机制,获取注解信息
        Class<?> c = Lisi.class;
        User ua = c.getAnnotation(User.class);
        System.out.println(ua.name());
        System.out.println(ua.age());
        System.out.println(ua.sex());

        // 方法上的注解
        Method m = c.getMethod("show");
        User mu = m.getAnnotation(User.class);
        System.out.println(mu.name());
        System.out.println(mu.age());
        System.out.println(mu.sex());

        // 属性上的注解
        Field name = c.getField("name"); // 读取非private
        System.out.println(name.getAnnotation(Name.class).value());
        Field sname = c.getDeclaredField("sname"); // 可以读取private属性
        System.out.println(sname.getAnnotation(Name.class).value());
    }
}


@User(name = "李强",age = 25)
public class Lisi {
    @Name("张三丰")
    public String name;

    @Name
    private String sname;

    @User(name = "李三")
    public void show(){

    }
}


@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Name {
    String value() default "佚名";
}


@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE,METHOD})
public @interface User {
    String name();

    int age() default 18;

    String sex() default "男";
}

注解的使用

	注解接口定义好了,如何使用呢?对于注解的使用,现在来说就只有一种方法,就是基于反射机制。
如果有其他的方法,可以评论区告诉我。感谢。
	直接上代码。这里用到了反射,不过这些都是简单的使用,加载类,加载类的方法,加载类的属性。

注解使用测试类

public class AnnDemo {
    public static void main(String[] args) throws Exception{
        // 正射
        Lisi li = new Lisi();

        // 反射
        // Class<Lisi> c1 = Lisi.class;
        // Class<?> c2 = Lisi.class;
        // Class c3 = li.getClass();
        // Class<?> c4 = Class.forName("com.nnzb.day02.Lisi");

        // System.out.println(c1);
        // System.out.println(c2);
        // System.out.println(c2 == c1); // true
        // System.out.println(c3 == c2);// true
        // System.out.println(c4);
        // System.out.println(c4 == c3);// true

        // 利用反射机制,获取注解信息
        Class<?> c = Lisi.class;
        User ua = c.getAnnotation(User.class);
        System.out.println(ua.name());
        System.out.println(ua.age());
        System.out.println(ua.sex());

        // 方法上的注解
        Method m = c.getMethod("show");
        User mu = m.getAnnotation(User.class);
        System.out.println(mu.name());
        System.out.println(mu.age());
        System.out.println(mu.sex());

        // 属性上的注解
        Field name = c.getField("name"); // 读取非private
        System.out.println(name.getAnnotation(Name.class).value());
        Field sname = c.getDeclaredField("sname"); // 可以读取private属性
        System.out.println(sname.getAnnotation(Name.class).value());
    }
}


@User(name = "李强",age = 25)
public class Lisi {
    @Name("张三丰")
    public String name;

    @Name
    private String sname;

    @User(name = "李三")
    public void show(){

    }
}


@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Name {
    String value() default "佚名";
}


@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE,METHOD})
public @interface User {
    String name();

    int age() default 18;

    String sex() default "男";
}

正射 反射

 // 正射
        Lisi li = new Lisi();

        // 反射
        // Class<Lisi> c1 = Lisi.class;
        // Class<?> c2 = Lisi.class;
        // Class c3 = li.getClass();
        // Class<?> c4 = Class.forName("com.nnzb.day02.Lisi");

        // System.out.println(c1);
        // System.out.println(c2);
        // System.out.println(c2 == c1); // true
        // System.out.println(c3 == c2);// true
        // System.out.println(c4);
        // System.out.println(c4 == c3);// true

利用反射机制,获取注解信息

// 利用反射机制,获取注解信息
        Class<?> c = Lisi.class;
        User ua = c.getAnnotation(User.class);
        System.out.println(ua.name());
        System.out.println(ua.age());
        System.out.println(ua.sex());

方法上的注解

 // 方法上的注解
        Method m = c.getMethod("show");
        User mu = m.getAnnotation(User.class);
        System.out.println(mu.name());
        System.out.println(mu.age());
        System.out.println(mu.sex());

属性上的注解

// 属性上的注解
        Field name = c.getField("name"); // 读取非private
        System.out.println(name.getAnnotation(Name.class).value());
        Field sname = c.getDeclaredField("sname"); // 可以读取private属性
        System.out.println(sname.getAnnotation(Name.class).value());

总结

注释程序人员查看源码时看,注解JVM运行字节码文件时查看信息

1.如果注解难于理解,你就把它类同于标签,标签为了解释事物,注解为了解释代码。
2.注解的基本语法,创建如同接口,但是多了个@符号。public @interface Ann{}
3.注解的元注解是@Documented @Retention @Target
4.注解的属性 String value(); String name(); defauly "james" int age() default 18。
5.注解主要给编译器及工具类型(框架)的软件用的。
6.注解的提取需要借助于java的反射技术,反射比较慢(但功能强大,是开发框架人员必须
掌握,也是标志升级为动态语句的方式),所以注解使用时也需要谨慎计较时间成本。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值