转载自: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. [Abp vNext微服务实践] - vue-element-admin登录二

    简介: Vue Element Admin是基于vue.element ui开发的后台管理ui,abp vNext是abp新一代微服务框架.本篇将会介绍如何改造Vue Element Admin权限验 ...

  2. Files的常用方法都有哪些?(未完成)

    Files的常用方法都有哪些?(未完成)

  3. 牛客练习赛53 E 老瞎眼 pk 小鲜肉 (线段树,思维)

    链接:https://ac.nowcoder.com/acm/contest/1114/E来源:牛客网 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 524288K,其他语言1048 ...

  4. PHPStorm 3.3 破解方法 以及汉化

    第一步修改host文件(host文件地址为): C:\Windows\System32\drivers\etc 将以下内容添加到host文件里面     0.0.0.0 account.jetbrai ...

  5. ShedLock日常使用

    首发于个人博客:ShedLock日常使用 场景模拟 定时器Scheduler在平时使用比较频繁,比如定时数据整理,定时向客户发送问候信息等...,定时任务的配置比较简单,比如在springboot中, ...

  6. rac 数组之遍历

    rac的数组遍历其实很简单.但是有个点需要注意. 以下先举个例子说明遍历的用法 NSArray *temArr = @["]; [temArr.rac_sequence.signal sub ...

  7. HDU4465 Candy

    Candy Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submi ...

  8. WINCE7 SYMBOL MC32N0 SDK,VS2008调试程序,连接设备时,出现bootstrap 未能加载时

    开发工具:visual studio 2008 手持设备: SYMBOL  MC32NO工具->连接到设备->WINCE 7.00连接设备出现bootstrap 未能加载时,试下安装Mot ...

  9. [Javascript] Customize Behavior when Accessing Properties with Proxy Handlers

    A Proxy allows you to trap what happens when you try to get a property value off of an object and do ...

  10. error MSB6006: “cmd.exe”已退出,代码为 3。

    error MSB6006: “cmd.exe”已退出,代码为 3. 这两天调程序遇到一个奇怪的问题. C:\Program Files (x86)\MSBuild\Microsoft.Cpp\v4. ...