2009-09-24 10 views
4

Supposons que nous ayons l'interface Java suivante:Comment étendre l'interface Java contenant des méthodes génériques dans Scala?

// Java 
public interface Foo { 
    <T> T bar(Class<T> c); 
} 

Comment dois-je l'étendre à Scala? L'écriture

// Scala 
class FooString extends Foo { 
    override def bar(c: Class[String]): String = "hello, world"; 
} 

provoquera le compilateur de lancer "FooString de classe doit être abstraite, puisque la barre de méthode Foo trait de type [T ] (classe [T]) T n'est pas défini."

Merci d'avance!

Mise à jour: La vilaine vérité est: J'ai mal compris les génériques en Java.

En tout cas, les solutions à mes malheurs sont présentées dans les réponses de Nicolas et de Walter, bien que je préfère mieux la réponse de Walter car elle est moins verbeuse.

+0

Vous l'avez enfin compris! Je suis content que vous ayez compris votre erreur sur les génériques. De rien. – Nicolas

Répondre

3

Cela fonctionne:

class FooString extends Foo { 
    def bar[String](c: Class[String]): String = "hello world".asInstanceOf[String] 
} 

val fs = new FooString 
println(fs.bar(classOf[String])) 

Modifié:

Les commentaires de @Eastsun est correcte. Puisque bar est une méthode générique avec le paramètre de type T, l'implémentation de la barre dans Scala doit aussi être une méthode générique. Je pense que la bonne façon de mettre en œuvre Foo à Scala est le suivant:

class FooString extends Foo { 
    def bar[T](c: Class[T]): T = c.newInstance.asInstanceOf[T] // c gotta have a default constructor 
} 

val fs = new FooString 
println(fs.bar(classOf[String]).getClass) // prints "class java.lang.String" 
println(fs.bar(classOf[java.util.Date]).getClass) // prints "class java.util.Date" 
+1

En fait, cela ne fonctionne pas comme prévu. La chaîne "String" dans la méthode FooString # n'est pas le type java.lang.String mais un paramètre de type "T" dans Foo. Donc, vous pouvez écrire quelque chose comme fs.bar (classOf [Int]) et compiler OK, mais exécutez avec une exception. – Eastsun

1

Vous pouvez changer comme ceci:

public interface Foo<T> { 
    T bar(Class<T> c); 
} 

class FooString extends Foo[String] { 
    override def bar(c: Class[String]): String = "hello, world"; 
} 
+1

En fait, l'interface Java est une API tierce, je dois donc l'utiliser tel quel. – shaolang

+0

Autant que je sache, il n'y a aucun moyen de remplacer une méthode générique avec une méthode de type spécial. – Eastsun

6

Il ne fonctionne pas parce que vous n'implémente l'interface correctement. La siganture de votre méthode n scala doit être:

def bar[T](c:Class[T]):T 

Vous pouvez corriger le comportement de chaîne seulement si vous voulez ton œuvre Foo.

essayer Troisièmement, selon notre discussion:

def bar[T](c:Class[T]):T = { 
    // Some stuff 
    val o:Any = myUntypedFunction(env) 
    c.cast(o) 
} 

Selon le contexte, le myUntypedFunction va créer un objet, puis vous utilisez le paramètre de classe pour lancer votre résultat et obtenir un objet T. Encore une fois: ce comportement est le même dans java et dans scala.

+0

Voilà ma question: comment faire correspondre la signature? – shaolang

+0

Vous ne pouvez pas. Vous essayez de changer l'interface, ce n'est pas une question de scala, c'est une question de programmation. l'interface dit: "Acceptez n'importe quelle classe et renvoyez une resut de cette classe", votre implémentation dit "Accepter n'importe quelle classe String et retourne une chaîne". Une implémentation de barre doit certainement utiliser cast(), newInstance ou un constructeur pour construire un T à partir de l'objet c. – Nicolas

+0

Ceci est seulement un exemple artificiel; le vrai problème auquel je suis confronté m'oblige à implémenter une interface Java qui contient un type paramétré dans la méthode, quelque chose de similaire à l'exemple que j'ai donné. S'il n'y a aucun moyen d'y parvenir, même si cela peut être un cas limite, il s'agit d'un problème de scala car il n'est pas entièrement compatible avec Java. – shaolang

Questions connexes