Java中的注解/注释详解(Override/Deprecated/SuppressWarning)
2016-08-07 16:46
731 查看
Java中的注解/注释详解
Java中的注释主要有以下三种:Override/Deprecated/SuppressWarning,接下来我们主要讨论这3个注解的内容。
一,什么是注释(注解)
在Java中,注解和注释,我们可以理解为同一个概念。说起注释,我们需要先知道什么是元metadata,这个单词我们国内一般翻译为元数据,
所谓元数据,就是数据的数据。也就是说,元数据存在的意义,就是为了描述数据。有了元数据的概念以后,我们就可以把注释称作Java代码的元
数据。
二,Override
这个注释的作用,是用来标识当前的方法,是否覆盖了它的父类中的方法。为什么要用Override注释呢?个人的理解,Override注释与Java
语法糖有异曲同工之妙,它更多的起到的作用是规范Java代码的编写,方便程序员使用,减少产生BUG的机会。关于这一点,我们可以通过下面2种
方式来证明。第一种方式:源代码经过编译后,用反编译工具JD打开后,所有Override注释的部分都没有了;第二种方式:从JVM的角度来看,在
Class文件的结构中,没有注释内容的定义。
官方定义:
三,Deprecated
Deprecated注释是一个标记注释。所谓标记注释,就是已经过期或者即将过期的方法,不推荐我们使用。这个方法不推荐使用的原因,可能是
存在安全问题,或者是有了更好的方法来替代他。源代码中加入这个标记后,并不影响程序的编译,但加上这个标记后,编译器会显示一些警告信息。
例如当我们使用myeclipse写代码时,使用提示功能:
String str = "yangcq";
str.
当我们输入str.以后,myeclipse会提示String类的所有可用方法,这时,我们找到getBytes这个方法,发现有些不同,方法前面多了一个斜线。这
个就是过期的方法,说明getBytes方法使用了@Deprecated注释。
进入String类的源代码,找到getBytes,这里果然有一个注释@Deprecated
官方定义:
四,SuppressWarnings
SuppressWarnings的作用,通过英文单词的意思,就可以看出来。Suppress是阻止的意思,Suppress Warnings就
是阻止警告信息的提示。在Java中,如果一个方法存在未经检查或者不安全的操作,编译器会提示警告信息。例如我们
最常见的Map和List泛型的问题,请看下面的写法:
Map map = new HashMap();
Map<String,String> map = new HashMap<String,String>();
上面一行的写法,编译器就会提示警告信息,因为Map和HashMap的类型未知,程序执行期间可能存在类型转换的问题,
如果我们用下面这一行的写法,就不会出现警告。怎么不让编译器提示警告信息呢,就是使用SuppressWarnings注解。
我们都知道,JDK1.5之后,Java开始支持泛型,泛型说白了,就是一种语法糖,只是为了方便程序员写程序而引入
的一个概念,是以一种规则的形式,告诉程序员,类似Map map = new HashMap();这种写法,在程序执行阶段,很有可
能存在强制类型转换的错误。更多关于Java语法糖的知识,可以参考我的另一篇博客:
http://blog.csdn.net/reggergdsg/article/details/51973701
SuppressWarnings注解的官方定义如下:
例如下面的一段代码,因为定义的reentrantReadWriteLock锁在之后的程序中一直没有使用,因此编译器会提示警告信
息,使用@SuppressWarnings("unused")以后,编译器不再提示警告信息。我们可以把这个功能理解为Java编程语言的
一种规范,它会以显式的方式,提示程序员对可能出问题的代码进行一次确认。就像下面的代码中,编译器提示以后,
程序员就会去检查一下,然后怎么做,由程序员自己来决定。这样做的好处是可以有效减少一些常见的错误,提高代码
质量。
五,如何自定义注解/注释
在Java中,如果有需求,我们也可以自定义注解/注释。在自定义注解之前,我们需要先了解一下注解的相关语
法。最简单的方法,我们可以看一下Java给我们提供的三种注解是如何定义的,如下:
1,@Ducumented
@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的
工具文档化。Documented是一个标记注解,没有成员。@Ducumented元注解的源码如下:
2,@Target
@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation
类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在
Annotation类型的声明中使用了target可更加明晰其修饰的目标。
作用:用于描述注解的使用范围(即:被描述的注解可以在哪些地方使用)
Target的取值(ElementType)有:
CONSTRUCTOR:用于描述构造器
FIELD:用于描述域
LOCAL_VARIABLE:用于描述局部变量
METHOD:用于描述方法
PACKAGE:用于描述包
PARAMETER:用于描述参数
TYPE:用于描述类、接口(包括注解类型) 或enum声明
Target的源码如下:
3,@Retention
@Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却
被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取
(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对
Annotation的“生命周期”限制。
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
Retention取值(RetentionPoicy)有:
SOURCE:在源文件中有效(即源文件保留)
CLASS:在class文件中有效(即class保留)
RUNTIME:在运行时有效(即运行时保留)
Retention的源码如下:
4,@Inherited
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修
饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法
并不从它所重载的方法继承annotation。
当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种
继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将
展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
Inherited的源码如下:
5,如何自定义注解/注释呢?
首先我们创建一个接口,interface,这个接口和普通的接口有点不一样的地方就是,interface前面需要加一个
@符号,不要担心,不会报错的。如下:
public @interface MyAnnotation // 自定义注解时新建的接口
public interface MyAnnotation // 我们平时使用的接口
源代码贴上(注解的生命周期,使用对象在注释中有详细说明):
OK ,上面新建了3个自定义的注解,接下来,我们编写一个测试类来进行测试,看一下自定义注解都是如何使用
的。就以上面的三个注解为例:
六,自定义注解在实际中的应用
自定义注解都有哪些应用场景呢?自定义注解/注释有什么用途呢?这个问题抛给读者朋友们,大家思考一下,
由于篇幅有限,这里不再详细说明,后面会继续分享关于这方面的文章。给大家一个思路,Hibernate、Spring和
Mybatis等ORM框架,在实现时,使用了大量的注解功能,我们可以阅读一下Hibernate、Spring或者Mybatis的源代码,
了解自定义注解在实际中的应用。
Java中的注释主要有以下三种:Override/Deprecated/SuppressWarning,接下来我们主要讨论这3个注解的内容。
一,什么是注释(注解)
在Java中,注解和注释,我们可以理解为同一个概念。说起注释,我们需要先知道什么是元metadata,这个单词我们国内一般翻译为元数据,
所谓元数据,就是数据的数据。也就是说,元数据存在的意义,就是为了描述数据。有了元数据的概念以后,我们就可以把注释称作Java代码的元
数据。
二,Override
这个注释的作用,是用来标识当前的方法,是否覆盖了它的父类中的方法。为什么要用Override注释呢?个人的理解,Override注释与Java
语法糖有异曲同工之妙,它更多的起到的作用是规范Java代码的编写,方便程序员使用,减少产生BUG的机会。关于这一点,我们可以通过下面2种
方式来证明。第一种方式:源代码经过编译后,用反编译工具JD打开后,所有Override注释的部分都没有了;第二种方式:从JVM的角度来看,在
Class文件的结构中,没有注释内容的定义。
官方定义:
/** * Indicates that a method declaration is intended to override a * method declaration in a superclass. If a method is annotated with * this annotation type but does not override a superclass method, * compilers are required to generate an error message. * * @author Joshua Bloch * @since 1.5 */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.SOURCE) public @interface Override { }
三,Deprecated
Deprecated注释是一个标记注释。所谓标记注释,就是已经过期或者即将过期的方法,不推荐我们使用。这个方法不推荐使用的原因,可能是
存在安全问题,或者是有了更好的方法来替代他。源代码中加入这个标记后,并不影响程序的编译,但加上这个标记后,编译器会显示一些警告信息。
例如当我们使用myeclipse写代码时,使用提示功能:
String str = "yangcq";
str.
当我们输入str.以后,myeclipse会提示String类的所有可用方法,这时,我们找到getBytes这个方法,发现有些不同,方法前面多了一个斜线。这
个就是过期的方法,说明getBytes方法使用了@Deprecated注释。
进入String类的源代码,找到getBytes,这里果然有一个注释@Deprecated
@Deprecated public void getBytes(int srcBegin, int srcEnd, byte dst[], int dstBegin) { if (srcBegin < 0) { throw new StringIndexOutOfBoundsException(srcBegin); } if (srcEnd > count) { throw new StringIndexOutOfBoundsException(srcEnd); } if (srcBegin > srcEnd) { throw new StringIndexOutOfBoundsException(srcEnd - srcBegin); } int j = dstBegin; int n = offset + srcEnd; int i = offset + srcBegin; char[] val = value; /* avoid getfield opcode */ while (i < n) { dst[j++] = (byte)val[i++]; } }
官方定义:
/** * A program element annotated @Deprecated is one that programmers * are discouraged from using, typically because it is dangerous, * or because a better alternative exists. Compilers warn when a * deprecated program element is used or overridden in non-deprecated code. * * @author Neal Gafter * @version %I%, %G% * @since 1.5 */ @Documented @Retention(RetentionPolicy.RUNTIME) public @interface Deprecated { }
四,SuppressWarnings
SuppressWarnings的作用,通过英文单词的意思,就可以看出来。Suppress是阻止的意思,Suppress Warnings就
是阻止警告信息的提示。在Java中,如果一个方法存在未经检查或者不安全的操作,编译器会提示警告信息。例如我们
最常见的Map和List泛型的问题,请看下面的写法:
Map map = new HashMap();
Map<String,String> map = new HashMap<String,String>();
上面一行的写法,编译器就会提示警告信息,因为Map和HashMap的类型未知,程序执行期间可能存在类型转换的问题,
如果我们用下面这一行的写法,就不会出现警告。怎么不让编译器提示警告信息呢,就是使用SuppressWarnings注解。
我们都知道,JDK1.5之后,Java开始支持泛型,泛型说白了,就是一种语法糖,只是为了方便程序员写程序而引入
的一个概念,是以一种规则的形式,告诉程序员,类似Map map = new HashMap();这种写法,在程序执行阶段,很有可
能存在强制类型转换的错误。更多关于Java语法糖的知识,可以参考我的另一篇博客:
http://blog.csdn.net/reggergdsg/article/details/51973701
SuppressWarnings注解的官方定义如下:
/** * Indicates that the named compiler warnings should be suppressed in the * annotated element (and in all program elements contained in the annotated * element). Note that the set of warnings suppressed in a given element is * a superset of the warnings suppressed in all containing elements. For * example, if you annotate a class to suppress one warning and annotate a * method to suppress another, both warnings will be suppressed in the method. * * <p>As a matter of style, programmers should always use this annotation * on the most deeply nested element where it is effective. If you want to * suppress a warning in a particular method, you should annotate that * method rather than its class. * * @since 1.5 * @author Josh Bloch */ @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { /** * SuppressWarnings注解的不同之处在于,SuppressWarnings有一个属性value,这个属性对警告信息进行了分 * 类,比如我们常见的值有:unused、unchecked,下面的2种写法是等价的: * @SuppressWarnings(value="unused") * @SuppressWarnings("unused") */ String[] value(); }
例如下面的一段代码,因为定义的reentrantReadWriteLock锁在之后的程序中一直没有使用,因此编译器会提示警告信
息,使用@SuppressWarnings("unused")以后,编译器不再提示警告信息。我们可以把这个功能理解为Java编程语言的
一种规范,它会以显式的方式,提示程序员对可能出问题的代码进行一次确认。就像下面的代码中,编译器提示以后,
程序员就会去检查一下,然后怎么做,由程序员自己来决定。这样做的好处是可以有效减少一些常见的错误,提高代码
质量。
@SuppressWarnings("unused") public static void main(String[] args) { // 创建可重入锁对象lock Lock lock = new ReentrantLock(); ReentrantReadWriteLock reentrantReadWriteLock = new ReentrantReadWriteLock();// 读写锁 // 在执行一段代码之前获取锁 lock.lock(); // 执行代码,修改余额的值,这里可以是我们项目中任何一个需要加锁的操作 updateAccountBalance(account_balance); // 在执行一段代码之后释放锁 lock.unlock(); }
五,如何自定义注解/注释
在Java中,如果有需求,我们也可以自定义注解/注释。在自定义注解之前,我们需要先了解一下注解的相关语
法。最简单的方法,我们可以看一下Java给我们提供的三种注解是如何定义的,如下:
@Documented @Retention(RetentionPolicy.RUNTIME) public @interface Deprecated { }
1,@Ducumented
@Documented用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的
工具文档化。Documented是一个标记注解,没有成员。@Ducumented元注解的源码如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Documented { }
2,@Target
@Target说明了Annotation所修饰的对象范围:Annotation可被用于 packages、types(类、接口、枚举、Annotation
类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch参数)。在
Annotation类型的声明中使用了target可更加明晰其修饰的目标。
作用:用于描述注解的使用范围(即:被描述的注解可以在哪些地方使用)
Target的取值(ElementType)有:
CONSTRUCTOR:用于描述构造器
FIELD:用于描述域
LOCAL_VARIABLE:用于描述局部变量
METHOD:用于描述方法
PACKAGE:用于描述包
PARAMETER:用于描述参数
TYPE:用于描述类、接口(包括注解类型) 或enum声明
Target的源码如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Target { ElementType[] value(); }
3,@Retention
@Retention定义了该Annotation被保留的时间长短:某些Annotation仅出现在源代码中,而被编译器丢弃;而另一些却
被编译在class文件中;编译在class文件中的Annotation可能会被虚拟机忽略,而另一些在class被装载时将被读取
(请注意并不影响class的执行,因为Annotation与class在使用上是被分离的)。使用这个meta-Annotation可以对
Annotation的“生命周期”限制。
作用:表示需要在什么级别保存该注释信息,用于描述注解的生命周期(即:被描述的注解在什么范围内有效)
Retention取值(RetentionPoicy)有:
SOURCE:在源文件中有效(即源文件保留)
CLASS:在class文件中有效(即class保留)
RUNTIME:在运行时有效(即运行时保留)
Retention的源码如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Retention { RetentionPolicy value(); }
4,@Inherited
@Inherited 元注解是一个标记注解,@Inherited阐述了某个被标注的类型是被继承的。如果一个使用了@Inherited修
饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。
注意:@Inherited annotation类型是被标注过的class的子类所继承。类并不从它所实现的接口继承annotation,方法
并不从它所重载的方法继承annotation。
当@Inherited annotation类型标注的annotation的Retention是RetentionPolicy.RUNTIME,则反射API增强了这种
继承性。如果我们使用java.lang.reflect去查询一个@Inherited annotation类型的annotation时,反射代码检查将
展开工作:检查class和其父类,直到发现指定的annotation类型被发现,或者到达类继承结构的顶层。
Inherited的源码如下:
@Documented @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.ANNOTATION_TYPE) public @interface Inherited { }
5,如何自定义注解/注释呢?
首先我们创建一个接口,interface,这个接口和普通的接口有点不一样的地方就是,interface前面需要加一个
@符号,不要担心,不会报错的。如下:
public @interface MyAnnotation // 自定义注解时新建的接口
public interface MyAnnotation // 我们平时使用的接口
源代码贴上(注解的生命周期,使用对象在注释中有详细说明):
package com.annotation.java; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * * @author yangcq * @description 自定义注解 MyAnnotation * */ @Documented // 这是一个标识注解,标识当前注解是否可以被工具文档化 @Retention(RetentionPolicy.RUNTIME) // 定义注解的生命周期 RUNTIME:在运行时有效(即运行时保留) @Target(ElementType.METHOD) // 定义注解的使用对象,这里定义这个注解只能在方法上使用 public @interface MyAnnotation { // 这就是自定义注解/注释,没有任何内容 }
package com.annotation.java; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * * @author yangcq * @description 自定义注解 MyAnnotationWithValue * */ @Documented // 这是一个标识注解,标识当前注解是否可以被工具文档化 @Retention(RetentionPolicy.RUNTIME) // 定义注解的生命周期 RUNTIME:在运行时有效(即运行时保留) @Target(ElementType.METHOD) // 定义注解的使用对象,这里定义这个注解只能在方法上使用 public @interface MyAnnotationWithValue { String[] value(); }
package com.annotation.java; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * * @author yangcq * @description 自定义注解 MyAnnotationInVariable * */ @Documented // 这是一个标识注解,标识当前注解是否可以被工具文档化 @Retention(RetentionPolicy.RUNTIME) // 定义注解的生命周期 RUNTIME:在运行时有效(即运行时保留) @Target(ElementType.FIELD) // 定义注解的使用对象,这里定义这个注解只能在Field上使用 public @interface MyAnnotationInVariable { }
OK ,上面新建了3个自定义的注解,接下来,我们编写一个测试类来进行测试,看一下自定义注解都是如何使用
的。就以上面的三个注解为例:
package com.annotation.java; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * * @author yangcq * @description 如何使用自定义注解 * */ public class MyAnnotationTest { final Log log = LogFactory.getLog(MyAnnotationTest.class); /** * 注解1:只能在本地变量中使用的注解 */ @MyAnnotationInVariable // 这个注解只能在Field上使用 String str = "yangcq2016"; /** * 注解2:只能在方法上使用的注解 */ @MyAnnotation // 这个注解只能再方法上使用,如果我们在类上使用就会报错 public void eat() { log.info("eat方法使用了我们自定义的注解:MyAnnotation"); } /** * 注解3:只能在方法上使用的注解(带value值) */ @MyAnnotationWithValue(value="yangcq") // 有Value值的注解 public void say(){ log.info("say方法使用了我们自定义的注解:MyAnnotationWithValue"); } }
六,自定义注解在实际中的应用
自定义注解都有哪些应用场景呢?自定义注解/注释有什么用途呢?这个问题抛给读者朋友们,大家思考一下,
由于篇幅有限,这里不再详细说明,后面会继续分享关于这方面的文章。给大家一个思路,Hibernate、Spring和
Mybatis等ORM框架,在实现时,使用了大量的注解功能,我们可以阅读一下Hibernate、Spring或者Mybatis的源代码,
了解自定义注解在实际中的应用。
相关文章推荐
- Java注释Override、Deprecated、SuppressWarnings详解
- Java注释Override、Deprecated、SuppressWarnings详解
- Java注释Override、Deprecated、SuppressWarnings详解
- Java注释Override、Deprecated、SuppressWarnings详解
- java 注解:SuppressWarnings、Deprecated、Override
- Java注释Override、Deprecated、SuppressWarnings详解
- Java 注解(Annotation)@Override @Deprecated @SuppressWarnings
- Java注释Override、Deprecated、SuppressWarnings详解(过时方法,即将删除的方法或成员变量)
- Java注释Override、Deprecated、SuppressWarnings详解
- Java中的注解以及应用 @Deprecated @SupressWarning @Override
- Java注释Override、Deprecated、SuppressWarnings详解 以及自定义注释等
- Java中的注解以及应用 @Deprecated @SupressWarning @Override
- java 注解:SuppressWarnings、Deprecated、Override
- Java中的注解以及应用 @Deprecated @SupressWarning @Override
- JAVA 注解:SuppressWarnings、Deprecated、Override
- java 注解:SuppressWarnings、Deprecated、Override
- Java注释Override、Deprecated、SuppressWarnings详解
- Java注释Override、Deprecated、SuppressWarnings详解
- [Java 5.0] Annotation – @Deprecated @Override @SuppressWarnings
- Java注释Override、Deprecated、SuppressWarnings详解