companion - ¿Cómo llamas a un método de Scala singleton desde Java?
scala class (5)
¿Cuáles fueron los errores que estaba recibiendo? Usando su ejemplo de Scala y la siguiente clase de 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 ejecutándolo de la siguiente manera:
java -cp .:< path-to/scala/install-dir >/lib/scala-library.jar test
me da la salida:
show my power: 0, 1, 2
Estoy tratando de inyectar algo de código Scala en mi aplicación Java existente. (Así que, dicho, quiero un poco más de diversión).
Yo creo cosas singleton en Scala
ScalaPower.scala
package org.fun
class ScalaPower
object ScalaPower{
def showMyPower(time:Int) = {
(0 to time-1).mkString(", ")
}
}
Ahora, dentro de OldJava.java
class OldJava {
public void demo(){
System.out.println(?)
}
}
¿Qué debo completar ?
¿Para que Java llame al método showMyPower? org.fun.ScalaPower.showMyPower(10)
y org.fun.ScalaPower.getInstance().showMyPower(10)
pero ninguno funciona.
(Descompilar el archivo de clase usando Jad no me muestra nada más que un código sin sentido).
Edición class ScalaPower
declaración de la class ScalaPower
y scala produce el método estático como se esperaba. (la llamada a org.fun.ScalaPower.showMyPower(10)
simplemente funciona).
Me pregunto si es un error en el compilador scala o no
Creo que esto lo cubre indirectamente:
Objetos complementarios y métodos estáticos de Java
Hay una cosa más que saber sobre los objetos de compañía. Cuando defina un método principal para usar como punto de entrada para una aplicación, Scala requiere que lo coloque en un objeto. Sin embargo, en el momento de escribir esto, los métodos principales no se pueden definir en un objeto complementario. Debido a los detalles de implementación en el código generado, la JVM no encontrará el método principal. Este problema puede resolverse 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 una clase de persona simple y un objeto complementario que intenta definir main.
Como se encuentra aquí: http://programming-scala.labs.oreilly.com/ch06.html
En resumen, debido a que su Objeto es un objeto complementario (tiene una clase complementaria), no puede llamarlo como espera. Como has encontrado, si te deshaces de la clase funcionará.
Después de hacer
class ScalaPower
object ScalaPower{
def showMyPower(time:Int) = {
(0 to time-1).mkString(", ")
}
}
ScalaPower.showMyPower(10)
funciona como se esperaba.
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 la implementación, Scala diferencia espacios de nombres entre Objeto y Clase / Rasgo. Esto significa que pueden usar el mismo nombre. Sin embargo, un objeto tiene una clase y, por lo tanto, necesita un nombre mutilado en la JVM. Las convenciones actuales de Scala es agregar un $ al final del nombre del módulo (para los módulos de nivel superior). Si el objeto está definido en una clase, creo que la convención es OuterClass $ ModuleName $. Para imponer la propiedad singleton del módulo ScalaPower, también hay un miembro MÓDULO $ estático de la clase ModuleName $. Esto se inicializa en el tiempo de carga de clase, asegurando que solo hay una instancia. Un efecto secundario de esto es que no debe hacer ningún tipo de bloqueo en el constructor de un módulo.
En cualquier caso, Scala también ha incorporado un mecanismo de reenvío de estática para "hacer las cosas más agradables para Java". Aquí es donde escribe métodos estáticos en la clase ScalaPower que simplemente llama a ScalaPower $ .MODULE $ .someMethod (). Si también define una clase complementaria, los reenviadores que podrían generarse están limitados, ya que no se le permite 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 ScalaPower $ .MODULE $ en lugar de un reenviador estático, ya que el reenviador podría desaparecer con modificaciones a la clase ScalaPower.
EDITAR: Typo
Tenga en cuenta que la herramienta javap
stock se puede usar para ver qué produce el compilador de Scala. No responde directamente a su pregunta, por supuesto, pero cuando lo que necesita es solo recordar los patrones de generación de código, es suficiente.