请指出下列程序运行的结果?( )
public class Example {
String str = new String("good");
char[] ch = {'a', 'b', 'c'};
public static void main(String[] args) {
Example example = new Example();
example.change(example.str, example.ch);
System.out.print(example.str + " and ");
System.out.print(example.ch);
}
public void change(String str, char[] ch) {
str = "test ok";
ch[0] = 'g';
}
}
复制代码
A. good and abc
B. good and gbc
C. test ok and abc
D. test ok and gbc
解析: 本道题主要考察的是引用数据类型值传递和字符串对象不可变的问题。
首先,我们来看一下 main 方法,在 main 方法中,创建了当前类 Example 类的对象,然后调用了它的 change 方法,传入了它的两个引用数据类型的成员变量,在调用完 change 方法后,又打印了一下两个成员变量的值。
我们都知道,在 Java 中引用数据类型值传递,传递的是内存地址,所以在 change 方法中,两个形参(局部变量,不管是不是和成员变量同名,在方法中声明的变量都是局部变量,包括在方法体声明的以及方法形参)它们各自所指向的内存空间和两个成员变量所指向的内存空间相同。
因此,change 方法中的局部变量 ch 在更改了索引 0 的数据之后,成员变量 ch 也会受到影响,因为它们指向的是同一个内存空间。
我们又知道,在 JDK 1.9 之前,字符串类型(String)内部是通过一个不可变的字符数组来实现的内容存储。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
// ....
}
复制代码
在 JDK 1.9 开始,JDK 开发人员经过调研与分析之后,为了降低原来字符存储造成的内存空间浪费,更改了字符串类型(String)的内容存储方式为不可变的字节数组。
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
@Stable
private final byte[] value;
private final byte coder;
@Native static final byte LATIN1 = 0;
@Native static final byte UTF16 = 1;
static final boolean COMPACT_STRINGS;
static {
COMPACT_STRINGS = true;
}
// ....
}
复制代码
但不管怎样,重点是字符串内部的存储方式都是不可变的数组,这意味着字符串对象是不可变的,如果内容发生了改变,就会产生一个新的字符串对象。
好的,我们再回过来看一下本道题,change 方法中对局部变量 str 更改了一下字符串内容,既然涉及到了字符串内容的改变,那么就会创建一个新的字符串对象并将它的内存地址赋值给局部变量 str,这时候局部变量 str 和成员变量 str 就没有什么关系了,而且刚才的内容改变动作也不会影响到成员变量 str。
所以,当在 main 方法中调用完 change 方法之后,打印成员变量 str 和 ch 的值的结果就是:good and gbc 。