做h游戏视频网站建设银行注册网站首页

当前位置: 首页 > news >正文

做h游戏视频网站,建设银行注册网站首页,window优化大师官网,天津网站开发tjniu故事的小黄花 从出生那年就飘着 童年的荡秋千 随记忆一直晃到现在 可变参数#xff08; vararg #xff09; 方法#xff08;详见第 53 条#xff09;和泛型都是在 Java 5 中就有了#xff0c;因此你可能会期待它们可以良好地相互作用#xff1b;遗憾的是#xff0c;它们… 故事的小黄花 从出生那年就飘着 童年的荡秋千 随记忆一直晃到现在 可变参数 vararg 方法详见第 53 条和泛型都是在 Java 5 中就有了因此你可能会期待它们可以良好地相互作用遗憾的是它们不能 。 可变参数的作用在于让客户端能够将可变数量的参数传给方法但这是个技术露底 leaky abstration 当调用一个可变参数方法时会创建一个数组用来存放可变参数这个数组应该是一个实现细节它是可见的 。因此当可变参数有泛型或者参数化类型时编译警告信息就会产生温乱 。 回顾一下第28条非具体化( non-reifable)类型是指其运行时代码信息比编译时少并且显然所有的泛型和参数类型都是非具体化的。如果一个方法声明其可变参数为non-reifiable类型编译器就会在声明中产生一条警告。如果方法是在类型为non-reifiable的可变参数.上调用编译器也会在调用时发出一条警告信息。这个警告信息类似于 当一个参数化类型的变量指向一个不是该类型的对象时会产生堆污染 heap pollution)。 它导致编辑器的自动生成转换失败破坏了泛型系统的基本保证 。 举个例子 。 下面的代码是对第 28 条中的代码片段稍加修改而得 这个方法没有可见的转换但是在调用一个或者多个参数时会抛出 ClassCast­Exception 异常。 上述最后一行代码中有一个不可见的转换这是由编译器生成的 。 这个转换失败证明类型安全已经受到了危及因此将值保存在泛型可变参数数组参数 中是不安全的 。 这个例子引出了 一个有趣的问题为什么显式创建泛型数组是非法的用泛型可变参数声明方法却是合法的呢换句话说为什么之前展示的方法只产生一条警告而第 28 条中的代码片段却产生一个错误呢答案在于带有泛型可变参数或者参数化类型的方法在实践中用处很大因此 Java 语言的设计者选择容忍这 一矛盾的存在 。 事实上Java 类库导出了好几个这样的 方法包括 Arrays.asList(T … a 、Collections.addAll (Collection? super T C, T … elements 以及 EnumSet.of (E first,E … rest 。 与前面提到的危险方法不一样这些类库方法是类型安全的 。 在 Java 7 之前带泛型可变参数的方法的设计者对于在调用处 出错的警告信息一点办法也没有。 这使得这些 API 使用起来非常不愉快 。 用户必须忍受这些警告要么最好在每处调用点都通过SuppressWarnings 飞rnchecked”注解来消除警告详见第 27条 。 这么做过于烦琐而且影响可读性并且掩盖了反映实际问题的警告 。 在 Java 7 中增加了 SafeVarargs 注解它让带泛型 vararg 参数的方法的设计者能够自动禁止客户端的警告 。 本质上SafeVarargs 注解是通过方法的设计者做出承诺声明这是类型安全的。 作为对于该承诺的交换编译器同意不再向该方法的用户发出警告说这些调用可能不安全。 重要的是不要随意用 SafeVarargs 对方法进行注解除非它真正是安全的 。 那么它凭什么确保安全呢回顾一下泛型数组是在调用方法的时候创建的用来保存可变参数 。 如果该方法没有在数组中保存任何值也不允许对数组的引用转义这可能导致不被信任的代码访问数组那么它就是安全的 。 换句话说如果可变参数数组只用来将数量可变的参数从调用程序传到方法毕竟这才是可变参数的目的那么该方法就是安全的 。 值得注意的是从来不在可变参数的数组中保存任何值这可能破坏类型安全性 。以下面的泛型可变参数方法为例它返回了一个包含其参数的数组 。 乍看之下这似乎是一个方便的小工具
staticT T[] toArray(T… args) {return args; } 这个方法只是返回其可变参数数组看起来没什么危险但它实际上很危险 这个数组的类型是由传到方法的参数的编译时类型来决定的编译器没有足够的信息去做准确的决定 。 因为该方法返回其可变参数数组 它会将堆污染传到调用堆枝上 。 下面举个具体的例子 。 这是一个泛型方法它带有三个类型为 T 的参数并返回 一个包含两个随机选择的参数的数组 这个方法本身并没有危险也不会产生警告除非它 调用了 带有泛型 可 变参数的toArray 方法 。  在编译这个方法时编译器会产生代码 创建一个可变参数数组并将两个 T 实例传到 toArray 。 这些代码配置了 一个类型为 Object[ ]的数组这是确保能够保存这些实例的最具体的类型无论在调用时给 pickTwo 传递什么类型的对象都没问题 。toArray 方法只是将这个数组返回给 pickTwo 反过来也将它返回 给其调用程序因 此 pickTwo 始终都会返回一个类型为 Object[]的数组 。 允许另一个方法访问一个泛型可变参数数组是不安全的 有两种情况例外 将数组传给另一个用 SafeVarargs 正确注解过的可变参数方法是安全的将数组传给只计算数组内容部分函数的非可变参数方法也是安全的 。 确定何时应该使用 SafeVarargs 注解的规则很简单 对于每一个带有泛型可变参数或者参数化类型的方法都要用 SafeVarargs 进行注解这样它的用户就不用承受那些无谓的、令人困惑的编译警报了 。  每当编译器警告你控制 的某个带泛型可变参数的方法可能形成堆污染就应该检查该方法是否安全 。 这里先提个醒泛型可变参数方法在下列条件下是安全的
它没有在可变参数数组中保存任何值 。它没有对不被信任的代码开放该数组或者其克隆程序 。 以上两个条件只要有任何一条被破坏就要立即修正它 。 注意SafeVarargs 注解只能用在无法被覆盖的方法上因为它不能确保每个可能的覆盖方法都是安全的 。 在 Java 8 中该注解只在静态方法和 final实例方法中才是合法的在 Java 9 中它在私有的实例方法上也合法了 。 总而言之可变参数和泛型不能良好地合作这是因为可变参数设施是构建在顶级数组之上的一个技术露底泛型数组有不同的类型规则 。 虽然泛型可变参数不是类型安全的但它们是合法的 。 如果选择编写带有泛型或者参数化可变参数的方法首先要确保该方法是类型安全的然后用SafeVarargs 对它进行注解这样使用起来就不会出现不愉快的情况了 。