2010-09-10 27 views
11

Decir que tengo:¿Extender una clase en scala con parámetros de constructor agrega vals (campos) a la clase?

class A(val foo: String) 

class B(foo: String) extends A(foo) 
class C(val foo: String) extends A(foo) 
class D(override val foo: String) extends A(foo) 
class E(bar: String) extends A(bar) 

estoy interesado en cómo las instancias de memoria gran parte de cada una de estas clases ocupan. Las instancias de clase A tendrán una única variable miembro: foo.

¿Qué tal las clases B, C, D y E? ¿Cuántas variables de miembro tendrán cada una? Sospecho que E tendrá dos (E.bar, A.foo), espero que D tenga uno (A.foo), pero me pregunto acerca de B y C, ¿podrían tener dos? (B.foo, A.foo)?

+0

Solo una nota rápida que tanto var como val crean métodos en los archivos de clase generados por Scala. La generación de campos es algo opaca para el usuario, por lo que no puede confiar en ningún campo en particular que se genere ni en el nombre de dicho campo. – jsuereth

+0

gracias por la información jseureth –

Respuesta

14

Todos los ejemplos que compilan (A, B, D, E) tomar exactamente la misma cantidad de espacio de almacenamiento. De hecho, incluso

class F(val bar: String) extends A(bar) 

tendrá los datos almacenados en un campo; solo obtiene un método de acceso adicional para el mismo campo. Sin embargo, si

class G(var bar: String) extends A(bar) 

se construye un nuevo campo.

Puede comprobar todo esto mediante la compilación de sus ejemplos más arriba y mirando el código de bytes de javap -c Classname (nótese el putfield en 2: en el constructor de A):

public class Sizes$A extends java.lang.Object implements scala.ScalaObject{ 
public java.lang.String foo(); 
    Code: 
    0: aload_0 
    1: getfield #11; //Field foo:Ljava/lang/String; 
    4: areturn 

public Sizes$A(java.lang.String); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: putfield #11; //Field foo:Ljava/lang/String; 
    5: aload_0 
    6: invokespecial #18; //Method java/lang/Object."<init>":()V 
    9: return  
} 

(Y la falta de un putfield extra en F ...)

public Sizes$F(java.lang.String); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: invokespecial #15; //Method Sizes$A."<init>":(Ljava/lang/String;)V 
    5: return 

(Y la presencia de uno nuevo en G ...)

public Sizes$G(java.lang.String); 
    Code: 
    0: aload_0 
    1: aload_1 
    2: putfield #11; //Field bar:Ljava/lang/String; 
    5: aload_0 
    6: aload_1 
    7: invokespecial #18; //Method Sizes$A."<init>":(Ljava/lang/String;)V 
    10: return 
7

Su clase C requerirá una palabra clave override en val foo para compilar, haciéndola idéntica a D. Almacenará su propia copia de foo. Su clase B no agrega almacenamiento a menos que en algún lugar fuera de su cuerpo constructor haya una referencia a foo. Eso forzaría la creación de un campo oculto para contener el parámetro constructor. El cuerpo constructor es todo el código dentro de la definición de clase y fuera de cualquier cuerpo de método.

Adición:

package storage 

    class A(val foo: String) 

    class B(   foo: String) extends A(foo) 
// class C(  val foo: String) extends A(foo) 
    class D(override val foo: String) extends A(foo) 
    class E(   bar: String) extends A(bar) 
    class F(   bar: String) extends A(bar) { def barbar: String = bar } 

estoy perplejo por esto:

% javap -private storage.F 
Compiled from "Storage.scala" 
public class storage.F extends storage.A implements scala.ScalaObject{ 
    public java.lang.String barbar(); 
    public storage.F(java.lang.String); 
} 

Cuál es el método barbar usando para obtener su valor de retorno?

+0

'B' tampoco agregaría un campo para' foo' en caso de que accediera a él fuera del cuerpo del constructor pero use el acceso de los padres. – Moritz

+0

Gracias por la información de Randall. Solo para aclarar: ¿estás diciendo que las instancias de D tendrán dos copias de foo? –

+0

@Alex Black: Sí. El comando 'javap' es bueno para revelar estos detalles, pero tenga en cuenta que debe usar su opción' -private' para ver todos los campos privados que respaldan los métodos de acceso (y mutador) que el compilador usa para mediar el acceso a aquellos campos. –

Cuestiones relacionadas