【问题标题】:Java generics code cannot compileJava 泛型代码无法编译
【发布时间】:2018-01-12 15:41:08
【问题描述】:

下面的代码给我编译带来了麻烦。

给我这个错误

Error:(20, 22) java: incompatible types: com.company.Main.Impl cannot be converted to T

我只需要那个接口在这个函数中工作,我不想对函数体做太多改动。

为什么这不起作用? 和 我怎样才能做到这一点?

    package com.company;

public class Main {

    class Impl implements someinterface, anotherinterface{

        @Override
        public Integer getInteger() {
            return 0;
        }
    }

    class BigObject{
        public Impl get(){
            return new Impl();
        }
    }

    private <T extends someinterface & anotherinterface> Integer myfunc(BigObject bg){

        T xy = bg.get(); // this line will not compile????
        if (xy.isOK()) // from someinterface 
           return xy.getInteger(); // from anotherinterface
        return null;
    }


    public static void main(String[] args) {
    // write your code here
    }
}

【问题讨论】:

  • 为什么你首先需要泛型参数?从表面上看,someinterface(应该写成CamelCase)只包含getInteger()这个方法。您可以将T 替换为someinterface
  • T 是实现someinterfacesomething;它不一定是Impl。只需改用someinterface xy = ...
  • 这里的泛型是荒谬的。删除泛型声明并将T xy = bg.get(); 替换为someinterface xy = bg.get(); 然后调试。
  • @user40129 然后创建一个newinterface extends someinterface, anotherinterface 并将T 替换为newinterface
  • @user40129 又是一个问题:为什么需要泛型?为什么不将T 替换为Impl

标签: java


【解决方案1】:

它不会编译,因为在 Java 中,泛型是不变的see related post

使用以下代码行:

<T extends SomeInterface> Integer myfunc(BigObject bg) { ... }

你是说T 是某种SomeInterface,或者更准确地说,是SomeInterface 的子类型。编译器抱怨T xy = bg.get(),因为bg.get() 返回T 的某个子类型,但该类型可能与Impl 相同也可能不同。

打个比方,你是这样说的:

class Cat extends Animal { }
class AnimalObj {
    public Cat get() {
        return new Cat();
    }
}

private <T extends Animal> Integer myfunc(AnimalObj bg) {
    T xy = bg.get();
    ...
}

T 可以是Cat,但也可以是Dog。谁知道。所以这就是编译器抱怨的原因。

如果你不关心子类型,你应该放弃泛型,改为这样写:

private Integer myfunc(AnimalObj bg) {
    Animal xy = bg.get();
    ...
}

由于myFunc 接受BigObject,它能够提供具体的Impl,您只需将&lt;T extends someinterface &amp; anotherinterface&gt; 替换为Impl


阅读全文

【讨论】:

  • 是的,它也可以是一只狗,这有关系吗? myfunc 只关心任何类型的Animal。对吗?
  • 不,不完全是。不是“任何类型的Animal”(那么我们就可以写成Animal xy = ...),而只是“一个特定但未知的类型,它是Animal 的子类”。它们不一样。
  • 对,但是如果 bg.get() 没有这些接口,编译器应该会抱怨,为什么编译器要检查的不止这些?
  • @user40129 根据这个逻辑,Dog d = new Cat() 是可能的,如果它们都实现了Strokeable。两个类实现相同的接口这一事实并不意味着它们可以互换。
  • @MCEmperor,如果 ,T d canott 是一个新的 Cat()?
【解决方案2】:

让我们稍微改变一下myfunc,让它返回泛型类型T

private static <T extends someinterface & anotherinterface> T myfunc(BigObject bg){
    return bg.get();
}

现在你可以这样称呼它:

Impl i1 = myfunc( new BigObject() );

像这样:

Impl2 i2 = myfunc( new BigObject() );

但如果BigObject.get 只返回Impl,那么第二次调用就会出现预期Impl2 的错误。

【讨论】:

  • 这不会编译。并在 bg.get() 处给出错误
  • 是的,它不会因为bg.get() 只返回Impl。我给出的例子表明,myfunc 有签名,bg.get() 函数不能只返回Impl。编译器无法确保 myfunc 的调用者不会为 T 指定 Impl2
  • 一个合理的编译器会让你编译函数,但不会编译函数调用。因为它不知道返回的泛型类型是否可以转换为 Impl/Impl2,但如果 il 是类型 (而不是 Impl/Impl2),则函数调用应该编译,因为没有歧义。
  • 是的,这就是为什么正如其他人建议的那样,您需要将bg.get() 更改为public &lt;T extends someinterface &amp; anotherinterface&gt; T get()。这样编译器可以确定bg.get() 将处理ImplImpl2
  • 不要认为这是他们的建议,因为 BigObject 上的 public T get() 不会编译。
猜你喜欢
  • 1970-01-01
  • 2012-12-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-11-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多