如何测试JavaSting中使用的支持数组?

如何测试JavaSting中使用的支持数组?,java,android,string,arrays,java-memory-model,Java,Android,String,Arrays,Java Memory Model,当我开发我的Android应用程序时,我的注意力被它吸引住了 多个字符串可以共享同一个char[],因为字符串是不可变的。substring(int)方法始终返回一个字符串,该字符串共享其源字符串的支持数组。通常这是一种优化:需要分配的字符数组更少,需要的复制也更少。但这也会导致不必要的堆保留。取长字符串的短子字符串意味着长共享字符[]在两个字符串都成为垃圾之前不会成为垃圾。这通常发生在从大输入解析小的子字符串时。若要在必要时避免这种情况,请调用新字符串(longString.subString

当我开发我的Android应用程序时,我的注意力被它吸引住了

多个字符串可以共享同一个char[],因为字符串是不可变的。substring(int)方法始终返回一个字符串,该字符串共享其源字符串的支持数组。通常这是一种优化:需要分配的字符数组更少,需要的复制也更少。但这也会导致不必要的堆保留。取长字符串的短子字符串意味着长共享字符[]在两个字符串都成为垃圾之前不会成为垃圾。这通常发生在从大输入解析小的子字符串时。若要在必要时避免这种情况,请调用新字符串(longString.subString(…)。字符串复制构造函数始终确保支持数组的大小不超过所需的大小

然后我在网上读了很多资料。我知道这一点

然后我开始尝试使用,并测试代码中是否存在共享备份数组:

String str = "1234567890";
System.out.println("str.substring(1): "    + (str == str.substring(1)));
System.out.println("str.substring(0, 9): " + (str == str.substring(0, 9)));
首先,我假设==是一个相等的比较(不是吗?),它比较它们的内存位置(如C中的内容)

如果它们确实共享同一个支持数组,并且==只是比较它们的内存位置,那么这两条语句都应该返回true(或者至少最后一条语句返回true)

然而,它们都是错误的

嗯,我想我的笔记本电脑有Java7更新21。(显示在Win7->Control Panel->Java Control Panel->About中)(也显示在Eclipse->Window->Preference->Java->Compiler->Compiler compliance level:{1.3,1.4,1.5,1.6,1.7}中)

我知道1.7意味着Java7。而且我知道Java7太高了,共享备份阵列可能已经被拿走了。这就是为什么我要求Eclipse用1.5和1.6编译我的项目

Java project -> Properties -> Java Complier -> Compiler compliance level = 1.5
然而,正如我所说的,我在那些println()中仍然是错误的

让我总结一下我的问题:

Q1)如何使用Java代码验证是否使用了底层备份阵列?(除了通过数百万子字符串()生成OutOfMemoryError之外)

Q1)a。==sallow等于比较吗

Q1)b。如果我将编译器遵从性级别设置为1.5/1.6,那么我真的在使用Java5/6进行编译吗

感谢您的输入:-)

substring()返回一个新的字符串对象。即使这个返回的新字符串将引用相同的支持数组,该字符串本身也是一个不同于调用substring()方法的字符串的对象。因此,当您使用运算符==时,它将返回false

class MyClass {
    public Object myObject;

    public static void main(String args[]) {
        Object sharedObject = new Object();

        MyClass sampleA = new MyClass();
        sampleA.myObject = sharedObject;

        MyClass sampleB = new MyClass();
        sampleB.myObject = sharedObject;


        //Same object shared by different objects. Returns true.
        System.out.println(sampleA.sharedObject == sampleB.sharedObject);

        //They are different objects, as it is your str and str.substring(1).
        //So this will return false.
        System.out.println(sampleA == sampleB);
    }
}
substring()返回一个新的字符串对象。即使这个返回的新字符串将引用相同的支持数组,该字符串本身也是一个不同于调用substring()方法的字符串的对象。因此,当您使用运算符==时,它将返回false

class MyClass {
    public Object myObject;

    public static void main(String args[]) {
        Object sharedObject = new Object();

        MyClass sampleA = new MyClass();
        sampleA.myObject = sharedObject;

        MyClass sampleB = new MyClass();
        sampleB.myObject = sharedObject;


        //Same object shared by different objects. Returns true.
        System.out.println(sampleA.sharedObject == sampleB.sharedObject);

        //They are different objects, as it is your str and str.substring(1).
        //So this will return false.
        System.out.println(sampleA == sampleB);
    }
}
1) 我不明白你为什么要找出真相。由于字符串是不可变的,所以只要对其执行操作,就会创建一个新字符串(因此不会影响具有相同“后备数组”的任何内容)。正如Louis所说,您无意如此仔细地查看代码中字符串的底层工作。没什么意义

2) ==比较两个对象的指针

3) 这些语句是错误的,这是正确的,因为当您使用substring方法时,它正在创建一个新的字符串,因此将有一个指向原始字符串的不同指针。

1)我不明白您为什么需要找出这一点。由于字符串是不可变的,所以只要对其执行操作,就会创建一个新字符串(因此不会影响具有相同“后备数组”的任何内容)。正如Louis所说,您无意如此仔细地查看代码中字符串的底层工作。没什么意义

2) ==比较两个对象的指针


3) 这些语句为false是正确的,因为当您使用substring方法时,它正在创建一个新字符串,因此将有一个指向原始字符串的不同指针。

字符串对象将比较不同,即使它们共享相同的backing char数组,因为字符串对象本身是不同的对象

您可以使用反射获取背景阵列。在我的系统上,支持数组的名称是
value
,但不能保证它在您的系统上是相同的

import java.lang.reflect.*;

public class Main
{
    static Field stringBackingField = null;

    public static void main(String[] args) throws Exception
    {
        String strA = "1234567890";
        String strB = "1234567890";
        char[] charA = getBackingArray(strA);
        char[] charB = getBackingArray(strB);
        char[] subA1 = getBackingArray(strA.substring(1));
        char[] subA2 = getBackingArray(strA.substring(0, 9));
        System.out.println("charA address: " + System.identityHashCode(charA));
        System.out.println("charB address: " + System.identityHashCode(charB));
        System.out.println("subA1 address: " + System.identityHashCode(subA1));
        System.out.println("subA2 address: " + System.identityHashCode(subA2));
        System.out.println("charA == charB: " + (charA == charB));
        System.out.println("charA == subA1: " + (charA == subA1));
        System.out.println("charA == subA2: " + (charA == subA2));
    }

    public static char[] getBackingArray(String s) throws Exception
    {
        if (stringBackingField == null)
        {
            stringBackingField = String.class.getDeclaredField("value");
            stringBackingField.setAccessible(true);
        }
        return (char[]) stringBackingField.get(s);
    }
}
Java 6上的输出:

$/usr/lib/jvm/java-6-openjdk-amd64/bin/java-version
java版本“1.6.0_27”
OpenJDK运行时环境(IcedTea6 1.12.3)(6b27-1.12.3-0ubuntu1~12.04.1)
OpenJDK 64位服务器虚拟机(构建20.0-b12,混合模式)
$/usr/lib/jvm/java-6-openjdk-amd64/bin/java Main
查拉地址:1383884648
查布地址:1383884648
SUB1地址:1383884648
SUB2地址:1383884648
charA==charB:true
charA==subA1:true
charA==subA2:真
Java 7上的输出:

$/usr/lib/jvm/java-7-openjdk-amd64/bin/java-版本
java版本“1.7.0_15”
OpenJDK运行时环境(IcedTea7 2.3.7)(7u15-2.3.7-0ubuntu1~12.04.1)
OpenJDK 64位服务器虚拟机(构建23.7-b01,混合模式)
$/usr/lib/jvm/java-7-openjdk-amd64/bin/java Main
查拉地址:1264720121
charB地址:1264720121
SUB1地址:357935641
SUB2地址:722623040
charA==charB:true
charA==subA1:false
charA==subA2:false

编辑:

要查找支持数组成员的名称,请使用

java.util.Arrays.toString(String.class.getDeclaredFields());

并查找类型为
char[]

的字符串对象,因为字符串对象本身是不同的对象,所以即使它们共享相同的backing char数组,字符串对象也会比较不同

您可以使用反射获取背景阵列。在我的系统上,支持数组的名称是
value
,但不能保证它在您的系统上是相同的

import java.lang.reflect.*;

public class Main
{
    static Field stringBackingField = null;

    public static void main(String[] args) throws Exception
    {
        String strA = "1234567890";
        String strB = "1234567890";
        char[] charA = getBackingArray(strA);
        char[] charB = getBackingArray(strB);
        char[] subA1 = getBackingArray(strA.substring(1));
        char[] subA2 = getBackingArray(strA.substring(0, 9));
        System.out.println("charA address: " + System.identityHashCode(charA));
        System.out.println("charB address: " + System.identityHashCode(charB));
        System.out.println("subA1 address: " + System.identityHashCode(subA1));
        System.out.println("subA2 address: " + System.identityHashCode(subA2));
        System.out.println("charA == charB: " + (charA == charB));
        System.out.println("charA == subA1: " + (charA == subA1));
        System.out.println("charA == subA2: " + (charA == subA2));
    }

    public static char[] getBackingArray(String s) throws Exception
    {
        if (stringBackingField == null)
        {
            stringBackingField = String.class.getDeclaredField("value");
            stringBackingField.setAccessible(true);
        }
        return (char[]) stringBackingField.get(s);
    }
}
Java 6上的输出:

$/usr/lib/jvm/java-6-openjdk-amd64/bin/java-version
java版本“1.6.0_27”
OpenJDK运行时环境(IcedTea6 1.12.3)(6b27-1.12.3-0ubuntu1~12.04.1)
OpenJ