Java学习笔记——String(字符串的创建,字符串值不能更改的理解,String s = ““与String s = new String()的区别,常量相加与变量相加的区别)

String

      • 字符串的创建
      • 对于字符串一旦被赋值就不能被改变的理解
      • String s = new String(“hello”)和String s = “hello”;的区别是什么?
      • 字符串常量相加与变量相加的区别

字符串的创建

字符串的简单理解,就是由多个字符组成的一串数据叫字符串, 也可以看作一个字符数组
Java中所有的字符串文字(例如"abc")都被实现为此类的实例(对象)。
1、字符串字面值"abc"也可以被成为一个字符串对象
2、字符串是常量,一旦被赋值,就不能被改变

构造方法:
            public String()
            public String(byte[] bytes)
            public String(byte[] bytes,int offset,int length)
            public String(char[] value)
            public String(char[] value,int offset,int count)
            public String(String original)

字符串的方法:
public int length()返回此字符串的长度。

例子

package test.StringDemo;

public class demo1 {
    public static void main(String[] args) {
        //构造方法public String()
        String s = new String();
        System.out.println("s: "+s);
        System.out.println("字符串s长度为 "+s.length());
        String ss = new String("abc");
        System.out.println("ss: "+ss);
        System.out.println("字符串ss长度为 "+ss.length());
        System.out.println("=============");

        //构造方法 public String(byte[] bytes) 将一个字节数组转为一个字符串
        byte[] b = {97,98,99,100,101};
        String s1 = new String(b);
        System.out.println("s1: "+s1);
        //构造方法 public String(byte[] bytes,int index,int length)
        //将字节数组中的一部分截取出来变成一个字符串
        String s2 = new String(b,1,3);
        System.out.println("s2 "+s2);
        System.out.println("=============");

        //构造方法 public String(char[] value)
        //将一个字符数组转化成一个字符串
        char[] c = {'a','b','c','字','符','串'};
        String s3 = new String(c);
        System.out.println("s3: "+s3);
        //构造方法 public String(char[] value,int index,int count)
        //将字符数组中的一部分截取出来变成一个字符串
        String s4 = new String(c,1,4);
        System.out.println("s4: "+s4);
        System.out.println("=============");

        //public String(String original)
        String s5 = "original";
        String s6 = new String(s5);
        System.out.println("s6: "+s6);
    }
}

结果为
Java学习笔记——String(字符串的创建,字符串值不能更改的理解,String s = ““与String s = new String()的区别,常量相加与变量相加的区别)_第1张图片

对于字符串一旦被赋值就不能被改变的理解

先来看一段代码

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

结果为helloworld,这里s对应的值从hello变成了helloworld,那么为什么还说字符串一旦被赋值就不能被改变呢?

当我们使用String s = “hello”;语句创建字符串的时候,首先会去常量池中查找,如果有,就返回这个常量的地址,如果没有,在常量池中创建并返回。

比如这里的“hello”,一开始是没有的,所以要先创建,然后返回一个地址,比如0x001
下一次,如果String ss = “hello”;的时候,ss指向的也会是这个0x001的地址

Java学习笔记——String(字符串的创建,字符串值不能更改的理解,String s = ““与String s = new String()的区别,常量相加与变量相加的区别)_第2张图片
我们可以用==来验证一下

String s = "hello";  //常量池中没有常量"hello"就创建,假设地址值为0x001
String s1 = "hello"; //在常量池中查找到"hello",因此s1也指向地址0x001
System.out.println(s==s1); //地址值相同,所以返回的结果为true

之后 s = s+“world”; 语句中出现了“world”,同样要在常量池中创建
Java学习笔记——String(字符串的创建,字符串值不能更改的理解,String s = ““与String s = new String()的区别,常量相加与变量相加的区别)_第3张图片
现在需要将“hello”与“world”进行拼接,这里的拼接会开辟出一个新的地址空间,然后将拼接后的”helloworld“放入
Java学习笔记——String(字符串的创建,字符串值不能更改的理解,String s = ““与String s = new String()的区别,常量相加与变量相加的区别)_第4张图片
之前的变量s会重新指向这个新的地址0x003,而不是原先的0x001

所以说字符串一旦被创建,值就不可改变
这里的值指的字符串本身的值,而不是地址值

那么现在需要思考下一个问题

String s = new String(“hello”)和String s = “hello”;的区别是什么?

package test.StringDemo;

public class demo2 {
    public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = "hello";

        System.out.println(s1 == s2); // false
        System.out.println(s1.equals(s2)); //true
    }
}

这里可以发现s1与s2的内容相同,但是地址不同

这里需要确认三件事情

  1. ==比较引用数据类型比较的是地址值
  2. equals默认比较的是地址值,但是由于String类中重写了该方法,所以比较的是内容
  3. String s = new String(“hello”) 会在堆内存中创建对象

知道了这三点,再来看具体的操作过程
首先是String s1 = new String(“hello”);
new String()会在堆内存中创建对象,而引用变量String s1则会在栈里面被创建,然后s1指向堆内存中被创建的String对象
”hello“也会在常量池中被创建,然后new String()创建的String对象会指向”hello“的地址,比如0x001,而String对象本身在堆内存中的地址,假设为0x0001,两个地址是不一样的

因此,这里的引用变量s1指向的是堆内存中String对象地址0x0001,而不是直接指向常量池中”hello“的地址0x001
Java学习笔记——String(字符串的创建,字符串值不能更改的理解,String s = ““与String s = new String()的区别,常量相加与变量相加的区别)_第5张图片
String s2 = “hello”;中的引用变量s2在栈里面被创建后,就可以直接指向常量池中”hello“的地址0x001

所以才会出现s1与s2的内容相同,但是地址不同的情况
Java学习笔记——String(字符串的创建,字符串值不能更改的理解,String s = ““与String s = new String()的区别,常量相加与变量相加的区别)_第6张图片

字符串常量相加与变量相加的区别

  1. 字符串如果是变量相加,是先开辟空间,然后再拼接
  2. 字符串如果是常量相加,是先加,然后再去常量池里找,如果找到了就返回,如果找不到就创建
package test.StringDemo;

public class demo4 {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "world";
        String s3 = "helloworld";

        System.out.println(s3==(s1+s2));  //false
        System.out.println(s3==("hello"+"world"));  //true
    }
}

s3==(s1+s2)的结果是false,是因为变量相加是先在常量池中开辟空间,然后将拼接后的字符串放入开辟的空间之中,因此地址会改变。
s3==(“hello”+“world”)的结果是true,是因为常量相加,是先拼接,然后在常量池中查找,是否有拼接后的字符串,如果有就返回这个地址值,如果没有才会创建新的空间。因为之前s3已经创建了”helloworld“字符串,所以返回的是s3指向的这个地址。因此地址相同。

那么还有一个问题,这里我们通过s1+s2的方式在常量池中创建了一个字符串”helloworld“,假设这个地址是0x001。那么原先s3指向的字符串同样是”helloworld“,假设地址是0x002。
这里的内容相同,但是地址不同,如果此时我再创建一个呢?比如

package test.StringDemo;

public class demo4 {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "world";
        String s3 = "helloworld";
        String s4 = s1+s2;
        String s5 = "helloworld";
    }
}

s5会在常量池中查找"helloworld",如果找到就返回地址,可是这里不仅找到了,而且一下子找到了两个,那么会返回哪个地址呢?

package test.StringDemo;

public class demo4 {
    public static void main(String[] args) {
        String s1 = "hello";
        String s2 = "world";
        String s3 = "helloworld";
        String s4 = s1+s2;
        String s5 = "helloworld";
       
        System.out.println(System.identityHashCode(s3)); //第一行
        System.out.println(System.identityHashCode(s4)); //第二行
        System.out.println(System.identityHashCode(s5)); //第三行
    }
}

第一行与第三行返回的值相同,说明s5优先指向的地址是s3一开始就创建的地址

你可能感兴趣的:(java,java,String,字符串)