当前位置:首页  生活常识

生活常识

string包括什么(string类型是什么)

2024-02-06 07:28:03
导读 你们好,最近小活发现有诸多的小伙伴们对于string包括什么,string类型是什么这个问题都颇为感兴趣的,今天小活为大家梳理了下,一起往下看...

你们好,最近小活发现有诸多的小伙伴们对于string包括什么,string类型是什么这个问题都颇为感兴趣的,今天小活为大家梳理了下,一起往下看看吧。

1、从何处开始说哪,还是先来看源码吧,看一下源码对String类的解释:

2、在java程序中所有的文字,比如“ABC”,都是String类的实例。

3、字符串是常量,在被创建后,他们的值(注意是值)不能被改变。

4、字符串缓冲区支持可变的字符串。因为String类对象不可变,所以他们可以共享,例如:String str=“abc” 和 String str=new String(“str”)的值相等。

5、java语言对字符串操作提供了特殊的支持,字符串+操作使用了StringBuilder类的append实现(更细的说明下文还会分析)。字符串转换使用toString实现。

6、String类的修饰符是final,表示此类是不能被继承的。而关键点则是其实现的数据结构:字符数组。

7、String类中有一个字符数组: private final char value[];可以看出java字符串的实现方式是字符数组,并且是final型,表示value是常量,在被定以后其值不可变。

8、事实也是如此,在String类中并没有找到类似StringBuilder中的append方法。为了看的更明显,看一眼StringBuilder的value数组(继承的抽象类AbstractStringBuilder中的定义),char[] value;这是一个可变的字符数组,并没有final的修饰,所以可以使用append方法追加字符串。

9、接下来看一下其equals方法,比较字符串是否相等。其算法核心也是比较简单,就是从第一位开始比较,如果不同返回false,否则就比较下一位。

10、hashCode也重写了,如果两个字符串相等,则其hashCode的返回值也是一样的,计算公式是:

11、s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]

12、s是字符数组,n是其长度。

13、看完了equals,接下来看一个小程序,先写一个测试类。

14、查看输出。首先要清楚的知道,equals是调用String类的方法,比较的是value数组的每一位是否相同,即比较的是变量引用对象的值。而“==”则是比较变量的引用是否相同。

15、所以第一个和第二个的输出并不意外,上面已经分析过了。

16、关键就来看第三个和第四个输出:

17、因为==比较的是引用而非引用的值,这就说明了s1和s3指向同一个引用,而s2指向另外一个引用。

18、要强调两点:

19、第一点,s1和s2的引用都是String对象,为什么这么说,因为可以通过反射拿到其所属的类java.lang.String。下图1

20、第二点,也是比较关键的一点;到底创建了几个对象?如有异议欢迎指正。

21、首先来看一眼jvm对String的管理:

22、首先堆用于存储String类的实例;

23、其次每一个jvm会维护一张内部表StringTable,用于存储程序运行时出现过的不重复的String对象的引用(不重复的判断方式equals)。

24、常量池:存储字符串对象的引用。

25、(1)String s1=“abc”,在StringTable中查找此字符串(使用hashCode和equals),如果有取其引用赋值给常量池;否则,创建一个字符串对象,并将其引用保存在常量池和StringTable中。在此例子中会在堆中创建一个对象A,然后将其引用存储到StringTable和常量池入口中。

26、(1)String s2=new String(”abc“),new String每次都会在堆中创建一个新的对象B。检查StringTable中是否存在此字符串(使用hashCode和equals),没有的话再创建对象C,并将其引用保存在常量池和StingTable中。在此例子中首先会直接在堆中创建对象B;其次,在StringTable中已经发现了“abc”,所以不会再创建一个对象了C,并且只会拿到A的引用去创建对象B,为何这么说,反编译的时候看到的(下图234,图4更说明了这一点,new的时候新的对象和原来的对象指向了同一个value数组)。并且最终s2指向的是对象B的引用。

27、(3)String s3=“abc”,同理这句代码不会创建任何对象,只会将其入口指向s1的入口。

28、所以最终是创建了两个对象A和B,常量池和StringTable存储的都是对象的引用。

29、并且A和B的value数组其实是指向同一个地方,即共享一个final的字节数组,且看源码中的String构造方法,如下图4。

30、在class文件的常量池中,未连接前,字符串变量直接指向的是字符串的值;

31、连接后指向的是根据此字符串创建的对象的引用。

32、字符串拼接操作:

33、String a="ab";

34、String b="cd";

35、String c=a+b;//new String(value, 0, count);,编译期不可确定,编译器不可优化,执行的时候借助stringBuilder。

36、String d="abcd";

37、String e="ab"+"cd";//编译器可以确定,编译器优化

38、代码String c=a+b;是先创建一个StringBuilder,然后调用StringBuilder的append方法添加a和b,然后再调用其toString,在堆中new了一个对象,在new对象的时候,会检查常量池是否有“abcd”,有的话,对象的value数组,指向了常量池的引用对应的value的地址,而c则指向堆中的new的对象。

39、代码String e="ab"+"cd";是直接在常量池生成一个字符串“abcd”,e指向常量池的“abcd”。

40、下图是StringBuilder的toString,其创建了一个新的对象,并且会拷贝一份value数组。

41、总结一点,如果字符串拼接的时候有变量,则会使用stringBuilder去处理。否则直接优化。

以上就是string类型是什么这篇文章的一些介绍,希望对大家有所帮助。

免责声明:本文由用户上传,如有侵权请联系删除!