美文网首页
Java剖析String类

Java剖析String类

作者: 南在南方i | 来源:发表于2020-02-13 20:19 被阅读0次

    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
        }
    }
    

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

    String内存关系图
    • 发现在程序中如果使用“==”比较的只是两个对象(任意的引用类型)\color{red}{堆内存的地址数值},并不是对堆内存中保存的内容进行比较
    • 如果想要在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}{此时我们可能有疑问,为何使用"=="运算关系符strA仍然与strB相等,在接下来我们会得到这个答案}
    内存关系图如下:

    内存关系图

    关于对象池的概念(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类

          本文链接:https://www.haomeiwen.com/subject/xlhlfhtx.html