转载自:http://softlab.sdut.edu.cn/blog/subaochen/2017/04/safevarargs%E7%9A%84%E7%94%A8%E6%B3%95/

@SafeVarargs在JDK 7中引入,主要目的是处理可变长参数中的泛型,此注解告诉编译器:在可变长参数中的泛型是类型安全的。可变长参数是使用数组存储的,

而数组和泛型不能很好的混合使用[effective-java, p105,第25条:列表优先于数组]

1、

简单的说,数组元素的数据类型在编译和运行时都是确定的,而泛型的数据类型只有在运行时才能确定下来,因此当把一个泛型存储到数组中时,编译器在编译阶段
无法检查数据类型是否匹配,因此会给出警告信息:存在可能的“堆污染”(heap pollution),即如果泛型的真实数据类型无法和参数数组的类型匹配,会导致ClassCastException异常。

,因此当在可变长参数中使用泛型时,编译器都会给出警告信息。考虑#[java-7-new-feature-cookbook, p35]

package cn.edu.sdut.softlab.safevarargs;

import java.util.ArrayList;

/**
* Created by subaochen on 17-4-3.
*/
public class SafeVarargsTest {
public static void main(String[] args) {
ArrayList<Integer> a1 = new ArrayList<>();
a1.add(new Integer(1));
a1.add(2); showArgs(a1, 12);
} //@SafeVarargs
public static <T> void showArgs(T... array) {
for (T arg : array) {
System.out.println(arg.getClass().getName() + ":" + arg);
}
} }

当我们使用-Xlint:unchecked参数编译此代码时

2、

如果使用IDE进行编译,需要修改编译参数,增加-Xlint:unchecked编译选项。

,有如下的警告信息:

$ javac -Xlint:unchecked cn/edu/sdut/softlab/safevarargs/SafeVarargsTest.java
cn/edu/sdut/softlab/safevarargs/SafeVarargsTest.java:18: 警告: [unchecked] 参数化 vararg 类型T的堆可能已受污染
public static <T> void showArgs(T… array) {
^
其中, T是类型变量:
T扩展已在方法 <T>showArgs(T…)中声明的Object
1 个警告
但是显然在这个示例中,可变参数的泛型是安全的,因此可以启用#中的@SafeVarargs注解消除这个警告信息。请读者自行验证。
@SafeVarargs注解只能用在参数长度可变的方法或构造方法上,且方法必须声明为static或final,否则会出现编译错误。一个方法使用@SafeVarargs注解的前提是,
开发人员必须确保这个方法的实现中对泛型类型参数的处理不会引发类型安全问题,否则可能导致运行时的类型转换异常。下面给出一个“堆污染”的实例,参见1
 
package cn.edu.sdut.softlab.safevarargs;

import java.util.Arrays;
import java.util.List; /**
* Created by subaochen on 17-4-3.
* 本例取自SafeVarargs的javadoc文档
*/
public class UnsafeMethodTest { public static void main(String[] args) {
List&lt;String&gt; list1 = Arrays.asList("one", "two");
List&lt;String&gt; list2 = Arrays.asList("three","four");
unsafeMethod(list1, list2);
} @SafeVarargs // 其实并不安全!
static void unsafeMethod(List&lt;String&gt;... stringLists) {
Object[] array = stringLists;
List&lt;Integer&gt; tmpList = Arrays.asList(42, 56);
array[0] = tmpList; // tmpList是一个List对象(类型已经擦除),赋值给Object类型的对象是允许的(向上塑型),能够编译通过
String s = stringLists[0].get(0); // 运行时抛出ClassCastException!
}
}
运行UnsafeMethodTest的结果如下:
Exception in thread “main” java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
at cn.edu.sdut.softlab.safevarargs.UnsafeMethodTest.unsafeMethod( UnsafeMethodTest.java:22 )
at cn.edu.sdut.softlab.safevarargs.UnsafeMethodTest.main( UnsafeMethodTest.java:14 )
对这个结果意外吗?我们来详细分析一下。在1中,当代码执行到第22行时的状态如1所示,数组array和stringLists同时指向了参数数组,tmpList是一个包含两个Integer对象的list对象。
 
图 1: 可变长参数的初始状态
当程序执行到
 
3、
这里的赋值操作是合法的,因为tmplist是List类型的对象,array是一个Object类型的数组,根据Java允许“向上塑型”的原则,array数组能够接受任意类型的对象。
array[0] = tmpList;

时,几个变量的关系如2所示,虚线表示原先的指向关系,实线表示新的指向关系。此时,参数数组的第0个元素指向了包含两个Integer对象的list对象tmpList。当进一步执行:

   String s = stringLists[0].get(0);
时,从参数数组中取出第0个元素为list对象(tmpList),再取出list对象的第0个元素为Integer类型的对象(其值为42)。问题在这里出现了,我们试图将一个Integer类型的对象赋值给String类型的对象,显然会导致类型转换异常(ClassCastException)。
因此,这个方法是不应该标记为@SafeVarargs的。
图 2: 可变长参数遭到堆污染

SafeVarargs的用法的更多相关文章

  1. @SafeVarargs 使用说明

    说明: @SafeVarargs 是jdk1.7引入的适用于可变参数与泛型能够更好结合的一个注解. 官方解释: 程序员认定带有注释的主体或者构造函数不会对其执行潜在的不安全操作 将此注释应用于未经检查 ...

  2. EditText 基本用法

    title: EditText 基本用法 tags: EditText,编辑框,输入框 --- EditText介绍: EditText 在开发中也是经常用到的控件,也是一个比较必要的组件,可以说它是 ...

  3. jquery插件的用法之cookie 插件

    一.使用cookie 插件 插件官方网站下载地址:http://plugins.jquery.com/cookie/ cookie 插件的用法比较简单,直接粘贴下面代码示例: //生成一个cookie ...

  4. Java中的Socket的用法

                                   Java中的Socket的用法 Java中的Socket分为普通的Socket和NioSocket. 普通Socket的用法 Java中的 ...

  5. [转载]C#中MessageBox.Show用法以及VB.NET中MsgBox用法

    一.C#中MessageBox.Show用法 MessageBox.Show (String) 显示具有指定文本的消息框. 由 .NET Compact Framework 支持. MessageBo ...

  6. python enumerate 用法

    A new built-in function, enumerate() , will make certain loops a bit clearer. enumerate(thing) , whe ...

  7. [转载]Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法总结

    本文对Jquery中$.get(),$.post(),$.ajax(),$.getJSON()的用法进行了详细的总结,需要的朋友可以参考下,希望对大家有所帮助. 详细解读Jquery各Ajax函数: ...

  8. 【JavaScript】innerHTML、innerText和outerHTML的用法区别

    用法: <div id="test">   <span style="color:red">test1</span> tes ...

  9. chattr用法

    [root@localhost tmp]# umask 0022 一.chattr用法 1.创建空文件attrtest,然后删除,提示无法删除,因为有隐藏文件 [root@localhost tmp] ...

随机推荐

  1. Centos7下搭建WebGoat 8和DVWA环境

    搭建WebGoat 安装前置条件说明 我们这里选择WebGoat的jar版本,由于WebGoat 8的jar文件已自带了tomcat和数据库,所以不需要再另外安装tomcat和mysql这种东西,只需 ...

  2. 算法9-----输出全排列(递归)---移除K个数,剩下最小数。

    1.题目:给定一个字符串,输出所有的字典序. 如: 输入字符串:'ac',输出:['ac','ca'] 输入字符串:‘abc' ,输出:['abc','acb','bac','bca','cab',' ...

  3. NOI2018 你的名字——SAM+线段树合并

    题目链接在这里洛谷/LOJ 题目大意 有一个串\(S\),每次询问给你一个串\(T\),两个数\(L\)和\(R\),问你\(T\)有多少个本质不同的子串不是\(S[L,R]\)的子串 SOLUTIO ...

  4. django缓存--缓存加数据库型

    4.缓存+数据库Session 数据库用于做持久化,缓存用于提高效率   a. 配置 settings.py       SESSION_ENGINE = 'django.contrib.sessio ...

  5. binlog2sql闪回工具的使用

    binlog2sql闪回工具的使用 一.下载安装依赖的python yum install openssl-devel bzip2-devel expat-devel gdbm-devel readl ...

  6. hybird(h5)页面自动化测试

  7. BZOJ 2982 combination 脑子+组合数学

    可以发现,整个数列构成一个树形结构,并且是个完全二叉堆(小根堆). 并且这个堆的形态在给定$n$后是固定的,第1个位置上显然只能放1. 对子树的根来说,他自己是所分得的数集中最小的那个,所以从剩下$s ...

  8. SQL Server text field里面有换行符的时候copy到excel数据会散乱

    解决方法: select '"'+convert(varchar(8000),testField)+'"'astestField from testTable 这样虽然结果集里面有 ...

  9. Ubuntu16.04下安装多版本cuda和cudnn

    Ubuntu16.04下安装多版本cuda和cudnn 原文 https://blog.csdn.net/tunhuzhuang1836/article/details/79545625 前言 因为之 ...

  10. ie8中如何使用base64

    由于ie8中不能使用jQuery2.0以上版本所以无法使用 window.btoa()加密 window.atob()解密 所以只能使用最原生的base64加密方法如下: /** * Created ...