Java 从Java 5开始支持注解。
了解了注解的概念以及作用以后,我们来学习一下Java提供的5个基本注解,这5个最基本的注解是:
- @Override
- @Deprecated
- @SuppressWarnings
- @SafeVarargs
- @FunctionalInterface
注意:使用注解时要在注解前加@符号。使用注解很简单,只需要把注解当成一个修饰符来修饰它支持的程序元素即可。
@Override
@Override注解用来指定子类必须重写父类方法。也就是说如果一个方法被@Override注解所修饰,那么改方法必须是重写了父类的方法,否则编译报错。
示例代码
- 声明Fu.java
public class Fu {
public void eat() {}
}
- 声明Zi.java,继承Fu
public class Zi extends Fu {
@Override
public void eat() {}//只要不符合方法重写的规则就编译报错}
}
@Override注解主要是用来帮助开发者避免一些低级错误,例如在子类重写父类方法时候不小心将子类的方法名称给写错误。就像这样,本来想写的是execute()结果却写成了executer();这个时候就成了子类独有的方法,而不是子类重写父类的方法。
@Deprecated
@Deprecated注解用于指示程序元素(类,方法等)已过时。
示例代码
public class Zi extends Fu {
@Deprecated
@Override
public void eat() {}//可以看出来一个程序元素可以被多个注解修饰
}
@SuppressWarnings
@SuppressWarnings注解用于取消编译器提示的警告信息。@SuppressWarnings会一直作用于该程序元素的所有子元素。例如使用@SuppressWarnings修饰某个类取消编译器的某个警告,同时又使用@SuppressWarnings修饰类中的某个方法取消编译器的另一个警告,那么该方法将会同时取消编译器的这两个警告。
抑制单一类型警告
编译器的警告信息有多种多样,在抑制单一类型警告这种情况中@SuppressWarnings只负责抑制一种类型的警告信息。
示例代码
@SuppressWarnings(value = "unchecked")
public static void main(String[] args) {
@SuppressWarnings(value = "rawtypes")
// 没有泛型的集合,编译器会给出警告信息,rawtypes用于取消编译给出new Arraylist()警告
List list = new ArrayList();
//没有泛型的集合添加元素,可能会引发unchecked异常,所以编译器会给出警告信息,unchecked用于取消添加元素时的警告信息
list.add(new Object());
}
抑制多种类型警告
为了方便起见,也可以让一个@SuppressWarnings注解抑制多种类型的警告信息。
示例代码
@SuppressWarnings(value = { "rawtypes", "unchecked" })
// 使用一个@SuppressWarnings注解抑制多种警告信息
public static void main(String[] args) {
List list = new ArrayList();
list.add(new Object());
}
抑制所有类型警告
顾名思义,就是让一个@SuppressWarnings注解抑制所有的类型的警告信息
示例代码
@SuppressWarnings(value = "all")
public static void main(String[] args) {
List list = new ArrayList();
list.add(new Object());
}
@SuppressWarnings的参数值
@SuppressWarnings注解定义在java.lang.SuppressWarnings中,用来抑制编译时的警告信息。使用它的时候需要添加一个参数,这些参数值都是已经定义好了的。具体看下表
|
参数名称 |
说明 |
|
Deprecation |
使用了过时的类或者方法的警告 |
|
Unchecked |
执行了未检查的转换的警告,例如使用集合时候未指定泛型 |
|
fallthrough |
switch语句中发生case穿透编译警告 |
|
Path |
在类路径,源文件路径等中有不存在路径的编译警告 |
|
Serial |
可序列化的类中缺少serialVersionUID定义的警告 |
|
Finally |
任何finally子句不能完成时警告 |
|
All |
关于以上所有的警告 |
@SafeVarargs
在Java中,将一个不带泛型的对象赋值给一个带泛型的变量,这种情况称之为”堆污染(heap pollution)”。发生”堆污染”以后,代码并不是固定的运行出错,也不是固定的运行正常,而是根据实际情况来定的。
“堆污染”示例
示例代码一:
public static void main(String[] args) {
List listA = new ArrayList<String>();
listA.add("小钻风");
List<Integer> listB = new ArrayList<>();
// "堆污染"代码,编译运行不报错
listB = listA;
// 运行报错,类转换异常
Integer integer = listB.get(0);
System.out.println(integer);
}
分析 : 如果将ListB的泛型定义成String类型,那么运行的时候就不会报错。所以发生“堆污染”以后,代发是否运行报错是根据实际情况而定的。
@SafeVarargs示例
注解@SafeVarargs就是用来取消编译器的堆污染警告信息。
示例代码二
Java不支持泛型数组,所以对于参数可变的方法,该方法的形式参数又带泛型,将更容易导致“堆污染”。因为Java在运行的时候会擦除泛型,因此程序在运行的时候会把List<Integer>…当成List[]处理,这就是发生“堆污染”的原因。
@SuppressWarnings(value = {"rawtypes", "unused" })
@SafeVarargs //取消堆污染警告信息
public static void addList(List<Integer>... lists) {
// java不支持泛型数组,这里已经发生堆污染
List[] listArray = lists;
List<String> aLists = new ArrayList<>();
listArray[0] = aLists;
aLists.add("小钻风");
//运行报错,将lists泛型修改成String,那么运行就又不报错了(修改以后记得用String接受哦)
Integer xiaozuanfeng = lists[0].get(0);
}
解析:取消编译器的堆污染警告信息并不意味着运行代码固定正常,它仅仅是取消编译器的警告信息而已。要始终记住,注解,只是一种符号,它帮助开发者在不改变原有逻辑的情况下进行补充,嵌入一些信息等操作。注解的删除,增加并不会影响代码的执行。
泛型数组
Java虽然不支持泛型数组,但是却可以声明变量是泛型数组类型,这样就可以将运行时期的错误提前到编译期间,保证代码运行正常。这也正是泛型的好处之一。
@SafeVarargs //取消堆污染编译警告信息
public static void addList(List<Integer>... lists) {
//java中不支持泛型数组,创建这种对象会报错
//new ArrayList<Integer>[10];
//跟上次相比,这次的变量类型是泛型数组,那么在编译期间就可以检查元素类型
List<Integer>[] listArray = lists;
List<String> aLists = new ArrayList<>();
//编译报错,避免运行时错误
//listArray[0] = aLists;
aLists.add("小钻风");
Integer xiaozuanfeng = lists[0].get(0);
}
小结
通过以上三个示例代码,可以总结出来,发生”堆污染”的代码运行时是否异常,要根据实际情况而定。基于这种情况,Java 7在定义方法的时候就发出”堆污染”警告,让开发者更早地注意到程序中可能存在的漏洞。当开发者不希望看到这个警告的时候,有如下三种解决方案
- 使用@SafeVarargs注解修饰引发堆污染警告的方法或构造器
- 使用@SuppressWarnings(“unchecked”)修饰
- 在编译时使用-Xlint:varargs选项
很显然,第三种方式是很少使用,通常选择第一种或者第二种方式。尤其第一种方式,它是Java 7专门为抑制堆污染警告提供的。
@FunctionalInterface
该注解的功能很简单,它用来指示某个接口必须是函数式接口。所以该注解只能修饰接口,不能修饰其它程序元素。
函数式接口就是为Java 8的Lambda表达式准备的,Java 8允许使用Lambda表达式创建函数式接口的实例,因此Java 8专门增加了@FunctionalInterface注解。
示例代码
@FunctionalInterface
public interface FunctionalInterfaceTest {
/*
* 只要接口中的抽象方法数量不是一,则编译报错
* 所以放开test2()或者注释掉test()都会编译报错
* 所以该注解就是用来帮助开发者避免一些低级错误
*/
public abstract void test();
// public abstract void test2();
}
2万+

被折叠的 条评论
为什么被折叠?



