2010-07-19 17 views
21

Estoy tratando de insertar algún código Scala en mi aplicación Java existente. (Entonces, dicho esto, quiero un poco más de diversión).¿Cómo se llama a un método singleton de Scala desde Java?

creo un producto único en materia Scala

ScalaPower.scala 

    package org.fun 
    class ScalaPower 
    object ScalaPower{ 
     def showMyPower(time:Int) = { 
     (0 to time-1).mkString(", ") 
     } 
    } 

Ahora, en el interior OldJava.java

class OldJava { 
    public void demo(){ 
    System.out.println(?) 
    } 
} 

¿Qué debo rellenar ? de manera que Java llamará al método showMyPower? Intenté ambos org.fun.ScalaPower.showMyPower(10) y org.fun.ScalaPower.getInstance().showMyPower(10) pero ninguno funciona.

(descompilar el archivo de clase utilizando Jad mostrarme nada más que código sin sentido.)

Editar que retire la declaración class ScalaPower y Scala producen el método estático como se esperaba. (llame al org.fun.ScalaPower.showMyPower(10) solo funciona).

pregunto si es un error en el compilador Scala o no

+1

¿Qué hay de 'org.fun.ScalaPower.showMyPower (10)'? – OscarRyz

+0

Ay, mi mal. Olvidé cambiar el espacio de nombres. Actualizado la pregunta ya. Gracias. –

+1

Por cierto, puede escribir '0 until time' en lugar de' 0 to time-1'. –

Respuesta

9

Creo que esto cubre indirectamente:

Companion Objetos y Java estáticas Métodos

hay una cosa más que saber sobre objetos de compañía. Siempre que defina como método principal para usar como entrada punto para una aplicación, Scala requiere que lo ponga en un objeto. Sin embargo, al momento de escribir esto, los métodos principales no se pueden definir en un objeto complementario . Debido a detalles de implementación en el código generado , la JVM no encontrará el método principal . Este problema puede ser resuelto en una versión futura. Por ahora, debe definir cualquier método principal en un objeto singleton (es decir, un objeto "no complementario" ) [ScalaTips]. Considere el siguiente ejemplo de un objeto simple Persona clase y compañero que intenta definir main.

como se encuentra aquí: http://programming-scala.labs.oreilly.com/ch06.html

En pocas palabras, porque su objeto es un objeto acompañante (tiene una clase de compañía) que no se puede llamar como se esperaba. Como descubriste si te deshaces de la clase, funcionará.

+2

Esto ya no es cierto. En algún lugar entre cuando eso fue escrito y cuando Scala 2.8 fue lanzado, los patrones de generación de código de reenvío se arreglaron para permitir los métodos principales en los compañeros. –

+0

Oooh, excelente. El libro insinuaba que deseaban que se cambiara, pero no decía para 2.8 (y tenían muchas ganas de llegar a 2.8-ness). Dicho esto, el autor de la pregunta original no da su versión, y de su "Editar elimino la declaración ScalaPower de la clase y Scala produce el método estático como se esperaba". todavía parece que ese podría haber sido el problema. –

+0

Gracias. Eso explica mi situación. Estoy cambiando a Scala 2.8 en este momento. Demonios, el plugin eclipse scala todavía apesta. –

3

Tenga en cuenta que la herramienta stock javap se puede utilizar para ver lo que produce el compilador Scala. No responde directamente a su pregunta, por supuesto, pero cuando lo que necesita es que le recuerden los patrones de generación de código, es suficiente.

+0

Gracias. Lo intentaré cuando regrese a casa. (En el trabajo ahora) –

10

¿Cuáles fueron los errores que estaba obteniendo? Uso de la muestra de Scala y la siguiente clase Java:

cat test.java:


import org.fun.*; 

public class test { 
    public static void main(String args[]) { 
     System.out.println("show my power: " + ScalaPower.showMyPower(3));  
    } 
} 

y ejecutarlo de la siguiente manera:

java -cp .:<path-to/scala/install-dir>/lib/scala-library.jar test

da a mi la salida:

show my power: 0, 1, 2

+1

Hmm, es extraño. Mi código ni siquiera compila. Está diciendo '' Símbolo 'showMyPower' no encontrado "' (aunque IDEA Scala Plugin lo entiende y me ofrece una autocompletación) –

+0

Descubrí que en realidad el método 'showMyPower' está declarado dentro de Scala $, no en Scala. ¿Qué versión de Scala estás utilizando que haga que estos códigos sean compilables? Estoy usando 2.7.5 –

+0

Ouch, 'org.fun.ScalaPower $ .MODULE $ .showMyPower' es de hecho el método correcto que debería llamar, ¿Qué diablos? –

1

Después de hacer

class ScalaPower 
object ScalaPower{ 
    def showMyPower(time:Int) = { 
    (0 to time-1).mkString(", ") 
    } 
} 

ScalaPower.showMyPower(10) funciona como se espera.

14

Por lo general, es mejor acceder al singleton directamente desde su propia clase.

En este caso:

org.fun.ScalaPower$.MODULE$.showMyPower(10); 

Sin entrar demasiado en los detalles de implementación, Scala diferencia a los espacios de nombres entre el objeto y la clase/Rasgo. Esto significa que pueden usar el mismo nombre. Sin embargo, un objeto tiene una clase y, por lo tanto, necesita un nombre destruido en la JVM. Las convenciones actuales de Scala es agregar $ al final del nombre del módulo (para módulos de nivel superior). Si el objeto está definido en una clase, creo que la convención es OuterClass $ ModuleName $. Para hacer cumplir la propiedad singleton del módulo ScalaPower, también hay un miembro MODULE $ estático de la clase ModuleName $. Esto se inicializa en el tiempo de carga de clases, lo que garantiza que solo haya una instancia. Un efecto secundario de esto es que debe no hacer algún tipo de bloqueo en el constructor de un módulo.

En cualquier caso, Scala también ha incorporado un mecanismo de reenvío estático "make things nicer for Java". Aquí es donde escribe métodos estáticos en la clase ScalaPower que acaba de llamar a ScalaPower $ .MODULE $ .someMethod(). Si también define una clase complementaria, los reenviadores que podrían generarse son limitados, ya que no tiene permitido tener conflictos de nombres con métodos estáticos y de nivel de instancia en la JVM. Creo que en 2.8.0 esto significa que si tienes un objeto complementario, pierdes tus reenviadores estáticos.

En este caso, una "mejor práctica" sería utilizar siempre la referencia $ .MODULE $ de ScalaPower en lugar de un reenviador estático, ya que el reenviador podría desaparecer con modificaciones a la clase ScalaPower.

EDIT: Typos

+0

El código aquí tiene un error tipográfico en MÓDULO $ –

Cuestiones relacionadas