Est-il possible d'obtenir une adresse de référence? [dupliquer]

cette question a déjà une réponse ici:

en Java, y a-t-il un moyen d'obtenir l'adresse de référence, dire

String s = "hello"

puis-je obtenir l'adresse de s lui-même , aussi, puis-je obtenir les adresse de l'objet dont la référence est?

30
demandé sur Peter Lawrey 2012-01-11 17:34:41

5 réponses

vous pouvez obtenir l'index des objets avec Unsafe. Selon la façon dont la JVM utilise la mémoire (adresses 32 bits, index 32 bits, index 32 bits avec offset, adresse 64 bits) peut affecter l'utilité de l'index objet.

voici un programme qui suppose que vous avez un index de 32 bits dans un 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);
        }
    }
}

tournant sur Java 6 update 26 (64-bit avec Oops compressé) et Java 7. Note: les adresses et les adresses relatives sont en hex.

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

OU parfois

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
35
répondu Peter Lawrey 2012-01-11 13:48:52

Non, vous ne pouvez pas. Même en utilisant L'Interface Java Native (JNI), vous ne pouvez obtenir qu'une poignée opaque vers la structure des données, pas un pointeur vers l'objet JVM réel.

pourquoi voudriez-vous une telle chose? Il ne serait pas nécessairement dans une forme que vous pourriez utiliser pour n'importe quoi, de toute façon, même à partir de code natif.

6
répondu Ernest Friedman-Hill 2012-01-11 13:36:51

Oui, vous pouvez le faire avec danger, bien que ce ne soit pas si directement. Mettez la référence de l'objet ou de l'instance dans un int[], c'est ok. long [] devrait être très bien aussi.

    @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;
}
3
répondu qinxian 2012-04-27 11:42:26

en fait l'adresse peut être obtenue avec sun.misc."Dangereux mais il est vraiment très dangereux. GC déplace souvent des objets.

2
répondu Vadzim 2012-01-11 13:43:09

il n'est pas possible en Java d'obtenir une adresse de référence d'un objet, comme votre chaîne de caractères. L'adresse de référence d'un objet est caché à l'utilisateur, en Java.

en C, vous pouvez le faire, à travers le concept de pointeurs. Java a un concept similaire, à bas niveau,et c'est l'adresse de référence. La référence est comme un pointeur de C, mais elle n'est pas explicite. En C, vous pouvez faire l'opération de référencement de pointeurs, à travers le * , mais en Java, ce n'est pas possible.

Je n'aime pas beaucoup le langage C, aussi parce que les pointeurs, selon moi, ne sont pas un concept Facile à gérer. C'est l'une des raisons pour lesquelles J'aime Java, parce que le programmeur n'a pas besoin de se soucier du pointeur d'un objet.

Comme @jarnbjo dit, vous pouvez vérifier, si certaines références sont similaires, avec une syntaxe comme celle-ci:

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));

notez que == vérifie l'égalité de référence adresse. Si vous voulez vérifier l'égalité de la valeur des chaînes, utilisez la méthode equals() .

je vous suggère de lire ceci donc question, ceci page Wikipedia et ceci page.

1
répondu Alberto Solano 2017-05-23 12:18:11