Java SafeVarargs注释,是否存在标准或最佳实践? [英] Java SafeVarargs annotation, does a standard or best practice exist?

查看:111
本文介绍了Java SafeVarargs注释,是否存在标准或最佳实践?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近遇到了java @SafeVarargs 注释。谷歌搜索使Java中的可变函数不安全的原因让我感到困惑(堆中毒?擦除类型?),所以我想知道一些事情:

I've recently come across the java @SafeVarargs annotation. Googling for what makes a variadic function in Java unsafe left me rather confused (heap poisoning? erased types?), so I'd like to know a few things:


  1. 什么使得变量Java函数在 @SafeVarargs 意义上不安全(最​​好以深入的例子的形式解释)?

  1. What makes a variadic Java function unsafe in the @SafeVarargs sense (preferably explained in the form of an in-depth example)?

为什么这个注释留给程序员自行决定?这不是编译器应该检查的东西吗?

Why is this annotation left to the discretion of the programmer? Isn't this something the compiler should be able to check?

是否有一些标准必须遵守以确保其功能确实是安全的?如果没有,确保它的最佳做法是什么?

Is there some standard one must adhere to in order to ensure his function is indeed varags safe? If not, what are the best practices to ensure it?


推荐答案

1互联网和StackOverflow上有很多关于泛型和变量的特定问题的例子。基本上,当你有一个类型参数类型的可变数量的参数时:

1) There are many examples on the Internet and on StackOverflow about the particular issue with generics and varargs. Basically, it's when you have a variable number of arguments of a type-parameter type:

void foo(T... args);

在Java中,varargs是一种语法糖,在编译时经历了一次简单的重写 :类型为 X ... 的varargs参数将转换为类型为 X [] 的参数;每次调用这个varargs方法时,编译器都会收集varargs参数中的所有变量参数,并创建一个数组,就像 new X [] {...(参数在这里)}}

In Java, varargs are a syntactic sugar that undergoes a simple "re-writing" at compile-time: a varargs parameter of type X... is converted into a parameter of type X[]; and every time a call is made to this varargs method, the compiler collects all of the "variable arguments" that goes in the varargs parameter, and creates an array just like new X[] { ...(arguments go here)... }.

当varargs类型具体如 String时,这很有效。 。如果它是一个类型变量,如 T ... ,当 T 被认为是具体类型时,它也可以工作那个电话。例如如果上述方法属于类 Foo< T> 的一部分,并且您有一个 Foo< String> 引用,然后调用 foo 就可以了,因为我们知道 T String 在代码中的那一点。

This works well when the varargs type is concrete like String.... When it's a type variable like T..., it also works when T is known to be a concrete type for that call. e.g. if the method above were part of a class Foo<T>, and you have a Foo<String> reference, then calling foo on it would be okay because we know T is String at that point in the code.

但是,当 T 是另一个类型参数。在Java中,不可能创建类型参数组件类型的数组( new T [] {...} )。所以Java改为使用 new Object [] {...} (这里 Object 是<$ c的上限$ c> T ;如果上限不同,那就是代替 Object ),然后给出编译器警告。

However, it does not work when the "value" of T is another type parameter. In Java, it is impossible to create an array of a type-parameter component type (new T[] { ... }). So Java instead uses new Object[] { ... } (here Object is the upper bound of T; if there upper bound were something different, it would be that instead of Object), and then gives you a compiler warning.

那么创建 new Object [] 而不是 new T []有什么问题还是其他什么?嗯,Java中的数组在运行时知道它们的组件类型。因此,传递的数组对象在运行时将具有错误的组件类型。

So what is wrong with creating new Object[] instead of new T[] or whatever? Well, arrays in Java know their component type at runtime. Thus, the passed array object will have the wrong component type at runtime.

对于可能最常用的varargs,只需迭代元素,这是没有问题的(你不关心数组的运行时类型),所以这是安全的:

For probably the most common use of varargs, simply to iterate over the elements, this is no problem (you don't care about the runtime type of the array), so this is safe:

@SafeVarargs
final void foo(T... args) {
    for (T x : args) {
        // do stuff with x
    }
}

但是,对于任何依赖于传递的数组的运行时组件类型的东西,它都是不安全的。这是一个不安全和崩溃的简单示例:

However, for anything that depends on the runtime component type of the passed array, it will not be safe. Here is a simple example of something that is unsafe and crashes:

class UnSafeVarargs
{
  static <T> T[] asArray(T... args) {
    return args;
  }

  static <T> T[] arrayOfTwo(T a, T b) {
    return asArray(a, b);
  }

  public static void main(String[] args) {
    String[] bar = arrayOfTwo("hi", "mom");
  }
}

这里的问题是我们依赖于 args T [] 以将其作为 T [] 。但实际上,运行时参数的类型不是 T [] 的实例。

The problem here is that we depend on the type of args to be T[] in order to return it as T[]. But actually the type of the argument at runtime is not an instance of T[].

3)如果你的method的参数类型为 T ... (其中T是任何类型参数),然后:

3) If your method has an argument of type T... (where T is any type parameter), then:


  • 安全:如果您的方法仅取决于数组元素是 T 的实例

  • 不安全:如果它取决于数组的实例 T []

  • Safe: If your method only depends on the fact that the elements of the array are instances of T
  • Unsafe: If it depends on the fact that the array is an instance of T[]

依赖于数组运行时类型的东西包括:将其返回为类型 T [] ,将其作为参数传递给类型为<$ c的参数$ c> T [] ,使用 .getClass()获取数组类型,将其传递给依赖于数组运行时类型的方法,如 List.toArray() Arrays.copyOf()等。

Things that depend on the runtime type of the array include: returning it as type T[], passing it as an argument to a parameter of type T[], getting the array type using .getClass(), passing it to methods that depend on the runtime type of the array, like List.toArray() and Arrays.copyOf(), etc.

2)我上面提到的区别太复杂了,不容易自动区分。

2) The distinction I mentioned above is too complicated to be easily distinguished automatically.

这篇关于Java SafeVarargs注释,是否存在标准或最佳实践?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆