2012-01-11 26 views
29

En Java, hay una manera de obtener la dirección de referencia, dicen¿Hay alguna forma de obtener una dirección de referencia?

String s = "hello" 

puedo obtener la dirección de s mismo, también, puedo obtener la dirección del objeto que se hace referencia se refiere a?

+0

especifique ¿qué quiere decir con la dirección? Dirección en la memoria? Garbage collector-id? – yankee

+0

¿Por qué lo necesitas? – jarnbjo

+0

cualquiera de las direcciones en la memoria o el recolector de basura id –

Respuesta

7

No, no puedes. Incluso utilizando Java Native Interface (JNI), solo puede obtener un identificador opaco para la estructura de datos, no un puntero al objeto JVM real.

¿Por qué querrías tal cosa? No necesariamente estaría en una forma que pudieras usar para nada, de todos modos, incluso desde código nativo.

+0

Solo quiero asegurarme de que alguna referencia sea la misma. –

+11

Si quiere comparar dos referencias, puede hacer eso con ==. No es necesario que obtenga la dirección del objeto. – jarnbjo

4

No, no puedes. Especialmente no como Java puede (y AFAIK lo hace) mover objetos en el montón si es necesario para compactar la memoria durante la recolección de basura.

¿Por qué necesita o quiere esto?

2

La dirección real se puede obtener con sun.misc.Unsafe pero es realmente muy inseguro. GC a menudo mueve objetos.

+1

El enlace que publiqué en mi comentario a Peter Lawry muestra cómo puede hacerlo, de modo que puede conservar las direcciones correctas (porque si crea objetos utilizando asignación de memoria, probablemente pueda salir técnicamente del montón, donde GC no afectará tú). Supongo que así es como funciona la BigMemory de Terracota. –

31

Puede obtener el índice del objeto con Inseguro. Dependiendo de cómo la JVM está utilizando la memoria (direcciones de 32 bits, índice de 32 bits, índice de 32 bits con desplazamiento, dirección de 64 bits) puede afectar la utilidad del índice del objeto.

Aquí hay un programa que supone que tiene un índice de 32 bits en una JVM de 64 bits.

import sun.misc.Unsafe; 

import java.lang.reflect.Field; 
import java.util.Arrays; 
import java.util.Collections; 

public class OrderOfObjectsAfterGCMain { 
    static final Unsafe unsafe = getUnsafe(); 
    static final boolean is64bit = true; // auto detect if possible. 

    public static void main(String... args) { 
     Double[] ascending = new Double[16]; 
     for(int i=0;i<ascending.length;i++) 
      ascending[i] = (double) i; 

     Double[] descending = new Double[16]; 
     for(int i=descending.length-1; i>=0; i--) 
      descending[i] = (double) i; 

     Double[] shuffled = new Double[16]; 
     for(int i=0;i<shuffled.length;i++) 
      shuffled[i] = (double) i; 
     Collections.shuffle(Arrays.asList(shuffled)); 

     System.out.println("Before GC"); 
     printAddresses("ascending", ascending); 
     printAddresses("descending", descending); 
     printAddresses("shuffled", shuffled); 

     System.gc(); 
     System.out.println("\nAfter GC"); 
     printAddresses("ascending", ascending); 
     printAddresses("descending", descending); 
     printAddresses("shuffled", shuffled); 

     System.gc(); 
     System.out.println("\nAfter GC 2"); 
     printAddresses("ascending", ascending); 
     printAddresses("descending", descending); 
     printAddresses("shuffled", shuffled); 
    } 

    public static void printAddresses(String label, Object... objects) { 
     System.out.print(label + ": 0x"); 
     long last = 0; 
     int offset = unsafe.arrayBaseOffset(objects.getClass()); 
     int scale = unsafe.arrayIndexScale(objects.getClass()); 
     switch (scale) { 
      case 4: 
       long factor = is64bit ? 8 : 1; 
       final long i1 = (unsafe.getInt(objects, offset) & 0xFFFFFFFFL) * factor; 
       System.out.print(Long.toHexString(i1)); 
       last = i1; 
       for (int i = 1; i < objects.length; i++) { 
        final long i2 = (unsafe.getInt(objects, offset + i * 4) & 0xFFFFFFFFL) * factor; 
        if (i2 > last) 
         System.out.print(", +" + Long.toHexString(i2 - last)); 
        else 
         System.out.print(", -" + Long.toHexString(last - i2)); 
        last = i2; 
       } 
       break; 
       case 8: 
        throw new AssertionError("Not supported"); 
     } 
     System.out.println(); 
    } 

    private static Unsafe getUnsafe() { 
     try { 
      Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe"); 
      theUnsafe.setAccessible(true); 
      return (Unsafe) theUnsafe.get(null); 
     } catch (Exception e) { 
      throw new AssertionError(e); 
     } 
    } 
} 

se ejecuta en Java 6 Update 26 (de 64 bits con comprimido vaya) y Java 7. Nota: direcciones y direcciones relativas están en formato hexadecimal.

Before GC 
ascending: 0x782322b20, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18 
descending: 0x782322e58, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 
shuffled: 0x782322ec0, +78, -30, +90, -c0, +18, +90, +a8, -30, -d8, +f0, -30, -90, +60, -48, +60 

After GC 
ascending: 0x686811590, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 
descending: 0x686811410, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 
shuffled: 0x686811290, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 

o, a veces

Before GC 
ascending: 0x782322b20, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18, +18 
descending: 0x782322e58, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18, -18 
shuffled: 0x782323028, -168, +150, -d8, -30, +60, +18, +30, +30, +18, -108, +30, -48, +78, +78, -30 

After GC 
ascending: 0x6868143c8, +4db0, +7120, -bd90, +bda8, -bd90, +4d40, +18, +18, -12710, +18, +80, +18, +ffa8, +220, +6b40 
descending: 0x68681d968, +18, +d0, +e0, -165d0, +a8, +fea8, +c110, -5230, -d658, +6bd0, +be10, +1b8, +75e0, -19f68, +19f80 
shuffled: 0x686823938, -129d8, +129f0, -17860, +4e88, +19fe8, -1ee58, +18, +18, +bb00, +6a78, -d648, -4e18, +4e40, +133e0, -c770 
+2

++ buen trabajo. Iba a señalar esto desde otro enlace de SO: http://stackoverflow.com/questions/5574241/interesting-uses-of-sun-misc-unsafe, pero usted mostró cómo hacerlo con el código, incluso mejor. –

+2

Esto es bueno, pero los lectores deben tener cuidado de darse cuenta de que esto no es portátil; la clase 'Inseguro' es un detalle de implementación no documentada de JVM derivadas de Sun. Este código no funcionará en J9, JRockit, Dalvik, etc. –

+0

@PeterLawrey ¿Hay alguna explicación detallada sobre la cosa de 32 bits y de 64 bits? Estoy muy interesado en eso. – dawnstar

1

No es posible en Java para obtener una dirección de referencia de un objeto, como su cadena. La dirección de referencia de un objeto está oculta para el usuario, en Java.

En C, puede hacerlo a través del concepto de punteros. Java tiene un concepto similar, a bajo nivel, y esta es la dirección de referencia. La referencia es como un puntero C, pero no es explícito. En C, puede hacer la operación de referenciar punteros a través del *, pero en Java no es posible.

No me gusta mucho el lenguaje C, también porque los indicadores, según yo, no son un concepto fácil de administrar. Esta es una de las razones por las que me gusta Java, porque el programador no necesita preocuparse por el puntero de un objeto.

Como @jarnbjo dice, se puede comprobar, si algunas referencias son similares, con una sintaxis como esta:

String s = "hello"; 
String g = s; 
System.out.println("Are the reference addresses similar? "+(s==g)); 
g = "goodbye"; 
System.out.println("Are the reference addresses similar? "+(s==g)); 

en cuenta que == comprueba la igualdad de la dirección de referencia. Si desea verificar la igualdad del valor de las cadenas, use el método equals().

Sugiero que leas this SO pregunta, this página de Wikipedia y this página.

3

Sí, puedes hacerlo con inseguro, aunque no es tan directo. Ponga el objeto o referencia de instancia en un int [], eso está bien. long [] también debería estar bien.

@Test 
public void test1() throws Exception { 
    Unsafe unsafe = Util.unsafe; 
    int base = unsafe.arrayBaseOffset(int[].class); 
    int scale = unsafe.arrayIndexScale(int[].class); 
    int shift = 31 - Integer.numberOfLeadingZeros(scale); 
    System.out.printf("base: %s, scale %s, shift: %s\n", base, scale, shift); 
    base = unsafe.arrayBaseOffset(Object[].class); 
    scale = unsafe.arrayIndexScale(Object[].class); 
    shift = 31 - Integer.numberOfLeadingZeros(scale); 
    System.out.printf("base: %s, scale %s, shift: %s\n", base, scale, shift); 
    int[] ints = { 1, 2, 0 }; 
    String string = "abc"; 
    System.out.printf("string: id: %X, hash: %s\n", System.identityHashCode(string), string.hashCode()); 
    unsafe.putObject(ints, offset(2, shift, base), string); 
    System.out.printf("ints: %s, %X\n", Arrays.toString(ints), ints[2]); 
    Object o = unsafe.getObject(ints, offset(2, shift, base)); 
    System.out.printf("ints: %s\n", o); 
    assertSame(string, o); 

    Object[] oa = { 1, 2, string }; 
    o = unsafe.getObject(oa, offset(2, shift, base)); 
    assertSame(string, o); 
    int id = unsafe.getInt(oa, offset(2, shift, base)); 
    System.out.printf("id=%X\n", id); 
} 

public static long offset(int index, int shift, int base) { 
    return ((long) index << shift) + base; 
} 
+1

¿Cuáles son los paquetes de estas clases? –

+0

sun.misc.Unsafe. hg openjdk.java.net. jdk \ src \ share \ classes \ sun \ misc \ Unsafe.java – qinxian

Cuestiones relacionadas