常用类——String类概述

public final class String
   implements java.io.Serializable, Comparable<String>, CharSequence {
   private final char value[];
   private int hash; 

上面是String类源码的一部分

1、由final修饰,不可以继承

2、实现了Serializable接口:表示字符串支持序列化;实现了Comparable接口,表示String可以比较大小

3、String内部定义了final char[]value用于存储字符串数据

4、String代表不可变的字符序列(String类的重要性质——不可变性)

5、通过字面量给一个字符串赋值的过程中,此时字符串声明在字符串常量池中(与new完全不同)

6、字符串常量池中没有两个相同的字符串

7、理解不可变性

不可变性

public class Java1Test1 {
    public static void main(String[]args)
    {
        String s1="abc";
        String s2="abc";
        System.out.println(s1==s2);
        s1="hello";
        System.out.println(s1);
        System.out.println(s2);
    }
}

此处显示出来的结果为

String是一个类,“==”符号在类的比较中很显然是对地址进行比较,但是在对于s1和s2的比较中,很明显现实的结果是true,证明二者存储地址相同,但是在对s1进行更改时,s2并没有随着更改,此处的疑惑就涉及到关于String类的不可变性

在这个过程中用图来描述关于不可变性的理解

如图所示,“==”依旧是比较引用数据类型的地址值,此处证明了不可变性,与原本存储方式是在分给的存储空间内部更改数据,此处不会对数据进行更改,而是会更改赋给原本位置的地址值修改读出内容

方法区中的字符串没有任何变动,所以可以从这个方向理解不可变性 

这时我们会有一个问题,就是关于字符串的连接,如果字符串连接了一

个字符串2,那么是在方法区对应的地址尾部加上字符串2吗

问题用一个例子来佐证

public class Java1Test1 {
    public static void main(String[]args)
    {
        String s1="abc";
        String s2="abc";
        System.out.println(s1==s2);
        s1+="hello";
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s1==s2);
    }
}

 此处得出的结果是

很显然在s1和s2之间,存储的地址在最开始是相同的,之后的s1输出的abchello也证明字符串确实是连接成功了,之后s2,发现s2的值实际上并没有发生改变,s2存储的依旧是原来的地址,但是s1并不是,这个时候我们对二者使用“==”进行比较,果然发现结果是false

不可变性,就是指字符常量池中的字符串不可能随意的进行连接或者切割,很明显会在方法区再次创造一个新的字符串,并且赋给它新的字符串的地址

如图所示,原本存储地址的内容并不会受到影响

由此可以适当的去理解关于字符串的不可变性,不可变性并不能说明String对于存储的数据不能够更换数据,但事实上是方法区的问题

String的赋值

直接赋值

如果不使用new函数的话,证明在堆空间里是没有创建新的空间,字符串会直接保存在方法区

间接赋值

使用new函数,创建了新的堆空间,在变量中存储的是堆空间的地址,堆空间中对应的存储就是方法区中字符串的对应地址

以下是对String的赋值进行描述

String str="hellow";
//这种就是直接赋值,以下都是利用new函数的间接赋值


String str1=new String();

//就是简单利用String类本身的空参构造器

String str2=new String(String.orignal);

//也是String类的构造器,该构造器的内部语句是
//this.value=orignal.value;

String str3=new String(char[]a);

//也可以传入字符类型的数组,可以相互转化,内部语句为
//this.value=Arrays.copyOf(value,value.length)

String str4=new String(char[]a,int startIndex,int count);

//这个构造器相当于是对于字符串的切片操作了,输入字符类型的数组
//并输入起始地址值,然后输入想要的字符个数

//因为new出来的结构在堆中,所以不变性不再适用了

如果用字面量赋值,那么只需要二者的字符串内容相同,进行“s1==s2”这个语句的时候返回的值就是true, 如果使用构造器(也就是用new构造)即使字符串一致,那么执行如上语句不成立,返回的值是false

String的不可变性,即使使用构造器进行构造对象,也依旧不影响String类本身的不可变性,而且始终都是这一套原则

字符串加法

在字符串加法中

public static void main(String[]args)
    {
        String str="hellow";
        String str1="world";
        String str2=str+str1;
        System.out.println(str2);
    }

如图上就是两个简单的操作,对两个字符串进行相加,需要注意的是,此处依旧遵守不可变性

str中存储的”hellow“在方法区中的位置依旧是没有变化的,对于str1也是一样,但是str2存储的连接字符串并不是二者实际意义上的加和,而是在方法区再次创建了一个”hellowworld“的空间,依旧是不可变性。

1、常量与常量拼接的内容在方法区,且方法区中没有相同内容的常量

2、只要有其中一个是变量,结果存储在堆中,不在方法区

String类中的方法

intern()

是返回在常量池的地址

测试

public static void main(String[]args)
    {
        String str=new String("hellow");

        //此处对于str来说,str存储的地址是在堆中的空间
        //但是堆中存储的才是真的在常量池的部分

        String str1=str.intern();
        //str1相当于存储的是str在堆中存储的常量池地址

        System.out.println(str1==str);
        //此处对于二者的地址值进行比较,以证实上面的结论
    }

结果是false

所以intern()所得到的地址就是字符串常量所在方法区的位置

String作为一个常用的类,其中最值得注意一下的地方就是它独特的不可变性

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值