2013-01-23 14 views
6

私は私のコントロール(つまり、私はそのタイプを変更することはできません)の外のどこかの一般的な​​変数を定義するいくつかの従来のJavaコードがあります:私は、メソッドのパラメータとしてな​​値を受け取るスカラとJavaを混在させる:一般的に型付けされたコンストラクタパラメータを取得する方法は?

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

を私のコードでScala case class(アクターシステムでメッセージとして使用する)に渡したいのですが、少なくともコンパイラの警告が出ないように定義を正しく取得しないでください。

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

これは、コンパイラの警告 "型の安全性を:コンストラクタは...生のタイプに属している..." を与える

をScalaのcase classは次のように定義されています

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

どのように定義することができますコードがきれいにコンパイルされるようなケースクラス? 、

を比較のために加えペイロードパラメータ

の起源を明らかにするため更新(悲しい、ジャワWrapperクラスのコードまたは​​パラメータの種類を変更するオプションではありません)

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

をしてACCOそれを呼び出す:Javaで私は​​変数が定義されているとちょうど同じようにパラメータを定義することができますrdingly

// Java code 
doSomethingWith(payload) 

しかし、私は、例えばインスタンス化することはできませんWrapperオブジェクトは、「生の型」の警告を直接得ずに直接的に処理します。

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

Wrapperオブジェクトをインスタンス化するために、この静的ヘルパーを使用します:ここで、私はstaticヘルパーメソッドを使用する必要が

// 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 
} 

ScalaMessageクラスW/Oの問題インスタンス化するためのJavaからこれを使用する:

はありがとう...誰かがよりエレガントな解決策を思い付くていない限り、私は答えとしてこれを抽出します

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

を!

ScalaMessage msg = new ScalaMessage(payload); 

は、その後、あなたがその生タイプを使用してScalaMessageをインスタンス化されています

答えて

3

は、私はこの問題は、Javaで使用すると、次の操作を行う場合ということだと思います。つまり、ScalaMessageを非ジェネリック型として使用しています(Javaがジェネリックを導入したときは、ジェネリッククラスを非ジェネリッククラスとして扱いました。

ScalaMessageをインスタンス化するときには、単純に型パラメータを指定する必要があります。

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

UPDATE:あなたのコメントを見た後、私は実際にダミーのプロジェクトでそれを試みたが、私は実際にエラーが発生します。

[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); 

これは、Javaジェネリックス(スカラのexitsentialsでエミュレートできる)とスカラジェネリックスとの間に不一致があるようです。

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

してから、このようなJavaでそれをインスタンス化します:あなたは ScalaMessageで型パラメータを落とし、代わりにexistentialsを使用することによってこの問題を解決することができ

new ScalaMessage(payload) 

これは動作します。しかし、今やScalaMessageはこれ以上一般的ではありません。より洗練されたペイロッド(例:Wrapper<? extends MyDerivedType>)でそれを使用したい場合には問題になるかもしれません。この問題を解決するには

、のはScalaMessageにさらに別の小さな変更しましょう:Javaで

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

そしてを:

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

問題は、あなたが経験していることである:)

+0

私は実際に 'Wrapper <? '型のメソッドパラメータを持っているので動かないでしょう。 SomeBaseType>をJavaで拡張して、議論しているコードのブロックに渡します。私はそれに応じて元の質問を更新します。 –

+0

私は更新をしました、それを確認してください。 –

1

を解決Javaジェネリックスが実装されていないという事実。 Javaで共分散と反分散を正しく実装することはできず、ワイルドカードを使用する必要があります。あなたがWrapper[T]を提供する場合

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

することは、これは正しく動作しますし、あなたがやりたい何ScalaMessage[T]

のインスタンスを作成しますK<:TWrapper[K]からScalaMessage[T]を作成することができることです不明です。ただし、これは可能な場合のみ可能です。

Wrapper[K]<:Wrapper[T] for K<:T 

これはまさに分散の定義です。 Javaのジェネリックは不変であるため、操作は違法です。あなたが持っている唯一の解決策は、しかし、ラッパーはすべてがスムーズかつエレガントにコンパイルします:)

を型分散に

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) 
} 

を使用してScalaで正しく実装された場合は、コンストラクタ

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

の署名を変更することです

+0

+1 Java/Scala型システムの詳細な説明 –

関連する問題