1.比较

程序员需要一直比较不同的变量。但是,正如您已经看到的,一切都不是那么简单。

整数非常容易比较——你只需使用==就可以了。要比较实数,您必须将它们的差异(或者更确切地说,差异的绝对值)与一些非常小的数字进行比较。

比较字符串更加困难。最重要的是,这是因为字符串是对象。更重要的是,程序员通常希望字符串比较根据情况有所不同。


2.字符串是如何排列内存的

正如您已经看到的,字符串在内存中的存储方式不同于整数和实数:

字符串是如何排列内存的

两个内存块用于存储字符串:一个块存储文本本身(其大小取决于文本的大小),而第二个块(4 个字节)存储第一个块的地址。

尽管有经验的程序员会说类似“String str变量存储对对象的引用String


3. 分配对字符串的引用

当您需要将一个字符串变量分配给另一个字符串变量时,这种方法的好处就很明显了。例子:

String text = "This is a very important message";
String message = text;

结果是内存将包含的内容:

分配对字符串的引用

在这种类型的赋值操作之后,String对象保持在原来的位置,只是它的地址(对对象的引用)被复制到变量中message


4. 使用引用和对象

但是,如果您决定将字符串转换为大写(大写字母),Java 机器会做所有正确的事情:您最终会得到两个String对象,并且text变量message将存储引用,每个对象都指向自己的对象。

例子:

String text = "This is a very important message";
String message = text.toUpperCase(); 

结果是内存将包含的内容:

使用引用和对象

请注意,该toUpperCase()方法不会更改调用它的字符串。相反,它创建一个新字符串(新对象)并返回对它的引用。

举一个更有趣的例子怎么样。假设您决定将一个字符串传递给一个Scanner对象(以便它从该字符串中读取值)。

例子:

String text = "10 20 40 80";
Scanner console = new Scanner(text);
int a = console.nextInt();
int b = console.nextInt();

您可以在此处详细了解该Scanner课程的运作方式。

这就是它将全部存储在内存中的方式:

使用引用和对象。 扫描仪类

在这种情况下,单个String对象保留在内存中,就像它原来一样——只有对它的引用被传递并存储在变量中。


5.比较对String对象的引用

最后,我们到达了有趣的部分:字符串比较。

有两个运算符可用于比较字符串变量:(==等于)和!=(不等于)。您不能使用“大于”、“小于”或“大于或等于”运算符——编译器不允许。

但这里有一个有趣的细微差别:实际上存储在字符串变量中的是什么?没错:对象的地址(引用)。将比较这些地址:

String text = "Hi";
String message = text;
String s1 = text.toUpperCase();
String s2 = text.toUpperCase(); 

这是内存中的内容:

比较对 String 对象的引用

message变量text引用(存储地址)同一个对象。但是s1s2变量存储对非常相似但不同的对象的引用。

如果你在代码中比较这 4 个变量,那么你会得到以下结果:

代码 控制台输出
String text = "Hi";
String message = text;
String s1 = text.toUpperCase();
String s2 = text.toUpperCase();
System.out.println(text == message);
System.out.println(text == s1);
System.out.println(s1 == s2); 


true  // The addresses are equal
false // The addresses are different
false // The addresses are different