使用泛型的代码不会编译

时间:2015-03-27 17:57:10

标签: java generics

我没有谷歌这个问题。为什么这一行会产生编译错误。

wrapper.doSmth(wrapper.getCurrent());

我正在使用java 7。

public class App {
 Wrapper<?> wrapper;

 class Generic<T>{

 }

 class Wrapper<T>{
  Generic<T> current;

  public void doSmth(Generic<T> generic){
  }

  public Generic<T> getCurrent(){
   return current;
  }
 }

 public void operation(){
  wrapper.doSmth(wrapper.getCurrent());
 }
}

错误是:

Error:(25, 24) java: method doSmth in class App.Wrapper<T> cannot be applied to given types;
  required: App.Generic<capture#1 of ?>
  found: App.Generic<capture#2 of ?>
  reason: actual argument App.Generic<capture#2 of ?> cannot be converted to conf.App.Generic<capture#1 of ?> by method invocation conversion

2 个答案:

答案 0 :(得分:8)

编译错误应该是&#34;捕获? #1与捕获不兼容? #2&#34 ;.导致此错误的原因是wrapperWrapper<?>

编译器发现wrapper.getCurrent()返回Generic<?>,而wrapper.doSmthGeneric<?>作为参数。但它不会将两个?通配符等同起来,即使我们可以看到它们来自同一个实例并且应该是相同的。

这里的一个解决方案是使App类具有通用性,因此您可以替换通配符。

public class App<T> {

由于GenericWrapper是内部类,T仍然在范围内,因此您不需要为它们声明泛型类型参数更多。

    Wrapper wrapper;

    class Generic{

    }

    class Wrapper{
        Generic current;

        public void doSmth(Generic generic){
        }

        public Generic getCurrent(){
            return current;
        }
    }

    public void operation(){
        wrapper.doSmth(wrapper.getCurrent());
    }
}

答案 1 :(得分:1)

可能是capturing helper的作业。

public void operation() {
    operationImpl(wrapper);
}

private static <T> void operationImpl(Wrapper<T> wrapper) {
    wrapper.doSmth(wrapper.getCurrent());
}

无需其他更改。帮助程序捕获wrapper的类型,因此我们可以确保getCurrent返回与doSmth接受的类型相同的类型。


发生此错误的原因是,每次引用带有通配符的类型时,都会为表达式中的特定点假定一个不同的类型(称为&#39; capture&#39;):

    Wrapper<?> wrapper = ...;

//  each capture for T is assumed distinct from each other
//  vvvvvvv        vvvvvvv
    wrapper.doSmth(wrapper.getCurrent());

引用指向同一实例的事实与指定捕获的方式无关。编译器不需要考虑到这一点,这样的事情也可能发生

Wrapper<?> wrapper = new Wrapper<String>();
wrapper.doSmth((wrapper = new Wrapper<Float>()).getCurrent());

T可以改变中间表达式。