2010-06-22 22 views
9

tengo 2 métodos sencillos en una clase de biblioteca de Scala:cómo declarar método Scala de modo que pueda ser llamado desde Java utilizando el estilo varargs

class Foo { 
    def bar(args : String*) : Unit = println("Foo.bar with: " + args) 
    def bar(args : Array[String]) : Unit = bar(args.toSeq : _*) 
} 

Todo esto compila muy bien. Entonces puse esto en una biblioteca foo.jar y tratar de compilar el siguiente trozo de Java:

import Foo 
public class Test { 

    public static void main(String[] args) { 
     Foo foo = new Foo(); 
     foo.bar("Hello", "World"); //DOES NOT COMPILE 
    } 
} 

puedo reemplazar la línea en cuestión con:

foo.bar(new String[] { "Hello", "World" }); //OK 

Pero esto parece derrotar el punto. ¿Cómo puedo llamarlo desde Java usando la sintaxis similar a Java varargs?

+0

podría ser un error tipográfico, pero foo' clase '' no tiene método foo'. –

+0

Cheers - typo de hecho –

+0

Estoy obviamente equivocado en lo que dije, aunque confieso que me confunde. Estoy borrando mi respuesta para evitar difundir información errónea. –

Respuesta

3

En 2,8 (dunno alrededor de 2,7), si reemplaza un método varargs de un padre de Java, o implementar un método varargs de una interfaz Java, el compilador Scala generará dos métodos , uno para Scala, uno para Java. El de Java, como puede ver por sí mismo inspeccionando el bytecode, simplemente toma el conjunto de varius y lo envuelve, luego pasa el WrappedArray a la versión de Scala que espera un Seq.

Si hay una manera de obligar al compilador a generar el reenviador en otras circunstancias, no sé. Dudo que exista Parece una manera de pedirlo (una anotación, supongo) sería una solicitud de mejora razonable.

1

No muy cierto, pero creo que los varargs en Scala usan Secuencias y son diferentes de la implementación de java. Creo que la forma más fácil de lograr lo que se desea es una subclase de la clase Scala Foo en Java y añadir un método de barras que toma un Java vararg es decir

public class JavaFoo extends Foo { 
    public void bar(String... args) { 
     super.bar(args) 
    } 
} 

El método vararg JavaFoo entonces puede ser llamado usando la sintaxis vararg en Java .

espero que ayude :)

+1

Hmmm ... intenté con la sugerencia de Daniel, pero no pude lograr que funcionara con Scala 2.8 beta. ¿La compilación de un vararg java y un scala vararg es algo que acaba de ser agregado recientemente? Descompilar el bytecode solo produce una clase Foo con un método de barra vacía pública (Seq args) ... –

0

A pesar de la sugerencia útil sobre el uso de interfaz de Java para forzar al compilador de Scala a ser "compatible", simplemente no pude hacer que mi código funcionara. Finalmente caí en la cuenta de que los métodos se declararon en un objeto de Scala, lo que significa que son estáticos y no se pueden especificar métodos estáticos en una interfaz, por lo que el compilador simplemente ignoraba el hecho de que el objeto implementaba la interfaz . Afortunadamente para mí, hay una solución alternativa. En lugar de llamar al método estático directamente desde Java como esto:

CLASS.method(x,y,z) 

Tienes que llamar así:

CLASS$.MODULE$.method(x,y,z) 

Esto significa que son, de hecho, el acceso a la objeto singleton como una instancia que se refiere por un campo estático, y dado que es una instancia, e implementa la interfaz java, allí el compilador hace su trabajo correctamente e implementa el método varargs para que Java pueda llamarlo como varargs.

Personalmente creo que esto debería considerarse como un error del compilador Scala.

1

Véase el answer to this question:

se puede utilizar el @annotation.varargs para instruir a Scala para generar ambos métodos:

class Foo { 
    @annotation.varargs def bar(args : String*) : Unit = println("Foo.bar with: " + args) 
    def bar(args : Array[String]) : Unit = bar(args.toSeq : _*) 
} 
Cuestiones relacionadas