编译错误:在Scala中使用Java类的有界通配符问题

huangapple go评论101阅读模式
英文:

Compilation error with bounded wildcards using Java classes in Scala

问题

在Java中,我们定义了一个名为ObservableCollection.java的类,如下所示:

  1. public class ObservableCollection<T> implements Collection<T> {
  2. public SubscriptionHandle onElementAdded(Consumer<T> onAdded) {
  3. // ...
  4. }
  5. }

还有一个返回ObservableCollectionAgentService.java

  1. public interface AgentService {
  2. ObservableCollection<? extends Agent> getAgents();
  3. }

现在,我想在Scala项目中使用这个ObservableCollection.java,代码如下:

  1. def test(service: AgentService): Unit = {
  2. val onAdded: Consumer[_ <: Agent] = ???
  3. service.getAgents.onElementAdded(onAdded)
  4. }

尝试这样做会导致以下编译错误:

  1. type mismatch;
  2. found : java.util.function.Consumer[_$1] where type _$1 <: com.xxxx.xx.xx.agent.Agent
  3. required: java.util.function.Consumer[?0] where type ?0 <: com.xxxx.xx.xx.agent.Agent
  4. service.getAgents.onElementAdded(onAdded)
  5. ^
  6. one error found

这对我来说不太有意义。有没有方法可以让这个运行起来?

编辑: 使用Consumer[Agent]会导致以下错误:

  1. type mismatch;
  2. found : java.util.function.Consumer[com.xxxx.xx.xx.agent.Agent]
  3. required: java.util.function.Consumer[?0] where type ?0 <: com.kuka.cc.si.agent.Agent
  4. Note: com.xxxx.xx.xx.agent.Agent >: ?0, but Java-defined trait Consumer is invariant in type T.
  5. You may wish to investigate a wildcard type such as `_ >: ?0`. (SLS 3.2.10)
  6. service.getAgents.onElementAdded(onAdded)
  7. ^
  8. one error found
英文:

In Java, we have defined an ObservableCollection.java like this:

  1. public class ObservableCollection&lt;T&gt; implements Collection&lt;T&gt; {
  2. public SubscriptionHandle onElementAdded(Consumer&lt;T&gt; onAdded) {
  3. // ...
  4. }
  5. }

And an AgentService.java that returns an ObservableCollection:

  1. public interface AgentService {
  2. ObservableCollection&lt;? extends Agent&gt; getAgents();
  3. }

Now, I am trying to use this ObservableCollection.java in a Scala project like this:

  1. def test(service: AgentService): Unit = {
  2. val onAdded: Consumer[_ &lt;: Agent] = ???
  3. service.getAgents.onElementAdded(onAdded)
  4. }

Trying this results in the following compilation error:

  1. type mismatch;
  2. found : java.util.function.Consumer[_$1] where type _$1 &lt;: com.xxxx.xx.xx.agent.Agent
  3. required: java.util.function.Consumer[?0] where type ?0 &lt;: com.xxxx.xx.xx.agent.Agent
  4. service.getAgents.onElementAdded(onAdded)
  5. ^
  6. one error found

This does not make much sense to me. Is there a way I can get this running?

Edit: Using a Cosumer[Agent] results in the following error:

  1. type mismatch;
  2. found : java.util.function.Consumer[com.xxxx.xx.xx.agent.Agent]
  3. required: java.util.function.Consumer[?0] where type ?0 &lt;: com.kuka.cc.si.agent.Agent
  4. Note: com.xxxx.xx.xx.agent.Agent &gt;: ?0, but Java-defined trait Consumer is invariant in type T.
  5. You may wish to investigate a wildcard type such as `_ &gt;: ?0`. (SLS 3.2.10)
  6. service.getAgents.onElementAdded(onAdded)
  7. ^
  8. one error found

答案1

得分: 2

以下是翻译好的内容:

首先是关于 Scala-Java 互操作性的内容:

  1. 不在于 Scala-Java 互操作性以下 Scala 代码也无法编译
  2. import java.util.function.Consumer
  3. import java.util
  4. trait Agent
  5. trait SubscriptionHandle
  6. trait AgentService {
  7. def getAgents: ObservableCollection[_ <: Agent]
  8. }
  9. trait ObservableCollection[T] extends util.Collection[T] {
  10. def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
  11. }
  12. def test(service: AgentService): Unit = {
  13. val onAdded: Consumer[_ <: Agent] = ???
  14. val agents: ObservableCollection[_ <: Agent] = service.getAgents
  15. agents.onElementAdded(onAdded)
  16. }
  17. // 类型不匹配;
  18. // 找到:java.util.function.Consumer[_$2],其中类型 _$2 <: App.Agent
  19. // 需要:java.util.function.Consumer[_$3]

你错误地使用了存在类型(通配符泛型)。以下代码无法编译:

  1. trait X[T]
  2. trait Y[T] {
  3. def foo(x: X[T]) = ???
  4. }
  5. val x: X[_] = ???
  6. val y: Y[_] = ???
  7. y.foo(x) // 无法编译

xy 都具有存在类型,但 foo 接受类型为 X[T]x,其中 T 必须与 y 的类型中的 T 相同,即 Y[T],因此无法保证 T 相同。

修复编译错误的一种方法是为 AgentService 添加泛型:

  1. trait Agent
  2. trait SubscriptionHandle
  3. trait AgentService[T <: Agent] {
  4. def getAgents: ObservableCollection[T]
  5. }
  6. trait ObservableCollection[T] extends util.Collection[T] {
  7. def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
  8. }
  9. def test[T <: Agent](service: AgentService[T]): Unit = {
  10. val onAdded: Consumer[T] = ???
  11. val agents: ObservableCollection[T] = service.getAgents
  12. agents.onElementAdded(onAdded)
  13. }

或者将泛型添加到其方法中:

  1. trait Agent
  2. trait SubscriptionHandle
  3. trait AgentService {
  4. def getAgents[T <: Agent]: ObservableCollection[T]
  5. }
  6. trait ObservableCollection[T] extends util.Collection[T] {
  7. def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
  8. }
  9. def test[T <: Agent](service: AgentService): Unit = {
  10. val onAdded: Consumer[T] = ???
  11. val agents: ObservableCollection[T] = service.getAgents
  12. agents.onElementAdded(onAdded)
  13. }
英文:

The thing is not in Scala-Java interop. The following Scala code doesn't compile either

  1. import java.util.function.Consumer
  2. import java.util
  3. trait Agent
  4. trait SubscriptionHandle
  5. trait AgentService {
  6. def getAgents: ObservableCollection[_ &lt;: Agent]
  7. }
  8. trait ObservableCollection[T] extends util.Collection[T] {
  9. def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
  10. }
  11. def test(service: AgentService): Unit = {
  12. val onAdded: Consumer[_ &lt;: Agent] = ???
  13. val agents: ObservableCollection[_ &lt;: Agent] = service.getAgents
  14. agents.onElementAdded(onAdded)
  15. // ^^^^^^^
  16. }
  17. //type mismatch;
  18. // found : java.util.function.Consumer[_$2] where type _$2 &lt;: App.Agent
  19. // required: java.util.function.Consumer[_$3]

You misuse existential types (wildcard generics). The following code can't compile

  1. trait X[T]
  2. trait Y[T] {
  3. def foo(x: X[T]) = ???
  4. }
  5. val x: X[_] = ???
  6. val y: Y[_] = ???
  7. y.foo(x) // doesn&#39;t compile

Both x and y have existential types but foo accepts x of type X[T], where T must be the same as T in the type of y, i.e. Y[T], so you can't guarantee that T are the same.

One way to fix compilation is to add generics to AgentService

  1. trait Agent
  2. trait SubscriptionHandle
  3. trait AgentService[T &lt;: Agent] {
  4. def getAgents: ObservableCollection[T]
  5. }
  6. trait ObservableCollection[T] extends util.Collection[T] {
  7. def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
  8. }
  9. def test[T &lt;: Agent](service: AgentService[T]): Unit = {
  10. val onAdded: Consumer[T] = ???
  11. val agents: ObservableCollection[T] = service.getAgents
  12. agents.onElementAdded(onAdded)
  13. }

or to its method

  1. trait Agent
  2. trait SubscriptionHandle
  3. trait AgentService {
  4. def getAgents[T &lt;: Agent]: ObservableCollection[T]
  5. }
  6. trait ObservableCollection[T] extends util.Collection[T] {
  7. def onElementAdded(onAdded: Consumer[T]): SubscriptionHandle
  8. }
  9. def test[T &lt;: Agent](service: AgentService): Unit = {
  10. val onAdded: Consumer[T] = ???
  11. val agents: ObservableCollection[T] = service.getAgents
  12. agents.onElementAdded(onAdded)
  13. }

huangapple
  • 本文由 发表于 2020年8月24日 20:47:58
  • 转载请务必保留本文链接:https://go.coder-hub.com/63561372.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定