Java 是否可以解决“为可变参数参数创建了一个通用的 T 数组”编译器警告?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1445233/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-12 12:21:56  来源:igfitidea点击:

Is it possible to solve the "A generic array of T is created for a varargs parameter" compiler warning?

javagenerics

提问by matt b

This is a simplified version of the code in question, one generic class uses another class with generic type parameters and needs to pass one of the generic types to a method with varargs parameters:

这是所讨论代码的简化版本,一个泛型类使用另一个具有泛型类型参数的类,并且需要将其中一种泛型类型传递给具有可变参数的方法:

class Assembler<X, Y> {
    void assemble(X container, Y... args) { ... }
}

class Component<T> {
    void useAssembler(T something) {

        Assembler<String, T> assembler = new Assembler<String, T>();

        //generates warning:
        // Type safety : A generic array of T is
        // created for a varargs parameter
        assembler.assemble("hello", something);
    }

}

}

Is there any correct way to pass along the generic parameter to a varargs method without encountering this warning?

是否有任何正确的方法将泛型参数传递给可变参数方法而不会遇到此警告?

Of course something like

当然像

assembler.assemble("hello", new T[] { something });

does not work since you cannot create generic arrays.

不起作用,因为您无法创建通用数组。

采纳答案by Kevin

Other than adding @SuppressWarnings("unchecked"), I don't think so.

除了添加@SuppressWarnings("unchecked"),我不这么认为。

This bug reporthas more information but it boils down to the compiler not liking arrays of generic types.

这个错误报告有更多信息,但归结为编译器不喜欢泛型类型的数组。

回答by Tom Hawtin - tackline

It is a very easy problem to solve: Use List<T>!

这是一个很容易解决的问题:使用List<T>

Arrays of reference type should be avoided.

应该避免引用类型的数组。

In the current version of Java (1.7), you can mark method with @SafeVargswhich will remove the warning from the caller. Careful with that though, and you're still better off without legacy arrays.

在当前版本的 Java (1.7) 中,您可以标记方法,@SafeVargs用于从调用者中删除警告。不过要小心,如果没有遗留数组,你仍然会过得更好。

See also the Improved Compiler Warnings and Errors When Using Non-Reifiable Formal Parameters with Varargs Methodstech note.

另请参阅在可变参数方法中使用不可具体化的形式参数时改进的编译器警告和错误技术说明。

回答by KLE

When workings with arrays of generic type, I am forced to pass a reference to the generic type. With that, I can actually do the generic code, using java.lang.reflect.Array.

当使用泛型类型的数组时,我被迫传递对泛型类型的引用。有了这个,我实际上可以使用 java.lang.reflect.Array 执行通用代码。

http://java.sun.com/javase/6/docs/api/java/lang/reflect/Array.html

http://java.sun.com/javase/6/docs/api/java/lang/reflect/Array.html

回答by EA.

You can have overload the methods. This does not solve your problem but it minimizes the number of warnings (and yes, it's a hack!)

您可以重载这些方法。这不能解决您的问题,但可以最大限度地减少警告的数量(是的,这是一个黑客!)

class Assembler<X, Y> {
  void assemble(X container, Y a1) { ... }
  void assemble(X container, Y a1, Y a2) { ... }
  void assemble(X container, Y a1, Y a2, Y a3) { ... }
  void assemble(X container, Y a1, Y a2, Y a3, Y a4) { ... }
  void assemble(X container, Y... args) { ... }
}

回答by Cowan

Tom Hawtin pointed this out in a comment, but to be more explicit: yes, you can solve this at the declaration-site (rather than the (potentially many) call sites): switch to JDK7.

Tom Hawtin 在评论中指出了这一点,但更明确地说:是的,您可以在声明站点(而不是(可能很多)调用站点)解决此问题:切换到 JDK7。

As you can see in Joseph Darcy's blog post, the Project Coin exercise to select some small incremental language improvements for Java 7 accepted Bob Lee's proposalto allow something like @SuppressWarnings("varargs")at the method side to make this warning go away in situations where it was known to be safe.

正如您在Joseph Darcy 的博客文章中所看到的,为 Java 7 选择一些小的增量语言改进的 Project Coin 练习接受了Bob Lee 的提议,允许@SuppressWarnings("varargs")在方法方面允许类似的东西在已知情况下消除此警告安全的。

This has been implemented in OpenJDK with this commit.

这已通过此提交在 OpenJDK 中实现。

This may or may not be useful to your project (many people wouldn't be happy to switch to a pre-release unstable version of the JVM!) but perhaps it is — or perhaps someone who finds this question later (after JDK7 is out) will find it useful.

这对您的项目可能有用也可能没有用(许多人不乐意切换到 JVM 的预发布不稳定版本!) ) 会发现它很有用。

回答by Konstantin Komissarchik

Explicitly casting parameters to Object in vararg method invocation will make the compiler happy without resorting to @SuppressWarnings.

在 vararg 方法调用中显式地将参数转换为 Object 将使编译器满意,而无需求助于 @SuppressWarnings。

public static <T> List<T> list( final T... items )
{
    return Arrays.asList( items );
}

// This will produce a warning.
list( "1", 2, new BigDecimal( "3.5" ) )

// This will not produce a warning.
list( (Object) "1", (Object) 2, (Object) new BigDecimal( "3.5" ) )

// This will not produce a warning either. Casting just the first parameter to 
// Object appears to be sufficient.
list( (Object) "1", 2, new BigDecimal( "3.5" ) )

I believe the issue here is that the compiler needs to figure out what concrete type of array to create. If the method is not generic, the compiler can use type information from the method. If the method is generic, it tries to figure out the array type based on parameters used at invocation. If the parameter types are homogenic, that task is easy. If they vary, the compiler tries to be too clever in my opinion and creates a union-type generic array. Then it feels compelled to warn you about it. A simpler solution would have been to create Object[] when type cannot be better narrowed down. The above solution forces just that.

我相信这里的问题是编译器需要弄清楚要创建什么具体类型的数组。如果方法不是泛型的,编译器可以使用来自方法的类型信息。如果该方法是通用的,它会尝试根据调用时使用的参数确定数组类型。如果参数类型是同质的,那么这项任务就很容易了。如果它们不同,在我看来,编译器会尝试过于聪明并创建一个联合类型的泛型数组。然后感觉有必要警告你。一个更简单的解决方案是在无法更好地缩小类型范围时创建 Object[] 。上述解决方案正是如此。

To understand this better, play around with invocations to the above list method compared to the following list2 method.

为了更好地理解这一点,与下面的 list2 方法相比,对上面的 list 方法进行调用。

public static List<Object> list2( final Object... items )
{
    return Arrays.asList( items );
}

回答by npgall

If you're after a fluent-type interface, you could try the builder pattern. Not as concise as varargs but it is type safe.

如果您追求流畅的界面,则可以尝试构建器模式。不像可变参数那么简洁,但它是类型安全的。

A static generically-typed method can eliminate some of the boilerplate when using the builder, while retaining the type safety.

静态泛型方法可以在使用构建器时消除一些样板,同时保留类型安全性。

The builder

建设者

public class ArgBuilder<T> implements Iterable<T> {

    private final List<T> args = new ArrayList<T>();

    public ArgBuilder<T> and(T arg) {
        args.add(arg);
        return this;
    }

    @Override
    public Iterator<T> iterator() {
        return args.iterator();
    }

    public static <T> ArgBuilder<T> with(T firstArgument) {
        return new ArgBuilder<T>().and(firstArgument);
    }
}

Using it

使用它

import static com.example.ArgBuilder.*;

public class VarargsTest {

    public static void main(String[] args) {
        doSomething(new ArgBuilder<String>().and("foo").and("bar").and("baz"));
        // or
        doSomething(with("foo").and("bar").and("baz"));
    }

    static void doSomething(Iterable<String> args) {
        for (String arg : args) {
            System.out.println(arg);
        }
    }
}

回答by Daniel Hári

You can add @SafeVarargsto method since Java 7, and you don't have to annotate on client code.

从 Java 7 开始,您可以将@SafeVarargs添加到方法中,并且您不必在客户端代码上进行注释。

class Assembler<X, Y> {

    @SafeVarargs
    final void assemble(X container, Y... args) {
        //has to be final...
    }
}