《Java基本原理》——String类型的存储

String类型的==与equals

1.概念区别:

     1)String既可以作为一个对象来使用,又可以作为一个基本类型来使用。
        这里指的作为一个基本类型来使用只是指使用方法上的,比如String s = "Hello",它的使用方法如同基本类型int一样,比如int i = 1;,而作为一个对象来使用,则是指通过new关键字来创建一个新对象,比如String s = new String("Hello")。但是它的内部动作其实还是创建了一个对象。
     2)对String对象的比较方法需要了解。
        J ava里对象之间的比较有两种概念,这里拿String对象来说:
        一种是用"=="来比较,这种比较是针对两个String类型的变量的引用,也就是说如果两个String类型的变量,它们所引用同一个String对象(即指向同一块内存堆),则"=="比较的结果是true。
        另一种是用Object对象的equals()方法来比较,String对象继承自Object,并且对equals()方法进行了重写。两个String对象通过equals()方法来进行比较时,其实就是对String对象所封装的字符串内容进行比较,也就是说如果两个String对象所封装的字符串内容相同(包括大小写相同),则equals()方法将返回true。


2.举例分析:

   1) 用new String() 创建字符串            
public static void main(String[] args) {
    String s1 = new String("abc");
    String s2 = new String("abc");

    System.out.println(s1==s2);
    System.out.println(s1.equals(s2));

    // 第一个结果 :false
    // 第二个结果 :true
}

    两个String类型的变量s1和s2都通过new关键字分别创建了一个新的String对象,这个new关键字为创建的每个对象分配一块新的、独立的内存堆。

    通过"=="来比较它们所引用的是否是同一个对象时,将返回false。

    通过equals()方法来比较时,则返回true,因为这两个对象所封装的字符串内容是完全相同的。

    2) 用new String() 和 ’=’创建字符串
public static void main(String[] args) {
     String s1 = "abc";
     String s2 = new String("abc");

     System.out.println(s1==s2);
     System.out.println(s1.equals(s2));

     // 第一个结果 :false
     // 第二个结果 :true
}

    第一行是把String作为一个基本类型来使用的,因此s1所引用的对象是属于String缓冲池内的。并且此时String缓冲池内并没有与其值相同的String对象存在,因此虚拟机会为此创建一个新的String对象,即new String("Hello");

    第二行是把String作为一个对象来使用的,因此s2所引用的对象不属于String缓冲池内的,即它是独立的。通过new关键字,虚拟机会为此创建一个新的String对象,即为它分配了一块新的内存堆。

    因此"=="比较后的结果是false,因为s1和s2所引用的并不是同一个对象,它们是独立存在的。而equals()方法所返回的是true,因为这两个对象所封装的字符串内容是完全相同的。

  • 两种方式都能创建字符串对象,但方式一要比方式二更优。
  • 因为字符串是保存在常量池中的,而通过new创建的对象会存放在堆内存中。
    3)用“=”创建字符串
public static void main(String[] args) {
     String s1 = "abc";
     String s2 = "abc";

     System.out.println(s1==s2);
     System.out.println(s1.equals(s2));

     // 第一个结果 :true
     // 第二个结果 :true
}
        首先这两个String对象都是作为一个基本类型来使用的,而不是通过new关键字来创建的,因此虚拟机不会为这两个String对象分配新的内存堆,而是到String缓冲池中来寻找。
        首先为s1寻找String缓冲池内是否有与"Hello"相同值的String对象存在,此时String缓冲池内是空的,没有相同值的String对象存在,所以虚拟机会在String缓冲池内创建此String对象,其动作就是new String("Hello");。然后把此String对象的引用赋值给s1。
        接着为s2寻找String缓冲池内是否有与"Hello"相同值的String对象存在,此时虚拟机找到了一个与其相同值的String对象,这个String对象其实就是为s1所创建的String对象。既然找到了一个相同值的对象,那么虚拟机就不在为此创建一个新的String对象,而是直接把存在的String对象的引用赋值给s2。
        这里既然s1和s2所引用的是同一个String对象,即自己等于自己,所以以上两种比较方法都返回ture。
 
       到这里,对String对象的基本概念应该都已经理解了。现在我来小结一下:     
       
        一、常量池中没有字符串常量"abc”
  • 通过方式一创建对象,程序运行时会在常量池中查找"abc”字符串,将找到的"abc”字符串的地址赋给a。
  • 通过方式二创建对象,无论常量池中有没有"abc”字符串,程序都会在堆内存中开辟一片新空间存放新对象。

        二、常量池中已经有字符串常量"abc”

  • 通过方式一创建对象,程序运行时会将"abc”字符串放进常量池,再将其地址赋给a。
  • 通过方式二创建对象,程序会在堆内存中开辟一片新空间存放新对象,同时会将"abc”字符串放入常量池,相当于创建了两个对象。


猜你喜欢

转载自blog.csdn.net/shixinbing/article/details/80899996
今日推荐