Java剖析String类

String类对象的两种实例化方法

String并不是一个基本数据类型,它本身属于一个类。但是这个类在设计的过程之中加入了属于Java的特殊支持,所以对于这个类的对象实例化方式有两种形式

  • 直接赋值:String 对象名称 = "内容";
  • 构造方法:String 对象名称 = new String("内容");

String的相等比较

如果说现在有两个int型的变量,要进行相等的判断,则直接使用“==”即可;如果进行String的比较,我们可先用“=="尝试:

class StringDemo{
    public static void main(String[] args){
        String steA = "hello";
        String steB = new String("hello") ;
        String steC = steB;
        System.out.println(steA == steB);//false
        System.out.println(steB == steC);//true
        System.out.println(steA == steC);//false
    }
}

发现结果并不相等,此时我们发现问题,字符串的内容实际上都是一样的,而在使用“==”比较结果是,具体原因如下图所示:

String内存关系图

  • 发现在程序中如果使用“==”比较的只是两个对象(任意的引用类型),并不是对堆内存中保存的内容进行比较
  • 如果想要在String类中进行比较,那么可以利用String类中提供的public boolean equals(String str);方法进行比较
代码如下:
class StringDemo{
    public static void main(String[] args){
        String strA = "hello";
        String strB = new String("hello") ;
        String strC = strB;
        System.out.println(strA.equals(strB));//true
        System.out.println(strB.equals(strC));//true
        System.out.println(strA.equals(strC));//true
    }
}

\color{red}{由于内容是可控的因素而地址是不可控的因素,因此只要是字符串的比较都使用equals()完成}

面试题:请解释在String比较中”==“与"equals()"的区别
  • "=="是java的一种关系运算符,可以进行数值比较,如果用在String上时则是对堆内存地址数值进行比较,使得结果错误
  • "equals()"是String类的一个方法,用于进行字符串内容的比较

String匿名对象

任何的编程语言都不会提供有字符串这一数据类型,字符串的描述在很多语言之中都是用字符数组表示,而在Java的设计之初为了解决这样的问题,专门提供了一个String类来进行描述。但是随着发展,为了能够让程序变得更加的易于开发,所以在Java里面也提供双引号声明的数据,而这些数据,在Java中并不是普通的变量,而是String类的匿名对象

String 字符串对象 = "字符串";本质:就是为一个字符串的匿名对象起了一个名字


String类两种实例化对象的区别(核心)

此时对于String类的声明方式有两种,那么这两种方式到底应该使用哪一种,以及每种方式的区别

分析String类对象直接实例化的形式

开辟一块堆内存空间,并且开辟一块栈内存空间将直接指向该堆内存

观察以下代码:

class StringDemo{
    public static void main(String[] args){
        String strA = "hello";
        String strB = "hello";
        String strC = "nihao";
        System.out.println(strA == strB);//true
        System.out.println(strB == strC);//false
        System.out.println(strA == strC);//false
    }
}

\color{red}{此时我们可能有疑问,为何使用
内存关系图如下:

内存关系图

关于对象池的概念(Object Pool):

  • 为了更方便用户的代码编写开发,针对于几个特殊的类使用了共享设计的思路,其中String类属于这其中的一员。这种设计思路是Java自己的支持,而且只针对于直接赋值的情况

  • 在使用直接赋值实例化String类对象的操作之中,字符串的内容定义之后实际上会自动将其保存在一个对象池之中,而后如果现在有其他的字符串对象也采用了直接赋值的形式,并且内容与之前的字符串内容完全相同,那么不会开辟新的堆内存空间,而是会通过对象池找到已有的堆内存空间地址,直接引用即可

回到上方的疑问:由于对象池的存在,当若干个字符内容相同时,地址是完全相同的,所以“==“的结果也是相同的,这样的设计就是共享设计模式

分析String类利用构造方法实例化对象的形式

代码如下:

class StringDemo{
    public static void main(String[] args){
        String str = new String("hello");
        System.out.println(str);
    }
}

内存关系图如下:

内存关系图

分析以上情况:

  • 通过此时的内存分析可以发现,如果采用了构造方法进行String类对象的实例化操作,那么最终会产生两块堆内存,其中一块是垃圾空间

  • 如果使用了构造方法进行String类对象实例化,那么所产生的的对象将不会保存在对象池之中(此对象无法重用),如果用户需要其入池,只能通过public String intern();手工入池

面试题:请解释String类两种对象实例化的区别
  • 直接赋值String str = "字符串";:只会开辟一块堆内存,且对象可以自动入池以供重复使用

  • 构造方法String str = new String("字符串");:会开辟两块堆内存,且其中一块为垃圾空间,由构造方法声明的实例化对象不能自动入池,需要调用intern()方法手动入池


字符串一旦声明不可改变

观察以下代码:

class StringDemo{
    public static void main(String[] args){
        String str = "hello ";
        str += "world";
        str += "!!!";
        System.out.println(str);
    }
}

分析内存关系:

内存关系图

可以发现整个的操作流程之中,都是String类对象的引用发生着改变,而字符串本身的内容并没有改变,这样的操作会产生大量垃圾,因此杜绝使用


总结

  • String类开发中都使用直接赋值,并且不要频繁修改

  • 字符串内容比较时使用equals()方法

你可能感兴趣的:(Java剖析String类)