String及相关类理解

String概述
1.String类是final类,且成员方法都为final修饰

2.String类其实是通过char数组来保存字符串的

3.String对象一旦被创建就是不可变的!其对象的任何方法调用都只是创建的新对象,而非在原对象操作

字符串常量池
1.每当我们创建字符串常量时,jvm会先去常量池(运行时常量池)中检查,如果该字符串已存在于常量池中,则直接返回实例引用。如果不存在,就会实例化该字符串并存于常量池中,由于字符串的不可变性我们可以十分的肯定常量池中一定不存在两个相同的字符串

2.java中的常量池
   静态常量池:  即*.class文件中的常量池,class文件中的常量池不仅仅包含字符串,还包含类,方法的信息,占用class文件大部分空间

   运行时常量池:  则是java虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区,我们常说的常量池,就是指方法区中的运行时常量池


3.采用new关键字创建字符串对象时,jvm首先在常量池中查找有无该字符串,如果有,则将该字符串的值拷贝并在堆中创建相应对象,然后返回堆中的地址。如果没有,在堆中创建一个对象,并将该对象的地址返回注意,此时不需要从堆中复制到池中,否则,将使得 堆中的字符串永远是池中的子集,导致浪费池的空间)!

   new String()创建的字符串不是常量,不能在编译期就确定,所以new String()创建的字符串不放入常量池中,他们有自己的地址空间


/**
* 继续-编译期无法确定
*/
public void test5(){
String str1="abc";
String str2="def";
String str3=str1+str2;
System.out.println("===========test5============");
System.out.println(str3=="abcdef"); //false
}

       首先创建str1时jvm在常量池中检查该字符串未存在,则创建"abc"字符串常量存入常量池中,并将该常量的地址返回给str1,即str1指向常量池中的"abc"字符串常量,同理,str2指向常量池中的"def"字符串常量。创建str3时,jvm首先创建了一个StringBuilder

       对象用于字符串的拼接 new  StringBuilder(str1),再调用append方法加入str2.最后通过toString()方法返回一个新的String对象并存储在堆中,将该对象的地址返回给str3

总结
1.String类初始化后是不可变的
String使用private final char value[] 来实现字符串的存储,也就是说字符串创建之后不能再修改值。其相关方法的操作,如replace(),实际上是新创建String对象,在新对象上进行操作

2.String.intern()
一个初始为空的字符串池,他由String独自维护,当调用intern方法时,如果池已经包含一个等于(equals)此String对象的字符串,则返回池中字符串,否则将此String对象添加到池中,并返回String'对象的引用

3.
(1).String中使用 + 字符串连接符进行字符串连接时,连接操作最开始时如果都是字符串常量,编译后将尽可能多的直接将字符串常量连接起来,形成新的字符串常量参与后续连接(通过反编译工具jd-gui也可以方便的直接看出);
(2).接下来的字符串连接是从左向右依次进行,对于不同的字符串,首先以最左边的字符串为参数创建StringBuilder对象,然后依次对右边进行append操作,最后将StringBuilder对象通过toString()方法转换成String对象(注意:中间的多个字符串常量不会自动拼接)。
     也就是说
     String c = "xx" + "yy " + a + "zz" + "mm" + b; 实质上的实现过程是: String c = new StringBuilder("xxyy").append(a).append("zz").append("mm").append(b).toString();
     结论:当使用+进行字符串连接时,实际上是产生了一个StringBuilder和String对象

String,StringBuffer,StringBuilder

1.可变与不可变:String是不可变字符串对象,StringBuilder和StringBuffer是可变字符串对象

2.线程安全与否:String中的对象是不可变的,也可以理解为常量,显然线程安全。StringBuffer和StringBuilder中的方法和功能完全一样,只是StringBuffer中方法加了synchronized,因此是线程安全的,StringBuilder是线程不安全

3.一般来说效率是String > StringBuilder > StringBuilder 当然,这只是相对的。要看具体的使用环境选择,

   当字符串相加操作或者改动较少的情况下,建议使用String str = “hello”,当字符串相加操作较多的情况下,建议使用StringBuilder,如果使用了多线程,则使用StringBuffer

==和equals
1.对于==,如果作用的是基本类型,则直接比较的是其存储的“值”是否相等如果作用于引用类型的变量,则比较的是所指向对象的地址(是否指向同一对象)

2.对于equals,不能作用于基本数据类型,但可以是他们的包装类,如果对equals方法不进行重写,那么比较的是引用类型的变量所指向的对象的 地址;如String,Date重写了equals方法,比较的是所指向对象的内容。


转载自:深入理解java中的String
https://www.cnblogs.com/xiaoxi/p/6036701.html

猜你喜欢

转载自www.cnblogs.com/chuixuehu/p/10907236.html