Scala和Java的混合:如何正确获取泛型构造函数参数?

Scala和Java的混合:如何正确获取泛型构造函数参数?,java,scala,generics,types,scala-java-interop,Java,Scala,Generics,Types,Scala Java Interop,我有一些遗留Java代码,它在我无法控制的地方定义了一个通用的有效负载变量(即,我无法更改其类型): 这会给出编译器警告“类型安全:构造函数…属于原始类型…” Scala案例类定义为: // Scala code case class ScalaMessage[T <: SomeBaseType](payload: Wrapper[T]) 并相应地称之为 // Java code doSomethingWith(payload) 但是我不能直接实例化包装器对象而不得到“raw typ

我有一些遗留Java代码,它在我无法控制的地方定义了一个通用的
有效负载
变量(即,我无法更改其类型):

这会给出编译器警告“类型安全:构造函数…属于原始类型…”

Scala
案例类定义为:

// Scala code
case class ScalaMessage[T <: SomeBaseType](payload: Wrapper[T]) 
并相应地称之为

// Java code
doSomethingWith(payload)
但是我不能直接实例化包装器对象而不得到“raw type”警告。在这里,我需要使用
静态
辅助方法:

static <T> Wrapper<T> of(T value) {
   return new Wrapper<T>(value);
}
解决方案

我可以向Scala companion对象添加类似的帮助器方法:

// 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
}
除非有人想出一个更优雅的解决方案,否则我将把它作为一个答案


谢谢大家!

我认为问题在于,在Java中,如果您执行以下操作:

ScalaMessage msg = new ScalaMessage(payload);
然后使用原始类型实例化
ScalaMessage
。或者换句话说,您使用
ScalaMessage
作为非泛型类型(当Java引入泛型时,它们保持将泛型类视为非泛型类的能力,主要是为了向后兼容)

实例化
ScalaMessage
时,只需指定类型参数即可:

// (here T = MyDerivedType, where MyDerivedType must extend SomeBaseType
ScalaMessage<MyDerivedType> msg = new ScalaMessage<>(payload);
case class ScalaMessage[T<:SomeBaseType](payload: Wrapper[_ <: T]) 
然后用java将其实例化如下:

new ScalaMessage(payload)

这很有效。然而,现在
ScalaMessage
不再是泛型的,如果您想将其用于更精细的薪资(比如
Wrapper),这可能是一个问题。您遇到的事实是Java泛型实现得很差。您无法在Java中正确实现协方差和逆变,您必须使用通配符

case class ScalaMessage[T <: SomeBaseType](payload: Wrapper[T]) 
这正是方差的定义。因为Java中的泛型是不变的,所以该操作是非法的。唯一的解决方案是更改构造函数的签名

class ScalaMessage[T](wrapper:Wrapper[_<:T])

classscalamessage[T](wrapper:wrapper[\u)不起作用,因为我实际上有一个
wrapper+1类型的方法参数来详细解释Java/Scala类型的系统
// (here T = MyDerivedType, where MyDerivedType must extend SomeBaseType
ScalaMessage<MyDerivedType> msg = new ScalaMessage<>(payload);
[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);
case class ScalaMessage(payload: Wrapper[_ <: SomeBaseType]) 
new ScalaMessage(payload)
case class ScalaMessage[T<:SomeBaseType](payload: Wrapper[_ <: T]) 
ScalaMessage<SomeBaseType> msg = new ScalaMessage<SomeBaseType>(payload);
case class ScalaMessage[T <: SomeBaseType](payload: Wrapper[T]) 
Wrapper[K]<:Wrapper[T] for K<:T
class ScalaMessage[T](wrapper:Wrapper[_<:T])
class Wrapper[+T]
class ScalaMessage[+T](wrapper:Wrapper[T])

object ScalaMessage {
  class A
  class B extends A

  val myVal:Wrapper[_<:A] = new Wrapper[B]()

  val message:ScalaMessage[A] = new ScalaMessage[A](myVal)
}