概念
Java提供了一种原程序中的元素关联任何信息和任何元数据的途径和方法 (有点抽象)
好处:能够读懂别人写的代码 让编程更加简洁,代码更加清晰 让别人高看一眼(手动滑稽)
分类
按照运行机制划分:
源码注解:注解只在源码中存在,编译成.class文件就不存在了
编译时注解:在源码和.class文件都存在。如:@Override、@Deprecated、@Supresswarnings
运行时的注解:在运行阶段还起作用,甚至会影响运行逻辑的注解。如@Autowired
按照来源划分:
来自JDK的注解:@Override、@Deprecated、@Supresswarnings
@Override 检查是否正确复写 告诉读代码的人这是一个复写方法
先写一个Person接口,有三个方法
package com.richard.test; public interface Person { public void name(); public void age(int a); public void sing(); }
在写一个Child类实现接口,每个方法上都会有一个@Override注解,告诉编译器还有读代码的人这是一个复写方法
package com.richard.test; public class Child implements Person { @Override public void name() { } @Override public void age(int a) { } @Override public void sing() { } }
如果我将age(int a) 中的int 改为float,就会出现如下错误,说明这个注解会对复写方法的正确性进行检查
@Deprecated: 此方法或类不建议使用,调用时会出现删除线,如果override的了一个deprecated方法,会出现警告、
如果我们在开发某一项目时,发现某方法写的不好,想丢掉不用,但是这个方法被很多地方用到了,直接删除的话会导致很多错误,这是我们可以加上@Deprecated注解,提示程序员这个方法过期了或者说有更好的方法了
public interface Person { public void name(); public void age(int a); @Deprecated public void sing(); }
在建一个Audlt类来测试一下 ,发现sing()方法出现了删除线,不建议使用此方法
如果是eclipse的话会出现警告
这个时候可以增加@SuppressWarnings注解来消除警告,当然不加也不会报错
@Suppresswarnings 抑制编译器产生警告信息(单类型、多类型、所有类型),解决会挡住一些编译器断点调试打断点的问题 ,目标:类、字段、函数、函数入参、构造函数和函数的局部变量,建议放在最近警告的位置
1. 抑制单类型警告
@SuppressWarnings("unchecked") public void addItems(String item){ @SuppressWarnings("rawtypes") List items = new ArrayList(); items.add(item); }
2. 抑制多类型警告
@SuppressWarnings(value={"unchecked", "rawtypes"}) public void addItems(String item){ List items = new ArrayList(); items.add(item); }
3. 抑制全部警告
@SuppressWarnings("all") public void addItems(String item){ List items = new ArrayList(); items.add(item); }
抑制警告的关键字
all
to suppress all warnings (抑制所有警告)boxing
to suppress warnings relative to boxing/unboxing operations(抑制装箱、拆箱操作时候的警告)cast
to suppress warnings relative to cast operations (抑制映射相关的警告)dep-ann
to suppress warnings relative to deprecated annotation(抑制启用注释的警告)deprecation
to suppress warnings relative to deprecation(抑制过期方法警告)fallthrough
to suppress warnings relative to missing breaks in switch statements(抑制确在switch中缺失breaks的警告)finally
to suppress warnings relative to finally block that don’t return (抑制finally模块没有返回的警告)hiding
to suppress warnings relative to locals that hide variable()incomplete-switch
to suppress warnings relative to missing entries in a switch statement (enum case)(忽略没有完整的switch语句)nls
to suppress warnings relative to non-nls string literals(忽略非nls格式的字符)null
to suppress warnings relative to null analysis(忽略对null的操作)rawtypes
to suppress warnings relative to un-specific types when using generics on class params(使用generics时忽略没有指定相应的类型)restriction
to suppress warnings relative to usage of discouraged or forbidden referencesserial
to suppress warnings relative to missing serialVersionUID field for a serializable class(忽略在serializable类中没有声明serialVersionUID变量)static-access
to suppress warnings relative to incorrect static access(抑制不正确的静态访问方式警告)synthetic-access
to suppress warnings relative to unoptimized access from inner classes(抑制子类没有按最优方法访问内部类的警告)unchecked
to suppress warnings relative to unchecked operations(抑制没有进行类型检查操作的警告)unqualified-field-access
to suppress warnings relative to field access unqualified (抑制没有权限访问的域的警告)unused
to suppress warnings relative to unused code (抑制没被使用过的代码的警告)
来自第三方的注解:Spring(@Autowired、@Service、@Repository)、Mybatis(@InsertProvider、@UpdateProvider、@Options)
这个暂时了解不多,后续再写
例外还有元注解:即注解的注解,在自定义注解中会有所说明
自定义的注解:
@Target({ElementType.METHOD,ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Description { String desc(); String author(); int age() default 18; }
使用@interface 关键字定义注解
成员方法以无参无异常方式声明
可以使用default为成员指定一个返回值
如果注解只有一个成员,则成员名必须为value(),在使用时可以忽略成员名和赋值号“=”
可以没有成员,没有成员的注解称为标识注解
元注解:
1、@Target 作用域
CONSTRUCTOR 构造方法声明
FIELD 字段声明
METHOD 方法声明
LOCAL_VARIABLE 局部变量声明
PACKAGE 包声明
PARAMETER 参数声明
TYPE 类,接口
2、@Rentention 生命周期
SOURCE:只在源码显示,编译时会丢失
CLASS:编译时会记录到class,运行时忽略
RUNTIME:运行时关联,可以通过反射读取
3、@Inherited 标识性注解,标识允许子类继承(对于实现接口是不会起作用的)
编写自定义注解时未写@Inherited的运行结果:
子类的类上能否继承到父类的类上的注解? 否
子类方法,实现了父类上的抽象方法,这个方法能否继承到注解? 否
子类方法,继承了父类上的方法,这个方法能否继承到注解? 能
子类方法,覆盖了父类上的方法,这个方法能否继承到注解? 否
编写自定义注解时写了@Inherited的运行结果:
子类的类上能否继承到父类的类上的注解? 能
子类方法,实现了父类上的抽象方法,这个方法能否继承到注解? 否
子类方法,继承了父类上的方法,这个方法能否继承到注解? 能
子类方法,覆盖了父类上的方法,这个方法能否继承到注解? 否
4、@Documented 生成javadoc时会包含注解
注解的使用
@Description(desc="I am eyeColor",author="SuperMan",age = 18) public class EyeColor { }
解析注解 :通过反射获取类、函数或成员上的运行时注解信息,从而实现动态控制程序运行的逻辑
测试一下,现在Child类以及name()方法上使用注解
@Description("I am class annotation") public class Child implements Person { @Override @Description("I am method annotation") public void name() { } @Override public void age(int a) { } @Override public void sing() { } }
再创建一个类通过反射来解析注解
public class ParseAnn { public static void main(String[] args) { try { //1、使用类加载器加载类 Class c = Class.forName("com.richard.test.Child"); //2、找到类上面的注解 boolean isExist = c.isAnnotationPresent(Description.class); if(isExist){ //3、拿到注解实例 Description d =(Description) c.getAnnotation(Description.class); System.out.println("d.value() = " + d.value()); } //4、找到方法上的注解 Method [] ms = c.getMethods(); for (Method m : ms) { boolean isEx = m.isAnnotationPresent(Description.class); if(isEx) { Description d = m.getAnnotation(Description.class); System.out.println("d.value() = " + d.value()); } } //另外一种方法 for (Method m : ms) { Annotation []as = m.getAnnotations(); for (Annotation a : as) { if(a instanceof Description){ Description d = (Description) a; System.out.println(d.value()); } } } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
输出结果如下,成功的得到了运行时的注解
将Description@Retention(RetentionPolicy.RUNTIME)中的RUNTIME换成SOURCE或CLASS之后再次运行会发现没有任何输出,说明只能对运行时注解进行解析
总结 :通过书写一遍博客,再一次复习了一下,收获挺丰富的,如有不当之处请指正,共同进步