Eri*_*ner 6 java generics types scala scala-java-interop
我有一些遗留Java代码,它在我的控制之外的某处定义了一个泛型payload变量(即我不能改变它的类型):
// Java code
Wrapper<? extends SomeBaseType> payload = ...
Run Code Online (Sandbox Code Playgroud)
我在我的代码中收到了一个payload像方法参数这样的值,并希望将它传递给Scala case class (用作带有actor系统的消息),但是没有得到正确的定义,这样我至少得不到编译器警告.
// still Java code
ScalaMessage msg = new ScalaMessage(payload);
Run Code Online (Sandbox Code Playgroud)
这给出了编译器警告"类型安全:构造函数...属于原始类型......"
Scala case class定义为:
// Scala code
case class ScalaMessage[T <: SomeBaseType](payload: Wrapper[T])
Run Code Online (Sandbox Code Playgroud)
如何定义案例类以使代码干净地编译?(遗憾的是,更改Java Wrapper类的代码或payload参数的类型不是一个选项)
更新以阐明有效负载参数的来源
添加为了比较,在Java中,我可以像定义payload变量一样定义参数:
// Java code
void doSomethingWith(Wrapper<? extends SomeBaseType> payload) {}
Run Code Online (Sandbox Code Playgroud)
并相应地调用它
// Java code
doSomethingWith(payload)
Run Code Online (Sandbox Code Playgroud)
但我不能直接实例化一个Wrapper对象而不会得到"原始类型"警告.在这里,我需要使用static辅助方法:
static <T> Wrapper<T> of(T value) {
return new Wrapper<T>(value);
}
Run Code Online (Sandbox Code Playgroud)
并使用此静态助手实例化Wrapper对象:
// Java code
MyDerivedType value = ... // constructed elsewhere, actual type is not known!
Wrapper<? extends SomeBaseType> payload = Wrapper.of(value);
Run Code Online (Sandbox Code Playgroud)
解
我可以为Scala伴侣对象添加一个类似的辅助方法:
// Scala code
object ScalaMessageHelper {
def apply[T <: SomeBaseType](payload: Wrapper[T]) =
new ScalaMessage(payload)
}
object ScalaMessageHelper2 {
def apply[T <: SomeBaseType](payload: Wrapper[T]) =
ScalaMessage(payload) // uses implicit apply() method of case class
}
Run Code Online (Sandbox Code Playgroud)
并使用Java中的这个实例化没有ScalaMessage问题的类:
// Java code
ScalaMessage msg = ScalaMessageHelper.apply(payload);
Run Code Online (Sandbox Code Playgroud)
除非有人提出更优雅的解决方案,否则我会将其作为答案提取......
谢谢!
我认为问题是在Java中如果你执行以下操作:
ScalaMessage msg = new ScalaMessage(payload);
Run Code Online (Sandbox Code Playgroud)
然后您将ScalaMessage使用其原始类型进行实例化。或者换句话说,您将其用作ScalaMessage非泛型类型(当 Java 引入泛型时,他们保留了将泛型类视为非泛型类的能力,主要是为了向后兼容)。
您应该在实例化时简单地指定类型参数ScalaMessage:
// (here T = MyDerivedType, where MyDerivedType must extend SomeBaseType
ScalaMessage<MyDerivedType> msg = new ScalaMessage<>(payload);
Run Code Online (Sandbox Code Playgroud)
更新:看到您的评论后,我实际上在一个虚拟项目中尝试了它,并且实际上收到了一个错误:
[error] C:\Code\sandbox\src\main\java\bla\Test.java:8: cannot find symbol
[error] symbol : constructor ScalaMessage(bla.Wrapper<capture#64 of ? extends bla.SomeBaseType>)
[error] location: class test.ScalaMessage<bla.SomeBaseType>
[error] ScalaMessage<SomeBaseType> msg = new ScalaMessage<SomeBaseType>(payload);
Run Code Online (Sandbox Code Playgroud)
java 泛型(我们可以通过 scala 中的 exitsentials 来模拟)和 scala 泛型之间似乎不匹配。您可以通过删除类型参数ScalaMessage并使用存在来解决此问题:
case class ScalaMessage(payload: Wrapper[_ <: SomeBaseType])
Run Code Online (Sandbox Code Playgroud)
然后在java中实例化它,如下所示:
new ScalaMessage(payload)
Run Code Online (Sandbox Code Playgroud)
这有效。然而, nowScalaMessage不再是通用的,如果您想将它与更精致的 Paylod 一起使用(例如 a ),这可能会成为问题Wrapper<? extends MyDerivedType>。
为了解决这个问题,让我们再做一个小改动ScalaMessage:
case class ScalaMessage[T<:SomeBaseType](payload: Wrapper[_ <: T])
Run Code Online (Sandbox Code Playgroud)
然后在java中:
ScalaMessage<SomeBaseType> msg = new ScalaMessage<SomeBaseType>(payload);
Run Code Online (Sandbox Code Playgroud)
问题解决了 :)
| 归档时间: |
|
| 查看次数: |
1493 次 |
| 最近记录: |