2010-01-30 11 views
7

Soy nuevo en Java y sigo aprendiendo. Entendí las clases internas y anónimas. Ahora tengo una pregunta técnica sobre cómo se ve Java en la memoria, al asignar objetos, definir clases, etc.¿Qué aspecto tiene Java en la memoria?

Me gusta cómo se ve la memoria cuando tengo un campo que es un objeto definido en una clase externa una clase interna ¿Las clases estáticas se ven diferentes de las no estáticas?

Solo necesito una referencia visual.

Gracias chicos

+0

El "cómo" es un detalle de implementación, no se define Spec. Dicho esto, este libro no le dice cómo lo hace en realidad ninguna implementación de Java, pero sí le dice cómo podría hacerlo una VM de tipo Java: http://www1.idc.ac.il/tecs/ – Dinah

Respuesta

3

Los detalles se encuentran en la puesta en práctica (no la especificación). Sin embargo, las implementaciones generalmente siguen un patrón muy simple. La mayor parte del diseño de la memoria en Java es muy simple y directo. Mi terminología puede no coincidir con la terminología de Java, ya que no hago mucha programación en Java.

En general, un objeto comienza con un puntero a su vtable, y luego tiene un montón de campos que siguen. Los campos son tipos primitivos (int/bool/float) o punteros a los objetos. Eso es todo por los objetos. (Las clases también son objetos). Los punteros nulos son como C, no son válidos, no como Python, donde None es un objeto.

En una clase interna, hay un campo oculto adicional que apunta a una instancia de la clase externa. Así es como las clases internas acceden a los datos en la clase externa. Las clases anónimas funcionan de la misma manera. Los métodos estáticos son solo métodos en la clase en lugar de métodos en la instancia.

El vtable es donde sucede toda la magia. Cada clase tiene su propio vtable compartido entre todos los objetos. El vtable tiene información sobre la clase, como el tamaño de sus instancias y cómo se distribuyen los campos. Esta información es utilizada por el recolector de basura. El vtable también tiene un puntero a todos los métodos que implementa la clase. Cuando llamas a un método, el tiempo de ejecución primero saca el puntero vtable del objeto, luego saca el puntero del método del vtable, luego llama al método y pasa el objeto al método como un parámetro implícito. Es similar a C++, pero mucho más simple de implementar. El proceso puede omitirse si el método o la clase es "final".

Sé que Java realmente no tiene "punteros", tiene "identificadores simbólicos" o algo así, pero las implementaciones más comunes simplemente usan punteros antiguos.

1

Al igual que lo hace la memoria mirada como cuando tener un campo que es un objeto que es definido en una clase fuera contra una clase interna . ¿Las clases estáticas parecen diferentes a las no estáticas?

Una instancia de clase interna (o anónima) no estática tendrá una referencia a la instancia de clase externa que se usó para crear una instancia. Esto es lo que permite que un método en la clase interna haga referencia a los miembros de nivel de instancia declarados en la clase adjunta. Normalmente, esta referencia se pasa a la clase interna como un parámetro adicional oculto en el constructor. Pero si utiliza la reflexión para crear una instancia de clase interna, debe proporcionar ese parámetro adicional explícitamente.

(Tenga en cuenta que un mecanismo diferente se utiliza cuando se utiliza una clase anónima de los locales/parámetros en el marco del procedimiento que crea la instancia de ella ...)

Si necesita los más detalles, se puede usar para javap desmontar los bytecodes de algunas clases de ejemplo simples.

Solo necesito una referencia visual.

Lo sentimos, no hago cuadros bonitos :-)

+0

ok, encontré buen recurso con diagramas :) http://www.artima.com/insidejvm/ed2/jvm.html –

+0

+1 por no hacer fotos bonitas – stacker

+0

@pp - Miré a través de ese recurso, y no pude ver ninguna imágenes que respondieron a esta pregunta en particular sobre las clases internas. Es posible que tenga que comprar una copia impresa del libro ... –

3

Bienvenido al mundo de Java. A diferencia del lenguaje C, donde el constructo del lenguaje y la representación de la memoria se correlacionan bastante uno a uno, Java es un poco más complicado.

En primer lugar, cuando la gente habla de Java, podría significar dos cosas: Java-the-language y Java-the-platform. Aquí, me refiero a Java como el lenguaje de programación Java. El código escrito en Java se compila primero en bytecode, código de máquina para Java Virtual Machine. Si está interesado en los detalles del lenguaje Java, aquí está The Java Language Specification. Y para JVM, está The Java Virtual Machine Specification.

qué aspecto tiene la memoria cuando tengo un campo que es un objeto que se define en una clase exterior frente a una clase interna.

Voy a interpretar que esto es lo que parece el diseño de la memoria en Java Virtual Machine, ya que el diseño físico depende de la implementación de la JVM. Para esto desnate Structure of the Java Virtual Machine.

Al igual que el lenguaje Java, Java Virtual Machine funciona con dos tipos de tipos: tipos primitivos y los tipos de referencia . Hay, en consecuencia, dos tipos de valores que pueden almacenarse en variables, pasarse como argumentos, retornar por métodos y operar sobre: ​​valores primitivos y valores de referencia.

Java Virtual Machine espera que casi todas las comprobaciones de tipos se realicen en tiempo de compilación, no por la propia máquina virtual de Java. En particular, los datos no necesitan ser etiquetados o ser inspeccionables para determinar los tipos.

....

Una referencia a un objeto se considera que tiene Java Virtual Machine tipo reference. Los valores del tipo reference pueden considerarse punteros a los objetos.

Así que la respuesta parece ser que ambos campos se verán exactamente iguales: reference.

0

Un estática (anidada) de clase funciona exactamente de la misma forma que una clase de nivel superior. La única diferencia es que su nombre tiene otro nombre de clase que lo prefija. (Si observas los archivos .class compilados verás que obtendrás algo como "Outer $ Nested.class" para una clase llamada Nested anidada dentro de una clase llamada Outer.)

Una clase interna tiene un campo oculto que es una referencia a la instancia que contiene su clase externa.Cuando se escribe:

class Outer { 
    final int x; 

    class Nested { 
    int y; 

    Nested(int y) { 
     this.y = y; 
    } 

    int bar() { 
     return x + y; 
    } 
    } 

    void foo() { 
    Nested n = new Nested(5); 
    } 
} 

Es como si se hubiera escrito:

class Outer { 
    final int x; 

    static class Nested { 
    Outer outer; 
    int y; 

    Nested(Outer outer, int y) { 
     this.outer = outer; 
     this.y = y; 
    } 

    int bar() { 
     return outer.x + y; 
    } 
    } 

    void foo() { 
    Nested n = new Nested(this, 5); 
    } 
} 

El nombre de ese campo oculto (que yo he llamado "exterior" aquí) se oculta a usted, aunque puede referirse a él diciendo Outer.this dentro de la clase interna (donde Outer es el nombre de su clase externa, por supuesto). Del mismo modo, observe que cuando un método en la clase interna se refiere a algo en la clase externa, esa referencia es realmente a través de esa referencia oculta a la clase externa.

Existen algunas complicaciones adicionales con respecto a cómo funciona el control de acceso (por ejemplo: privado) con clases anidadas/internas, pero eso realmente no afecta la pregunta de "memoria" que está haciendo.

0
public class I { 
    class inner { 
     public void ctor() {}; 
    } 
} 

Looks dissasemmbled como, usted podría utilizar JAD

class I$inner { 

    // Field descriptor #6 LI; 
    final synthetic I this$0; 

    // Method descriptor #8 (LI;)V 
    // Stack: 2, Locals: 2 
    I$inner(I arg0); 
    0 aload_0 [this] 
    1 aload_1 
    2 putfield I$inner.this$0 : I [10] 
    5 aload_0 [this] 
    6 invokespecial java.lang.Object() [12] 
    9 return 
     Line numbers: 
     [pc: 0, line: 3] 
     Local variable table: 
     [pc: 0, pc: 10] local: this index: 0 type: I.inner 

    // Method descriptor #14()V 
    // Stack: 0, Locals: 1 
    public void ctor(); 
    0 return 
     Line numbers: 
     [pc: 0, line: 4] 
     Local variable table: 
     [pc: 0, pc: 1] local: this index: 0 type: I.inner 
} 

Como hexdump sería comenzar con 0xcafebabe

Cuestiones relacionadas