String的不可变特性、内部存储结构、重写至Object的几个方法

一、 不可变特性,内部存储结构
  • 说到String字符串,可以语义的理解为将一系列字符(char),然后将串在一起,就是字符串了。可以猜测到String的底层也许就是这样构建出来的。 如下:进入源码发现内部结构其实就是一个字符型数组(char[])呈现的,所以字符串中的字符都是拆分成单个字符存入数组的。
    在这里插入图片描述

  • String字符串又称为不可变字符串;相对应的有可变字符串StringBuilder(线程非安全,效率高) 和 StringBuffer(StringBuilder的早期版本,线程安全,效率相对较StringBuilder低);不可变主要体现在两个方面:长度内容
    长度: value数组一旦定义长度之后,长度是不可变的。其次数组为引用数据类型,被final修饰后,其地址引用是不无法改变的;
    内容: value数组被private修饰后,外部是无法修改其内容的。

  • 也许我们会这么想,为啥我感觉不到它的不可变特点呢?比如:

    	String str = "hello"; 
    	str = "hello,world";
    

    这不就改变了吗?下面来理解一下:
    1,首先我们得知道,字符串虽然是引用数据类型,但是有一点特点不同于正常的引用数据类型,正常情况下,构建一个类的对象,它需要通过构造方法构建的,但是String可以像基本数据类型将一个串直接赋值给一个变量引用(我们习以为常的这样创建,如上面得例子;不过也可以通过构造方法来构建)。

    2,比如在执行上面那个语句的时候,"hello"其实相当于一个常量,但是它是存在常量池的一个String对象;String str = “hello” 就是将引用指向了一个在常量区的这个对象,而str = “hello,word”;这一步其实是在常量池新创建一个String对象,并将地址存到原来的变量中,并不是直接通过改变其内部数组的内容和地址的。
    在这里插入图片描述

    • 下面通过一个例子来进一步理解

          String a = "Code";
          String b = "once";
          String d = ",";
          String d = "Think";
          String e = "twice";
          String str = a + b + c + d + e;
      

      问:上面这个过程共创建了多少个对象?9个
      由于a, b, c, d, e 这里本身创建了5个对象;在进行a + b的过程中,String底层做的是将a ,b两个字符串中的value数组的值进行合并成一个新数组,然后创建一个新对象,并且新对象的底层数组就指向这个新数组,此时创建了第6个String对象;
      当a + b 的结果再加上c的时候,a + b的计算结果对应的那个字符串对象的value数组在和c的value数组进行合并成一个新数组,再创建一个新对象,将该对象的底层数组就指向这个新数组,这个时候创建了第7个String对象;后面依次类推。
      大致理解如下:

         a:         	{"Code"}                     1
         b:         	{"once"}                     2
         a+b:       	{"Code once"}                ==6 中间过程产生的对象
         c:         	{","}                        3
         a+b+c:     	{"Code once,"}               ==7 中间过程产生的对象
         d:         	{"Think"}                    4
         a+b+c:     	{"Code once,Think"}          ==8 中间过程产生的对象
         e:         	{"twice"}                    5
         a+b+c+d+e: 	{"Code once,Think twice"}    ==9
      

      总结:
      1,由于String的内部结构特点,从而有了不可变特性,在字面量创建字符串时本身会创建一个对象,在使用“+”运算符进行字符串拼接的过程中也会产生第三个新的字符串对象,并且将原来字符串的引用指向了新的字符串对象,表面上的拼接运算,实则却是String对象的创建,只是我们看不到底层操作罢了。

      2,假设我们拼接次数非常的频繁,可以想象到对象的频繁创建,想必是非常消耗内存的,且影响性能;所有后来有了可变字符串(StringBuffer和StringBuilder),适用于频繁拼接字符串的这一个过程。

    二、重写至Object的几个方法
    • 在Java官方API文档中可以看到,String类它存在于java.lang包下,它直接继承于Object;实现了Serializable, CharSequence,Comparable 三个接口。
      下面我们就来探讨一下重写至Object父类的方法:equals(),hashCode(),toString() 和实现的Comparable接口的 compareTo() 方法。
      1,equals()方法:equals()方法默认比较的是引用。而String进行了重写,如果引用相同,则表明同一对象,内容必然相同,返回true;引用不同则比较内容,也就是value数组的每一位字符进行依次遍历比较,如果都相同则也返回true。
      在这里插入图片描述 在这里插入图片描述
      一般最容易出现的笔试问题就是对于String,"==" 和 equals()方法的比较过程。
      eg: 判断输出结果

       String a = "java中的String";
       String b = "java中的String";
       String c = new String("java中的String");
       String d = new String("java中的String");
       System.out.println(a==b);             //true
       System.out.println(a==c);             //fasle
       System.out.println(c==d);             //fasle
       System.out.println(a.equals(b));      //true
       System.out.println(a.equals(c));      //true
       System.out.println(c.equals(d));      //true
      

      a、b指向的是常量池中的同一个对象;而通过new 创建出来的对象是存在堆内存中的,并且每次创建出来的都是不同对象,所以c、d表示不同的对象。
      在这里插入图片描述
      由于"=="比较的是引用,所以:a == b 结果为true,a == c结果为 false,c == d 结果为fasle。
      由于equals()重写了,同一对象则为true,不同对象则比较内部的值,所以结果都为true。在这里虽然a与c是不同对象但是由于值相同,所以也为true。

      2,hashCode()方法:hashCode()方法默认是调用了底层本地其他语言的方法,经过一系列算法求出以一个整型数值。而String进行了重写,将字符串的每一位进行遍历进行相应的计算后并且累加,最 后返回结果。如下:
      在这里插入图片描述
      3,toString()方法:toString()方法默认获取类名后中间通过“@”与hashCode()方法结果对应转化的16进制数进行拼接作为结果返回。而String进行了重写,返回字符串本身。
      在这里插入图片描述
      在这里插入图片描述
      4,compareTo()方法:compareTo()实现至Comparable接口。默认将每一个获取两个字符串长度最小的那一个,并且将它的长度作为遍历次数进行遍历比较,如果发现其中两位字符不同,则返回这两位的code码值返回;如果循环完,如果每个轮次都相等,则返回长度之差,可以发现,如果两个字符串相等则返回0,其他情况都不为0。
      在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值