Java注解(二) 系统注解

上一篇博文讲了Java注解是什么、有什么作用。现在让我们来谈谈Java本身提供的一些注解,包括内置注解跟元注解(后面解释)。

概要

  • 系统注解

    • 内置注解

      • @Deprecated
      • @Override
      • @SuppressWarnings
    • 元注解
      • @Retention
      • @Target
      • @Inherited
      • @Documented

内置注解

Java本身提供了一些比较常用的注解,下面就分别介绍一下@Deprecated@Override@SuppressWarnings

@Deprecated

作用: 标示一个方法、类或属性已经过时,不再推荐使用。

@Deprecated部分源码
/**
* Annotation type used to mark program elements that should no longer be used
* by programmers. Compilers produce a warning if a deprecated program element
* is used.
*
* @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
public @interface Deprecated {
}

其中@Documented标明该注解要加入Javadoc文档 ,@Retention(RetentionPolicy.RUNTIME)标明该注解运行时可见(具体文章后面会介绍到)。

@Deprecated使用示例代码:
User.java
public class User {
    /**
     * 测试 @Deprecated 注解
     */
    @Deprecated
    public String deprecatedMethod(){
        return "I am deprecated Method";
    }

    //省略...
}  
Test.java

上面的代码中,deprecatedMethod方法就是被@Deprecated注解的方法。

当调用该方法时,编译器就会检测到deprecatedMethod@Deprecated注解了,然后就会做一些提示操作(比如画横线)。

@Override

作用:标示子类的方法重载了父类的方法

@Override部分源码
/**
* Annotation type used to mark methods that override a method declaration in a
* superclass. Compilers produce an error if a method annotated with @Override
* does not actually override a method in a superclass.
*
* @since 1.5
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

其中@Target(ElementType.METHOD)标明该注解可修饰元素为方法 ,@Retention(RetentionPolicy.SOURCE)标明该注解为只在源码中可见(具体文章后面会介绍到)。

@Override用法示例代码

User.java

public class User{
        public String getProfile(){
            String profile = "I am a normal user.";
            return profile;
        }
}

SpecialUser.java

    public class SpecialUser extends User{
        @Override
        public String getProfile() {
            String profile = "I am  special user, so I had override getProfile method.";
            return profile;
        }
}

上述代码中SpecialUser继承了User并重写了getProfile方法,这里加上了@Override编译器就会知道SpecialUser是重写了User的方法,编译器就会在User类中找getProfile方法(如果User类中找不到就到User的父类去找,如此一直查找到基类),如果找不到就会报错。


但重写方法并不强制加上@Override,但推荐的做法还是加上,因为如果不加上可能会出现下面的问题。


由于需求的变更,要把User类中的getProfile更名为getDetail但忘记修改SpecialUser中的getProfile


假设SpecialUsergetProfile没有用@Override修饰,编译器就不会报错,编译器会认为你的getProfile是一个SpecialUser中的新方法(但这明显就不符合逻辑)。


但如果你在SpecialUsergetProfile前加上了@Override,编译的时候就会报错(提醒你复写的方法不存在,你就知道你忘记改SpecialUser中的getProfilegetDetail了),IDE工具中你也可以得到如下提示:

@SuppressWarnings

作用:让编译器忽略一些提醒(比如使用了过时的API)

@SuppressWarnings部分源码
/**
* Annotation type used to indicate that the compiler should not issue the
* specified warnings for the marked program element. Warnings are not only
* suppressed for the annotated element but also for all program elements
* contained in that element.
* <p>
* It is recommended that programmers always use this annotation on the most
* deeply nested element where it is actually needed.
*
* @since 1.5
*/
@Target( { ElementType.TYPE, ElementType.FIELD, ElementType.METHOD,
    ElementType.PARAMETER, ElementType.CONSTRUCTOR,
    ElementType.LOCAL_VARIABLE })
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {

    /**
     * The list of warnings a compiler should not issue.
     */
    public String[] value();
}

@Target 标明该注解可以注解的元素为 类、接口、枚举变量、成员变量、 方法、 参数、 构造器、 局部变量, @Retention 标明该注解为只在源码中可见(后面具体介绍),它有一个 value 标明它需要传入一个 String[] 的参数(这里先不做具体讲解,后续文章会有介绍)。

value的可选值
属性值 作用
deprecation 使用了不赞成使用的类或方法时的警告
path 在类路径、源文件路径等中有不存在的路径时的警告
serial 当在可序列化的类上缺少 serialVersionUID 定义时的警告
finally 任何 finally 子句不能正常完成时的警告
fallthrough 当 Switch 程序块直接通往下一种情况而没有 Break 时的警告
unchecked 执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型
all 关于以上所有情况的警告
@SuppressWarnings用法示例代码
开发过程中难免会用到一些不推荐使用的方法,但又不希望IDE一直给出划线的提示(强迫症。。。),这里就可以用到这个注解。

上面我们在讲@Deprecated注解的时候把deprecatedMethod注解了,所以使用的时候会被划横线,但是加上@SuppressWarnings注解之后就可以去除掉相应的提示。

元注解

作用:负责注解其他注解(可用于自定义注解)

@Retention
在上一篇文章中就提到注解是有可见范围的(运行时可见、构建时可见、编译时可见),控制注解什么时候可见的就是@Retention

作用:标示注解在什么时候可见(运行时可见、仅在.class文件及源代码中可见、仅在源代码中可见)

@Retention部分源码
/**
* Defines a meta-annotation for determining the scope of retention for an
* annotation. If the retention annotation is not set {@code
* RetentionPolicy.CLASS} is used as default retention.
*
* @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
   RetentionPolicy value();
}

@Document标明该注解需要加到Javadoc文档中,@Retention标明该注解为运行时可见,@Target标明该注解可注解元素类型为注解类型,同样它也需要传入一个value属性(用于标明什么时候可见)。

value可用参数
属性值 作用
RetentionPolicy.RUNTIME 标示该注解可以再运行时通过反射找到(ORM框架许多注解使用了该参数)
RetentionPolicy.CLASS 标示该注解保存在.class文件中,但在运行时不能通过反射找到
RetentionPolicy.SOURSE 标示该注解只在源码中可见
@Retention 用法示例代码

自定义了两个注解(如何自定义后面文章会介绍),RuntimeAnnotation(运行时可见注解)、SourceAnnotation(源码中可见注解)


RuntimeAnnotation.java

@Retention(RetentionPolicy.RUNTIME)
public @interface RuntimeAnnotation {
}

SourceAnnotation.java

@Retention(RetentionPolicy.SOURCE)
public @interface SourceAnnotation {
}

User.java

public class User {
    @RuntimeAnnotation
    private String name = "";

    @SourceAnnotation
    private String age = "";

    public void testRetentionAnnotation() {
        /**
         * 通过反射获取运行时注解
         */
        Class thisClass = this.getClass();
        Field[] fields = thisClass.getDeclaredFields();
        for (Field field :
                fields) {
            if (field.isAnnotationPresent(RuntimeAnnotation.class)) {
                System.out.println("Get Runtime Annotation Success in run time!");

            } else if (field.isAnnotationPresent(SourceAnnotation.class)) {
                System.out.println("Get Source Annotation Success in run time!");

            }

        }
    }

    public static void main(String[] args) {
        new User().testRetentionAnnotation();
    }
}       

上面利用了简单的反射知识(运行时),运行 Usermain方法,我们看到输出了“Get Runtime Annotation Success in run time!“,所以@Retention确实标示了注解的可见范围。


运行结果:

@Target

作用:标示该注解用于注解什么元素(类、方法、变量等)

@Retention部分源码
/**
 * Defines a meta-annotation for determining what {@link ElementType}s an
 * annotation can be applied to.
 *
 * @since 1.5
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}

@Documented标明该注解要加入Javadoc文档中、@Retention标明该注解运行时可见、@Target标明该注解可注解元素为为注解类型,同时它也有一个value参数(下面会有该参数的取值跟意义介绍)。

value可用参数
属性值 作用
ElementType.PACKAGE 标示该注解用于注解包声明
ElementType.ANNOTATION_TYPE 标示该注解用于注解其他注解
ElementType.CONSTRUCTOR 标示该注解用于注解构造函数
ElementType.FIELD 标示该注解用于注解成员变量
ElementType.METHOD 标示该注解用于注解方法
ElementType.TYPE 标示该注解用于注解类,接口,枚举类型
ElementType.PARAMETER 标示该注解用于注解参数
ElementType.LOCAL_VARIABLE 标示该注解用于注解局部变量
@Target使用示例代码

自定义了两个注解,MethodAnnotation(注解方法类型元素)、FieldAnnotation(注解成员变量)


MethodAnnotation.java

@Target(ElementType.METHOD)
public @interface MethodAnnotation {
}

FieldAnnotation.java

@Target(ElementType.FIELD)
public @interface FieldAnnotation {
}

User.java

public class User {
    @FieldAnnotation
    private String name = "";

    @MethodAnnotation
    public String getName(){
        return name;
    }

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

上面的代码我们就可以知道拥有不同Target的注解可以用来注解不同的元素。


当我们把只可用于方法变量的注解用到函数上就会出错(比如使用@FieldAnnotation去注解setName方法)。

@Inherited

作用:指定被它修饰的注解具有继承性(比如InheritedAnnotation注解了BaseClass,SubClass继承了BaseClass,这时SubClass也会具有InheritedAnnotation注解,但方法跟参数等的注解不会被继承)

@Inherited部分源码
/**
 * Defines a meta-annotation for indicating that an annotation is automatically
 * inherited.
 *
 * @since 1.5
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

@Documented标明该注解要加入Javadoc文档中、@Retention标明该注解运行时可见、@Target标明该注解可注解元素为为注解类型

@Inherited使用示例代码

InheritedAnnotation.java

@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface InheritedAnnotation {
}

Test.java

public class Test {
    @InheritedAnnotation
    public class BaseClass {

    }

    public class SubClass extends BaseClass {

    }

    public static void main(String[] args) {
        System.out.println("SubClass has InheritedAnnotation ? " + SubClass.class.isAnnotationPresent(InheritedAnnotation.class));
    }
}

运行结果:

上面运行结果可以看出SubClass确实也有拥有InheritedAnnotation注解。

@Documented

作用:表明被注解元素应该加入到JavaDoc(文档)

@Documented部分源码
/**
* Defines a meta-annotation for indicating that an annotation is documented and
* considered part of the public API.
*
* @since 1.5
*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}   

@Documented标明该注解要加入Javadoc文档中、@Retention标明该注解运行时可见、@Target标明该注解可注解元素为为注解类型

@Documented使用
直接在需要加入到JavaDoc的地方加上该注解即可。

总结

本文主要介绍了Java提供的常用注解(@Deprecated@Override@SuppressWarnings)以及自定义注解时需要用到的元注解(@Retetion@Target@Inherited@Documented),全文篇幅较长但讲的内容整体比较简单,主要还是靠自己动手打代码实践。

思路脑图

完整的思维导图可以在我的github上面查找,地址为https://github.com/liujiescut/AndroidKnowledge

下一篇文章将介绍 如何提取注解。

时间: 2024-10-18 04:16:25

Java注解(二) 系统注解的相关文章

利用Spring AOP与JAVA注解为系统增加日志功能

Spring AOP一直是Spring的一个比较有特色的功能,利用它可以在现有的代码的任何地方,嵌入我们所想的逻辑功能,并且不需要改变我们现有的代码结构. 鉴于此,现在的系统已经完成了所有的功能的开发,我们需要把系统的操作日志记录起来,以方便查看某人某时执行了哪一些操作.Spring AOP可以方便查看到某人某时执行了哪一些类的哪一些方法,以及对应的参数.但是大部分终端用户看这些方法的名称时,并不知道这些方法名代码了哪一些操作,于是方法名对应的方法描述需要记录起来,并且呈现给用户.我们知道,AO

Java核心技术点之注解

本博文是对Java中注解相关知识点的简单总结,若有叙述不清晰或是不准确的地方,希望大家可以指正,谢谢大家:) 一.什么是注解 我们大家都知道Java代码中使用注释是为了向以后阅读这份代码的人解释说明一些事情,注解是注释的升级版,它可以向编译器.虚拟机等解释说明一些事情.比如我们非常熟悉的@Override就是一种元注解,它的作用是告诉编译器它所注解的方法是重写父类的方法,这样编译器就会去检查父类是否存在这个方法,以及这个方法的签名与父类是否相同. 也就是说,注解是描述Java代码的代码,它能够被

java之 ------ JUnit、注解、类加载器

JUnit软件测试技术(工具) 在项目中建立专门用户测试的包结构. 在Junit中,通过@Test注解,可以运行一个方法(鼠标放在选择要运行的方法名上,单击右键,选择Run As,再选择JUnit Test即可). 这样做的好处就是不用在主代码中添加测试代码,避免了代码的冗余.而且一个测试类,可以测试多项功能,不需要main方法. 一. Junit注解说明 使用了@Test注解应该满足以下条件: 1) 必须是无参数的非静态方法. 2) 添加@Test注解的类,必须拥有一个无参数的公开构造 pac

springMVC学习笔记(二)-----注解和非注解入门小程序

最近一直在做一个电商的项目,周末加班,忙的都没有时间更新博客了.终于在上周五上线了,可以轻松几天了.闲话不扯淡了,继续谈谈springMvc的学习. 现在,用到SpringMvc的大部分使用全注解配置,但全注解配置也是由非注解发张而来的.所以,今天就谈谈springMvc最基础的注解和非注解的配置以及开发模式. 一:基础环境准备 1.功能需求:一个简单的商品列表查询 2.开发环境:eclipse,java1.7,springmvc版本:3.2 3.springMvc所需jar包(一定包括spri

Java 8的类型注解:工具和机会

在以前的Java版本中,开发者只能将注解(Annotation)写在声明中.对于Java 8,注解可以写在使用类型的任何地方,例如声明.泛型和强制类型转换等语句: @Encrypted String data;List strings;myGraph = (@Immutable Graph) tmpGraph; 乍一看,类型注解并不是Java新版本最炫的特性.事实上,注解只是语法!工具决定了注解的的语义(即,它们的含义和行为).本文介绍新的注解语法和实用工具,以提高生产力和构建更高质量的软件.

Java 注解入门实例 &amp;&amp; 注解传参

参考 概念:java提供了一种原程序中的元素关联任何信息和任何元数据的途径和方法 JDK内置系统注解: @Override 用于修饰此方法覆盖了父类的方法; @Deprecated 用于修饰已经过时的方法; @Suppvisewarnings 用于通知java编译器禁止特定的编译警告. 注解按照运行机制划分 源码注解:注解只在源码中存在,编译成.class文件就不存在了: 编译时注解:注解在源码和.class文件中都存在(例:JDK自带注解): 运行时注解:在运行阶段还起作用,甚至会影响运行逻辑

Java反射reflection与注解annotation的应用(自动测试机)

一.关于自动测试机 1.什么是自动测试机? 对类中的指定方法进行批量测试的工具 2.自动测试机又什么用? a.避免了冗长的测试代码 当类中的成员方法很多时,对应的测试代码可能会很长,使用测试能够让测试代码非常简洁 b.降低了类与测试代码之间的耦合性 以防万一,测试时应该对类中所有方法进行测试.当我们对类中的一个方法做改动时,很可能我们的测试代码也要做相应改动(如改变了方法名,返回值类型等等),使用测试机能降低类与测试代码之间的耦合性,大大降低不必要的工作量. c.增加了测试的灵活性 测试类与待测

Java 核心技术点之注解

转自:http://www.open-open.com/lib/view/open1473649808122.html 什么是注解 我们都知道在Java代码中使用注释是为了向以后阅读这份代码的人解释说明一些事情,注解是注释的升级版,它可以向编译器.虚拟机等解释说明一 些事情.比如我们非常熟悉的@Override就是一种元注解,它的作用是告诉编译器它所注解的方法是重写父类的方法,这样编译器就会去检查父类是否存在 这个方法,以及这个方法的签名与父类是否相同. 也就是说,注解是用来描述Java代码的,

Java中万恶的注解

本文由码农网 – 孙腾浩原创翻译,转载请看清文末的转载要求,欢迎参与我们的付费投稿计划! 当Java 1.5引入注解,企业开发者对简化EJB和其他企业产品开发抱有很大期望.可以看一看同一时期的一篇文章用EJB 3.0简化企业Java开发. 然而从那时起,Java企业使用注解出现一些无法预料的后果和副作用,一些甚至到今天都没有被注意到.幸运的是,并非所有的副作用都没有被注意到,来看一些例子,在StackOverflow标题为“Why Java Annotations?”有很多有价值的评论,“Are