转载自: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]

  1. package cn.edu.sdut.softlab.safevarargs;
  2.  
  3. import java.util.ArrayList;
  4.  
  5. /**
  6. * Created by subaochen on 17-4-3.
  7. */
  8. public class SafeVarargsTest {
  9. public static void main(String[] args) {
  10. ArrayList<Integer> a1 = new ArrayList<>();
  11. a1.add(new Integer(1));
  12. a1.add(2);
  13.  
  14. showArgs(a1, 12);
  15. }
  16.  
  17. //@SafeVarargs
  18. public static <T> void showArgs(T... array) {
  19. for (T arg : array) {
  20. System.out.println(arg.getClass().getName() + ":" + arg);
  21. }
  22. }
  23.  
  24. }

当我们使用-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
 
  1. package cn.edu.sdut.softlab.safevarargs;
  2.  
  3. import java.util.Arrays;
  4. import java.util.List;
  5.  
  6. /**
  7. * Created by subaochen on 17-4-3.
  8. * 本例取自SafeVarargs的javadoc文档
  9. */
  10. public class UnsafeMethodTest {
  11.  
  12. public static void main(String[] args) {
  13. List&lt;String&gt; list1 = Arrays.asList("one", "two");
  14. List&lt;String&gt; list2 = Arrays.asList("three","four");
  15. unsafeMethod(list1, list2);
  16. }
  17.  
  18. @SafeVarargs // 其实并不安全!
  19. static void unsafeMethod(List&lt;String&gt;... stringLists) {
  20. Object[] array = stringLists;
  21. List&lt;Integer&gt; tmpList = Arrays.asList(42, 56);
  22. array[0] = tmpList; // tmpList是一个List对象(类型已经擦除),赋值给Object类型的对象是允许的(向上塑型),能够编译通过
  23. String s = stringLists[0].get(0); // 运行时抛出ClassCastException!
  24. }
  25. }
运行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数组能够接受任意类型的对象。
  1. array[0] = tmpList;

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

  1. 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. APP移动测试

    (转自网络) App测试与传统台式机测试相比有一定的复杂性.这些复杂性可以被分类为: 环境(大量的设备,各种移动OSs,适应频繁OSs变化) . 设备(触摸式和非触摸式设备,有限的内存容量,电池耗电量 ...

  2. HDU 5876 补图最短路

    开两个集合,一个存储当前顶点可以到达的点,另一个存储当前顶点不能到达的点.如果可以到达,那肯定由该顶点到达是最短的,如果不能,那就留着下一次再判. #include<bits/stdc++.h& ...

  3. MySQL No Install zip安装方法

    解压 解压安装包到一个目录,比如:D:\Database\mysql-5.1.55 配置 创建配置文件 创建一个my.ini文件,MYSQL目录下有几个my开头的ini文件,是针对不同配置使用,具体可 ...

  4. SARS病毒 (生成函数 + 快速幂)

    链接:https://ac.nowcoder.com/acm/contest/992/A来源:牛客网 题目描述 目前,SARS 病毒的研究在世界范围内进行,经科学家研究发现,该病毒及其变种的 DNA ...

  5. python大数据初探--pandas,numpy代码示例

    import pandas as pd import numpy as np dates = pd.date_range(',periods=6) dates import pandas as pd ...

  6. BZOJ 1036 [ZJOI2008]树的统计Count 动态维护树上求和与求最大值 LCT板题

    模板,也可以用树链剖分+线段树做O(nlog2)O(nlog^2)O(nlog2) 用LCT做O(nlog)O(nlog)O(nlog)在乘上一个大于30的常数-然后LCT比树剖慢一倍- CODE # ...

  7. Bert系列 源码解读 四 篇章

    Bert系列(一)——demo运行 Bert系列(二)——模型主体源码解读 Bert系列(三)——源码解读之Pre-trainBert系列(四)——源码解读之Fine-tune 转载自: https: ...

  8. 【SecureCRT】SecureCRT 护眼配色

      终端有一个好的配色,不仅能保护自己的眼睛,也能给人一个好心情,本配色方案适合任意一种SSH客户端软件.   设置背景颜色 Options => Sessions options => ...

  9. 预处理、const、static与sizeof-为什么不把所有的函数都定义成内联函数

    1:内联是以代码膨胀(复制)为代价的,仅仅省去了函数调用的开销,从而提高函数的执行效率.如果执行函数体内代码的时间相比于函数调用的开销较大,那么效率的收获会很小.另一方面,每一处内联函数的调用都要复制 ...

  10. Arcgis python输出当前窗口

    import arcpy mxd = arcpy.mapping.MapDocument("CURRENT") mxdfile=arcpy.GetParameterAsText(0 ...