¿Cuáles son las relaciones entre Any, AnyVal, AnyRef, Object y cómo se asignan cuando se usan en código Java?

111

Por lo general, termino probando todas las combinaciones hasta que se compilan. ¿Alguien puede explicar qué debo usar y dónde?

huynhjl
fuente

Respuestas:

125

No estaré de acuerdo con la respuesta de Chris en un aspecto. Las clases Any, AnyRefy AnyVal son clases. Pero no aparecen como clases en bytecode, debido a las limitaciones intrínsecas de la JVM.

Esto surge del hecho de que no todo en Java es un objeto. Además de los objetos, hay primitivas. Todos los objetos en Java son descendientes de java.lang.Object, pero los primitivos están separados y, actualmente * , no son extensibles por un programador. Tenga en cuenta también que las primitivas tienen "operadores", no métodos.

En Scala, por otro lado, todo es un objeto, todos los objetos pertenecen a una clase e interactúan a través de métodos. El código de bytes de JVM generado no refleja esto, pero eso no los hace menos, al igual que Java tiene genéricos, aunque el código de bytes no los tenga.

Entonces, en Scala, todos los objetos son descendientes de Any, y eso incluye tanto lo que Java considera objetos como lo que Java considera primitivos. No hay equivalente en Java porque no existe tal unificación.

Todo lo que se considera primitivo en Java es descendiente de AnyValScala. Hasta que Scala 2.10.0 AnyValse selló y los programadores no pudieron extenderlo. Debería ser interesante ver qué pasará con Scala en .Net, ya que la interoperabilidad por sí sola requiere que Scala reconozca al menos las "primitivas" definidas por el usuario.

Extendiéndose también Anyes AnyRef, que es equivalente a java.lang.Object(en la JVM, en cualquier caso).

Hasta Scala 2.9.x, un usuario no puede extender Anyo AnyVal, ni referencia a ellas desde Java, pero no eran otros usos que se podrían poner en Scala. Específicamente, escriba firmas:

def f(x: AnyVal) = println(x)
def g(x: AnyRef) = println(x)
def h(x: Any) = println(x)

Lo que significa cada uno debería ser obvio a partir de la jerarquía de clases. Sin embargo, es de destacar que fy hse auto-box, pero gno lo hará. Eso es un poco lo contrario de lo que hace de Java, en el que fy hno se puede especificar, y g(definida mediante java.lang.Object) causaría auto-boxing.

Sin embargo, a partir de Scala 2.10.0, el usuario puede extender AnyValo Any, con la siguiente semántica:

  • Si una clase se extiende AnyVal, no se creará ninguna instancia para ella en el montón bajo ciertas condiciones. Esto significa que los campos de esta clase (en 2.10.0 solo se permite un campo único; queda por ver si eso cambiará) permanecerán en la pila, ya sean primitivas o referencias a otros objetos. Esto permite métodos de extensión sin el costo de creación de instancias.

  • Si un rasgo se extiende Any, se puede usar tanto con clases que se extienden AnyRefcomo con clases que se extienden AnyVal.

PD: En mi opinión, es probable que Java siga a C # al permitir primitivas de "estructura", y tal vez typedefs, ya que el paralelismo sin recurrir a ellas está resultando difícil de lograr con un buen rendimiento.

Daniel C. Sobral
fuente
2
Una actualización: a partir de Scala 2.9.2, AnyValse define como sealed trait AnyVal extends Any. Pero en Scala 2.10 esto ha cambiado a abstract class AnyVal extends Any with NotNull, y ahora es posible extender AnyValcon la nueva característica de las clases de valor, por ejemplo: class MyValue(val u: Int) extends AnyVal.
ebruchez
@ebruchez Gracias por la nota. Actualicé mi respuesta con una descripción general de las nuevas capacidades.
Daniel C. Sobral
¿Cómo se relaciona Nothing and Null con esto?
Gaurav Khare
5

Anyy AnyValson, creo, parte del sistema de tipos scala y no son clases como tales (de la misma manera que Nothinges un tipo, no una clase). No puede utilizarlos explícitamente desde el código Java.

Sin embargo, en la interoperación Java / Scala, un método que acepta un Java Objectesperará un scala Any/ AnyRef.

¿Qué estás intentando hacer realmente?

oxbow_lakes
fuente
Estoy tratando de entender mejor este tema para saber qué tipo debería usar cuando planeo que Java llame a Scala o viceversa. Esta respuesta stackoverflow.com/questions/2334200/… y su elenco AnyRefsimplemente me recordó que esto todavía era misterioso para mí.
huynhjl