简体   繁体   English

Java泛型编译错误-方法method(Class <capture#1-of ? extends Interface> ) <type> 不适用于参数

[英]Java generics compilation error - The method method(Class<capture#1-of ? extends Interface>) in the type <type> is not applicable for the arguments

Last Thursday someone at work showed me a compile error that I wasn't able to fix in a clean way and it has been bothering me ever since. 上周四,有人在工作给我看了一个编译错误,我无法以一种干净的方式解决它,此后一直困扰着我。

The problem is generics related and I've reconstructed a simplified version of the code that generates the compile error. 问题是与泛型有关,我重构了生成编译错误的简化代码。 The error occurs in the very last line of code shown below. 该错误发生在下面显示的最后一行代码中。

I've been looking all over the interwebs but can't seem to find a decent explanation why the Java compiler doesn't accept the code. 我一直在遍及整个Interweb,但是似乎找不到关于Java编译器不接受代码的正当解释。 I guess that if it were to allow the code, it would be possible the create a class cast issue in Bar.operationOnBar(), but I don't see how. 我猜想如果允许代码,有可能在Bar.operationOnBar()中创建一个类强制转换问题,但我不知道如何。

Could someone please enlighten me why this doesn't compile? 有人可以启发我为什么不编译吗?

public interface Interface {
}


public class Type implements Interface {
}

public class Bar<T> {
    public Bar(Class<T> clazz) {
    }

    public void operationOnBar(Class<T> arg){
    }
}

public class Foo {
    public <T> Bar<T> bar(Class<T> clazz){
        return new Bar<T>(clazz);
    }
    public static void main(String[] args) {
        Class<? extends Interface> extendsInterfaceClazz = Type.class;
        new Foo().bar(extendsInterfaceClazz).operationOnBar(Type.class);
    }
}

Compile Error on the second line of Foo.main(): Foo.main()第二行的编译错误:

The method operationOnBar(Class<capture#1-of ? extends Interface>) in the type Bar<capture#1-of ? extends Interface> is not applicable for the arguments (Class<Type>)

Btw. 顺便说一句。 I've solved it by downcasting Type.class to Class, this way the compiler is unable to see that the generic type of Class is "Type" instead of "? extends Interface". 我已经通过将Type.class下放到Class中来解决它,这样编译器无法看到Class的通用类型是“ Type”而不是“?extended Interface”。

A little advice: when you are not sure why compiler prohibits some generic-related conversion, replace generic classes in question with List<T> . 一些建议:当不确定为什么编译器禁止某些与通用相关的转换时,请使用List<T>替换相关的通用类。 Then it would be easy to find an example that breaks type safety. 然后,很容易找到破坏类型安全性的示例。

This replacement is correct since currently Java doesn't provide a way to conduct any a priory knowledge about possible behaviours of generic classes (ie it lacks a way to specify covariance and contravariance of generic classes in their declarations, as in C# 4 and Scala). 这种替换是正确的,因为当前Java没有提供一种方法来进行有关泛型类可能行为的先验知识(即,它缺乏一种在其声明中指定泛型类的协方差和相反性的方法,例如C#4和Scala)。 。 Therefore Class<T> and List<T> are equivalent for the compiler with respect to their possible behaviours, and compiler has to prohibit conversions that can cause problems with List<T> for other generic classes as well. 因此, Class<T>List<T>就其可能的行为而言,对于编译器是等效的,并且编译器必须禁止对其他通用类也可能导致List<T>问题的转换。

In your case: 在您的情况下:

public class Bar<T> {
    private List<T> l;

    public Bar(List<T> l) {
        this.l = l;
    }

    public void operationOnBar(List<T> arg) {
        l.addAll(arg);
    }
}

List<Type1> l1 = new ArrayList<Type1>();
List<? extends Interface> l2 = l1;
List<Type2> l3 = Arrays.asList(new Type2());

new Foo().bar(l2).operationOnBar(l3);

Type1 t = l1.get(0); // Oops!

您也可以将方法operationOnBar的签名更改为:

public void operationOnBar(Class<? extends Interface> arg){

You would agree that this shouldn't compile: 您将同意不应编译:

 1   Class<? extends Interface> clazz = AnotherType.class;
 2   new Foo().bar(clazz).operationOnBar(Type.class);

The problem is javac is a little dumb; 问题是javac有点愚蠢。 when compiling line#2, all it knows about variable clazz is its declared type; 在编译第2行时,它对变量clazz所了解的只是其声明的类型。 it forgets the concrete type it was assigned to. 它忘记了分配给它的具体类型。 So what is assigned to clazz at line#1 doesn't matter, compiler must reject line#2. 因此,在第1行分配给clazz内容无关紧要,编译器必须拒绝第2行。

We can imagine a smarter compiler that can track the concrete types, then your code can be compiled, as it is obviously safe and correct. 我们可以想象一个更聪明的编译器可以跟踪具体类型,然后可以编译您的代码,因为它显然是安全且正确的。

Since that's not the case, sometimes programmers know more about types than the compiler, it is necessary that programmers do casts to convince the compiler. 由于不是这种情况,所以有时程序员比编译器更了解类型,所以有必要让程序员进行强制转换以说服编译器。

The general way to deal with these sorts of problems is to introduce a generic argument for the repeated type, which generally means introducing a new generic method (a class would do as well, but isn't necessary). 处理此类问题的一般方法是为重复类型引入通用参数,这通常意味着引入新的通用方法(一个类也可以,但不是必需的)。

public static void main(String[] args) {
    fn(Type.class);
}
private static <T extends Interface> void fn(Class<T> extendsInterfaceClazz) {
    new Foo().bar(extendsInterfaceClazz).operationOnBar(extendsInterfaceClazz);
}

Not really related to the question, but I would suggest using reflection sparingly. 并非与问题真正相关,但我建议您谨慎使用反射。 It is very, very rarely a good solution. 这是一个非常非常好的解决方案。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 java generics - Comparable 类型中的方法 compareTo(capture#1-of?)<capture#1-of ?> 不适用于 arguments</capture#1-of> - java generics - The method compareTo(capture#1-of ?) in the type Comparable<capture#1-of ?> is not applicable for the arguments 类型Map <String中的方法,捕获#1-of? extends Object>不适用 - Method in the type Map<String,capture#1-of ? extends Object> is not applicable Java泛型:Comparable类型的compareTo(capture#2-of?扩展E)方法不适用于自变量(Comparable) - Java Generics :The method compareTo(capture#2-of ? extends E) in the type Comparable is not applicable for the arguments (Comparable) 泛型-类型中的方法不适用于参数 - Generics - The method in the type is not applicable for the arguments Java泛型编译错误“类 - Java generics compile error “Class<capture#1-of ? …” Java泛型-类型T中的方法validate(T,T)不适用于自变量(可比较,可比较 <capture#11-of ?> ) - java generics - The method evaluate(T,T) in the type T is not applicable for the arguments (Comparable, Comparable<capture#11-of ?>) 验证器类型中的方法validate(capture#2-of?extended Object) <capture#2-of ? extends Object> 不适用于参数(字符串) - The method validate(capture#2-of ? extends Object) in the type Validator<capture#2-of ? extends Object> is not applicable for the arguments (String) 方法不适用于Java中有关泛型或类型擦除的参数 - Method not applicable for arguments regarding generics or type erasure in Java 方法映射((<no type> cfg) -&gt; {}) 对于 List 类型是未定义的<capture#1-of ? extends Config> - The method map((<no type> cfg) -> {}) is undefined for the type List<capture#1-of ? extends Config> 类型中的方法不适用于参数 java - the method in the type is not applicable for the arguments java
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM