混合Scala和Java:如何获得通用类型的构造函数参数吧?
我有一些遗留
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); 问题解决了 :) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |