2012-07-30 16 views
7

Ich möchte eine Java-Methode implementieren, die Generics in Scala (2.9.2) verwendet. Aber ich versagt ...Scala, kann generische Java-Methode nicht implementieren

Java Interface-Methode:

public <T extends Number> void setAttribute(Key<T> key, Number value); 

Scala Code, der diese Methode implementieren möchten:

def setAttribute[T <: Number](key: Key[T], value: Number) = { 
    setAttributeLocal(key, value) } 

private def setAttributeLocal[T](key: Key[T], value: T) = { 
    val stringValue = ConvertUtils.convert(value, classOf[String]).asInstanceOf[String] 
    session = session + (key.getValue() -> stringValue) 
} 

Key wie folgt aussieht:

public class Key<T> 

Aber das kompiliert nicht.

[error] found : mypackage.Key[T] 
[error] required: mypackage.Key[java.lang.Number] 
[error] Note: T <: java.lang.Number, but Java-defined class Key is invariant in type T. 
[error] You may wish to investigate a wildcard type such as `_ <: java.lang.Number`. (SLS 3.2.10) 
[error]  setAttributeLocal(key, value) 

Ich kann nicht herausfinden, was das Problem ist. Irgendwelche Vorschläge/Idee?

greez GarfieldKlon

+1

Wir müssen wissen, wie 'Key' aussieht. Denn wenn ich 'public interface Key ' verwende, kompiliert der obige Code gut. –

+0

@GarfieldKlon Mit welcher Version von scala arbeiten Sie? –

+0

@ 0__ unter welcher Version kompiliert es? –

Antwort

4

Es erscheint der Compiler mit Ihrem Anruf setAttributeLocal unglücklich ist. setAttributeLocal erfordert eine Key[Number], aber Sie bieten eine Key[_ <: T]. In Java-Land bedeutet das, dass Sie versuchen, eine Key<? extends Number> als Key<Number> zu übergeben.

Der Vorschlag ist setAttributeLocal zu akzeptieren Key<? extends Number> oder Key[_ <: Number], je nachdem, ob es Java-oder Scala-definiert ist.

+0

@GarfieldKlon Ich musste das ein paar Mal lesen ... Ich denke, was Ben vorschlägt, ist, dass wenn du dich darauf konzentrierst, 'setAttribute' zu ​​fixieren, dann schaust du vielleicht auf die falsche Sache. Der von Ihnen beschriebene Fehler ist ein Typproblem mit 'setLocalAttribute', nicht' setAttribute'. Wie sieht Ihre Definition von 'setLocalAttribute' aus? –

+0

@Richard - in Ordnung, das erklärt, warum ich das nicht reproduzieren konnte –

+0

Wir haben schließlich diese Lösung hinzugefügt: 'private def setAttributeLocal [T] (Schlüssel: Key [T], Wert: Object)' – GarfieldKlon

1

Etwas sieht hier ein bisschen aus.

Haben Sie versucht:

def setAttribute[T <: Number](key: Key[T], value: T) = 
    setAttributeLocal(key, value) 

Es ist seltsam/schlecht scheint die Art T für den Schlüssel zu erhalten, aber es ist nicht auf den Wert zu verwenden. Meine Vermutung ist, dass Sie hier einen invarianten Fehler erhalten. Sie versuchen, den Wert des Typs Number zu einem Schlüssel des Typs T zuzuweisen, und der Compiler ist nicht sicher, ob es nicht Number für T übergeben kann (während es weiß, dass T für Number übergeben werden kann).

Können wir mehr Code sehen?

+0

Das ist keine Option, weil es ist kein Override. – GarfieldKlon

+0

Es gibt Einschränkungen in den Typschnittstellen von Java und Scala. Was Sie in Java tun, ist ein unzuverlässiger Typ, und Scala lässt das nicht zu. Wenn Sie diese Art-Zauberei weiter verwenden möchten, müssen Sie sich an das Typsystem von Java halten, tut mir leid. – jsuereth

1

Wie @jsuereth bereits darauf hingewiesen, gibt es eine Diskrepanz zwischen den Unterschriften von setAttribute und setAttributeLocal ist, nämlich, dass die ehemalige eine akzeptiert Key[T <: Number] sondern legt den Wert, der genau mit dem Schlüssel ein Number geht sein, während die letztere flexibler und erlaubt Schlüssel und Wert zu sein T <: Number. Das sieht eher komisch aus und Sie sollten diese Entscheidung vielleicht noch einmal überdenken. Es führt auch zu dem von @Ben Schulz erklärten Problem.

In jedem Fall ist der Compiler (2.9.1) ist zufrieden mit dem folgenden Setup:

MyI.java:

public interface MyI { 
    public <T extends Number> void setAttribute(Key<T> key, Number value); 
} 

Key.java:

public interface Key<T> { 
} 

Test.scala:

object Test extends App { 
    def setAttribute[T <: Number](key: Key[T], value: Number) = { 
    setAttributeLocal(key, value) } 

    private def setAttributeLocal[T](key: Key[T], value: Number) = { 
    /* Notice that value is now also of type Number. */ 
    } 
} 
Verwandte Themen