之前介绍继承的时候,提到对于子类而言,父类的普通方法可以重写也可以不重写,但是父类的抽象方法是必须重写的,如果不重写,编译器就直接在子类名称那里显示红叉报错。例如,以前演示抽象类用法之时,曾经把Chicken鸡类的call方法改为抽象方法,方法声明代码如下所示:

	// 定义一个抽象的叫唤方法。注意后面没有花括号,并且以分号结尾
abstract public void call();

倘若派生自鸡类的公鸡类没有重写call方法,编译器除了红叉报错以外,还会弹出提示“Add unimplemented method”,也就是建议开发者为公鸡类补充实现call方法。按照建议点击提示文字,eclipse会自动在公鸡类中添加以下的默认代码:

	@Override
public void call() {
// TODO Auto-generated method stub
}

注意到新增的call方法上面一行,多出了形如“@Override”的标记,该标记看起来似乎是多余的,即使把它删掉,编译器也不会报错,程序也能正常运行。莫非“@Override”是另一种形式的注释?实际上,以@符号开头的标记,它们的真正名称叫做“注解”,跟“注释”仅有一字之差,二者的关系恰如名字那样,既有相同点又有不同点。相同点为:注解一样带有解释说明的涵义,比如Override翻译成中文就是“重写”的意思,表示标记下方的call方法重写了父类的抽象方法。不同点为:注释是给人看的,而注解还要给编译器看,编译器扫描到注解@Override,便会去检查父类是否存在注解下方的方法声明,如果不存在或者参数类型对不上,就会提示红叉错误。
除了方法重写注解“@Override”之外,还有一种常见的注解叫“@FunctionalInterface”,翻译成中文便是“函数式接口”,猜的没错,该注解专门用来标记Java8规定的函数式接口。函数式接口是一类特殊的接口形式,它的内部有且仅有一个抽象方法,抽象方法多了不行,再来一个抽象方法的话,接口实例就没法简写为Lambda表达式,也就无法成为“函数式”接口。Java自带的几个函数式接口包括:比较器Comparator、断言接口Predicate、消费接口Consumer、函数接口Function、文件过滤器FileFilter、运行器Runnable等等,查看它们的源码,会发现接口定义的上方无一例外都存在注解“@FunctionalInterface”。例如下面是比较器Comparator的核心定义代码:

//该注解表示以下定义的是函数式接口,有且仅有一个抽象方法声明。
//如果同时声明了多个抽象方法,则编译器在编码阶段就会报错。
@FunctionalInterface
public interface Comparator<T> {
int compare(T o1, T o2); // 此处省略比较器接口的剩余代码定义
}

@FunctionalInterface注解明白无误地告诉编译器,它的下方接口是个函数式接口,请务必检查这个接口定义是否符合函数式接口的要求。编译器根据注解的指示,立即扫描注解下方的接口代码,并仔细统计接口内部的抽象方法个数,倘若抽象方法的数量不足一个或者多于一个,编译器都会提示错误“Invalid '@FunctionalInterface' annotation; *** is not a functional interface”,意思是“注解@FunctionalInterface是无效的,因为***不是一个函数式接口”,这样正好提醒开发者检查接口定义是否存在问题。
第三种常见的注解名叫“@Deprecated”,早前介绍日期工具Date的时候,在代码中调用日期实例的getYear、getMonth、getDate等方法,这几个方法的名称中间居然出现了一条删除线。查看相关日期方法的源码,才发觉它们的定义代码上方耸立着注解“@Deprecated”,该注解的含义是“不赞成、已废弃”,缘由是Java认为这几个日期方法已经过时了,随时都会从开发包中移除,建议开发者将它们替换成日历工具里的对应方法。尽管目前仍然可以在代码中调用这些过时的方法,但是编译器依旧按照规定在方法名称中间显示删除线,并且还会给出警告“Add @SupressWarnings 'deprecated' to '***'”。这警告说的是建议往***添加注解“@SupressWarnings”(含义为屏蔽警告),从而避免此处的警告提示。正所谓“眼不见心不烦”,那就按照建议在日期方法的调用处统统添加新注解“@SuppressWarnings("deprecation")”,添加完了,果然这些“已过时”的警告都被屏蔽掉了。
注解@SuppressWarnings不仅可用来屏蔽“已过时”的警告,还能用来屏蔽其它类型的警告,譬如“未使用”这类警告。上一篇文章演示私有方法的反射调用之时,给Chicken类增加了setName、getName、setSex、getSex四个私有方法,这些方法并未被Chicken类自身所调用,编译器会认为它们是“未使用”的方法,因而在这四个方法的定义处提示警告信息“Remove method '***'”,也就是建议删除某某某方法。如果程序员仍想保留这些方法,又不想看到警告提示,则可在Chicken类上方添加注解“@SuppressWarnings("unused")”,表示屏蔽未使用的警告。添加了@SuppressWarnings注解的鸡类定义代码片段示例如下:

//该注解表示屏蔽“未使用”这种警告
@SuppressWarnings("unused")
abstract public class Chicken {
// 此处省略鸡类的其它代码定义 private void setName(String name) { // 设置名称
this.name = name;
} private String getName() { // 获取名称
return this.name;
} private void setSex(int sex) { // 设置性别
this.sex = sex;
} private int getSex() { // 获取性别
return this.sex;
}
}

上面的四种注解中,@Override、@Deprecated、@SuppressWarnings这三种是从Java5开始引入的,而@FunctionalInterface是在Java8才引入的。除此之外,Java7还引入了第五种注解名叫“@SafeVarargs”,主要目的是兼容可变参数中的泛型参数,该注解告诉编译器:此处可变参数中的泛型是类型安全的,不必担心强制类型转换的问题。由于前述的五种注解是系统提供给开发者使用的,因此它们被统称为“内置注解”。

更多Java技术文章参见《Java开发笔记(序)章节目录

Java开发笔记(八十一)如何使用系统自带的注解的更多相关文章

  1. (八十一)利用系统自带App来实现导航

    利用系统的地图App进行导航,只需要传入起点和终点.启动参数,调用MKMapItem的类方法openMapWithItems:launchOptions:来实现定位,调用此方法后会打开系统的地图App ...

  2. Java开发笔记(十一)常见的数学函数

    前面介绍了Java编程的四则运算,虽然提供了基础的加减乘除符号,但是数学上还有其它运算符号,包括四舍五入用到的约等号≍.求绝对值的“| |”.开平方的“√ ̄”,这些运算符形态各异,而且并非ASCII码 ...

  3. Java开发笔记(序)章节目录

    现将本博客的Java学习文章整理成以下笔记目录,方便查阅. 第一章 初识JavaJava开发笔记(一)第一个Java程序Java开发笔记(二)Java工程的帝国区划Java开发笔记(三)Java帝国的 ...

  4. Java开发笔记(八十六)通过缓冲区读写文件

    前面介绍了利用文件写入器和文件读取器来读写文件,因为FileWriter与FileReader读写的数据以字符为单位,所以这种读写文件的方式被称作“字符流I/O”,其中字母I代表输入Input,字母O ...

  5. Java开发笔记(三十八)利用正则表达式校验字符串

    前面多次提到了正则串.正则表达式,那么正则表达式究竟是符合什么定义的字符串呢?正则表达式是编程语言处理字符串格式的一种逻辑式子,它利用若干保留字符定义了形形色色的匹配规则,从而通过一个式子来覆盖满足了 ...

  6. Java开发笔记(一百五十一)Druid连接池的用法

    C3P0连接池自诞生以来在Java Web领域反响甚好,业已成为hibenate框架推荐的连接池.谁知人红是非多,C3P0在大型应用场合中暴露了越来越多的局限性,包括但不限于下列几点:1.C3P0管理 ...

  7. Java开发笔记(一百三十八)JavaFX的箱子

    前面介绍了JavaFX标签控件的用法,其中提到Label文本支持中文字体,那么它到底支持哪些中文字体呢?自然要看当前的操作系统都安装了哪些字体才行,对于中文的Windows系统,默认安装了黑体“Sim ...

  8. Java开发笔记(八十九)缓存字节I/O流

    文件输出流FileOutputStream跟FileWriter同样有个毛病,每次调用write方法都会直接写到磁盘,使得频繁的写操作性能极其低下.正如FileWriter搭上了缓存兄弟Buffere ...

  9. Java开发笔记(八十八)文件字节I/O流

    前面介绍了如何使用字符流读写文件,并指出字符流工具的处理局限,进而给出随机文件工具加以改进.随机文件工具除了支持访问文件内部的任意位置,更关键的一点是通过字节数组读写文件数据,采取字节方式比起字符方式 ...

随机推荐

  1. 你真的知道final关键字吗?

    概述 final在英文中是最终的,不可更改的.在Java中final修饰变量,函数和类,就像这个单词的意思,一旦使用赋值之后不可更改. final修饰的变量不可以被改变 finalTest类 publ ...

  2. CART决策树和随机森林

    CART 分裂规则 将现有节点的数据分裂成两个子集,计算每个子集的gini index 子集的Gini index: \(gini_{child}=\sum_{i=1}^K p_{ti} \sum_{ ...

  3. 『性能』ServiceStack.Redis 和 StackExchange.Redis 性能比较

    背景 近来,需要用到 Redis 这类缓存技术 —— MongoDB 和 Redis 没有进行过比较. 我也懒得在这些细节上 纠结那么多 —— 按照网友给出的文章,听从网友建议,选择 Redis. R ...

  4. Java 在PDF 中添加超链接

    对特定元素添加超链接后,用户可以通过点击被链接的元素来激活这些链接,通常在被链接的元素下带有下划线或者以不同的颜色显示来进行区分.按照使用对象的不同,链接又可以分为:文本超链接,图像超链接,E-mai ...

  5. 3.JAVA-方法重载,类的封装,构造/析构方法

    1.方法重载 和C++的函数重载一样,主要是实现多个相同的函数名,但是参数表不同. 参数表不同主要有以下几种 1) 参数个数不同 2) 参数类型不同 3) 参数顺序不同 2.类和对象 类class 用 ...

  6. DFS(深度优先搜索)

    简介 DFS的过程是一个递归过程,它是从图中的某个顶点开始,首先访问起始点v,然后选择一个与顶点v相邻的且没有被访问的顶点w,以w为起始顶点,在进行DFS,直到图中所有与v相邻的顶点都被访问过为止. ...

  7. sql 语句 获取某张表某列字段最短的某几行数据

    sql 语句 获取某张表某列字段最短的某几行数据 SELECT C_name,C_code FROM Catalog where LEN(C_code)=LEN((SELECT top 1 C_cod ...

  8. Node.js 事件循环机制

    Node.js 采用事件驱动和异步 I/O 的方式,实现了一个单线程.高并发的 JavaScript 运行时环境,而单线程就意味着同一时间只能做一件事,那么 Node.js 如何通过单线程来实现高并发 ...

  9. jquery操作iframe的方法:父页面和子页面相互操作的方法

    今天在弄jquery操作iframe中元素:先由iframe中的子页面b.html给外面的父页面a.html页面传值,再将a.html页面计算机的值放到b.html页面上,这里就用到子页面和父页面相互 ...

  10. Vue(day8)

    继续上一篇文章的内容,本文主要内容为项目中新闻资讯模块的实现. 新闻资讯页面主要是当我们点击这个按钮时跳转到新闻列表界面. 一.新闻资讯的路由设计 将新闻资讯的标签改为路由:(a标签改为router- ...