加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

混合Scala和Java:如何获得通用类型的构造函数参数吧?

发布时间:2020-12-16 18:50:43 所属栏目:安全 来源:网络整理
导读:我有一些遗留 Java代码,它在我的控制之外的某处定义了一个通用的有效负载变量(即我不能改变它的类型): // Java codeWrapper? extends SomeBaseType payload = ... 我在我的代码中收到了这样的有效负载值作为方法参数,并希望将其传递给Scala案例类(用作带有a
我有一些遗留 Java代码,它在我的控制之外的某处定义了一个通用的有效负载变量(即我不能改变它的类型):

// Java code
Wrapper<? extends SomeBaseType> payload = ...

我在我的代码中收到了这样的有效负载值作为方法参数,并希望将其传递给Scala案例类(用作带有actor系统的消息),但是没有得到正确的定义,这样我至少得不到编译器警告.

// still Java code
ScalaMessage msg = new ScalaMessage(payload);

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

Scala案例类定义为:

// Scala code
case class ScalaMessage[T <: SomeBaseType](payload: Wrapper[T])

如何定义案例类以使代码干净地编译? (遗憾的是,更改Java Wrapper类的代码或payload参数的类型不是一个选项)

更新以阐明有效负载参数的来源

添加为了比较,在Java中,我可以像定义有效载荷变量一样定义参数:

// Java code
void doSomethingWith(Wrapper<? extends SomeBaseType> payload) {}

并相应地调用它

// Java code
doSomethingWith(payload)

但我无法实例化,例如一个Wrapper对象直接没有得到“原始类型”警告.在这里,我需要使用静态辅助方法:

static <T> Wrapper<T> of(T value) {
   return new Wrapper<T>(value);
}

并使用此静态帮助程序来实例化Wrapper对象:

// Java code
MyDerivedType value = ... // constructed elsewhere,actual type is not known!
Wrapper<? extends SomeBaseType> payload = Wrapper.of(value);

我可以为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
}

并使用Java中的这个实例化ScalaMessage类没有问题:

// Java code
ScalaMessage msg = ScalaMessageHelper.apply(payload);

除非有人提出更优雅的解决方案,否则我会将其作为答案提取……

谢谢!

解决方法

我认为问题是在Java中如果你执行以下操作:

ScalaMessage msg = new ScalaMessage(payload);

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

您应该在实例化ScalaMessage时指定类型参数:

// (here T = MyDerivedType,where MyDerivedType must extend SomeBaseType
ScalaMessage<MyDerivedType> msg = new ScalaMessage<>(payload);

更新:看到你的评论后,我实际上在一个虚拟项目中尝试过,我实际上得到一个错误:

[error] C:CodesandboxsrcmainjavablaTest.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);

这似乎是java泛型(我们可以通过scala中的exitsentials模拟)和scala泛型之间的不匹配.您可以通过在ScalaMessage中删除type参数并使用existentials来解决此问题:

case class ScalaMessage(payload: Wrapper[_ <: SomeBaseType])

然后在java中实例化它,如下所示:

new ScalaMessage(payload)

这有效.但是,现在ScalaMessage不再是通用的,如果你想用更精确的paylods(比如Wrapper<?extends MyDerivedType>),这可能是一个问题.

要解决这个问题,让我们对ScalaMessage进行另一个小改动:

case class ScalaMessage[T<:SomeBaseType](payload: Wrapper[_ <: T])

然后在java中:

ScalaMessage<SomeBaseType> msg = new ScalaMessage<SomeBaseType>(payload);

问题解决了 :)

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读