Programing

“varargs 매개 변수에 대해 일반 T 배열이 만들어집니다”컴파일러 경고를 해결할 수 있습니까?

lottogame 2020. 6. 13. 10:10
반응형

“varargs 매개 변수에 대해 일반 T 배열이 만들어집니다”컴파일러 경고를 해결할 수 있습니까?


이것은 문제가되는 코드의 단순화 된 버전입니다. 하나의 제네릭 클래스는 제네릭 형식 매개 변수가있는 다른 클래스를 사용하며 제네릭 형식 중 하나를 varargs 매개 변수가있는 메서드에 전달해야합니다.

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);
    }

}

이 경고가 발생하지 않고 일반 매개 변수를 varargs 메서드에 전달하는 올바른 방법이 있습니까?

물론 같은

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

일반 배열을 만들 수 없으므로 작동하지 않습니다.


를 추가하는 것 외에는 @SuppressWarnings("unchecked")그렇게 생각하지 않습니다.

버그 보고서 는 더 많은 정보를 가지고 있지만 일반적인 유형의 배열을 좋아하지 않는 컴파일러로 요약됩니다.


Tom Hawtin은 이것을 주석으로 지적했지만보다 명확하게 설명합니다. 그렇습니다. (잠재적으로 많은 호출 사이트가 아닌) 선언 사이트 에서이 문제를 해결할 수 있습니다 .JDK7로 전환하십시오.

Joseph Darcy의 블로그 게시물 에서 볼 수 있듯이 Java 7에 대한 약간의 점진적 언어 개선을 선택하기위한 Project Coin 연습은 Bob Lee의 제안을 받아 들였습니다.@SuppressWarnings("varargs") 에 따르면 메소드 측 에서이 경고가 사라지는 상황에서 안전한.

이것은 OpenJDK에서 구현되었습니다. 이 커밋 .

이것은 프로젝트에 유용하거나 유용하지 않을 수 있습니다 (많은 사람들이 JVM의 시험판 불안정 버전으로 전환하는 것을 좋아하지 않을 것입니다!) 또는 아마도 JDK7이 끝난 후 나중에이 질문을 찾는 사람이있을 것입니다 )가 유용하다는 것을 알게 될 것입니다.


유창한 인터페이스를 사용한 경우 빌더 패턴을 사용해 볼 수 있습니다. varargs만큼 간결하지는 않지만 형식이 안전합니다.

정적 제네릭 형식의 메서드는 빌더를 사용할 때 형식 안전성을 유지하면서 보일러 플레이트의 일부를 제거 할 수 있습니다.

빌더

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);
    }
}

그것을 사용하여

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);
        }
    }
}

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.

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

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

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

class Assembler<X, Y> {

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

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) { ... }
}

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

Arrays of reference type should be avoided.

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

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


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.

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

참고URL : https://stackoverflow.com/questions/1445233/is-it-possible-to-solve-the-a-generic-array-of-t-is-created-for-a-varargs-param

반응형