-
String类的特点?
- String类是final类,也即意味着String类不能被继承,并且它的成员方法都默认为final方法。
- String类其实是通过char数组来保存字符串的。
- String对象一旦被创建就是固定不变的了,对String对象的任何改变都不影响到原对象,相关的任何change操作都会生成新的对象。
-
字符串常量池?
- 我们知道字符串的分配和其他对象分配一样,是需要消耗高昂的时间和空间的,而且字符串我们使用的非常多。JVM为了提高性能和减少内存的开销,在实例化字符串的时候进行了一些优化:使用字符串常量池。每当我们创建字符串常量时,JVM会首先检查字符串常量池,如果该字符串已经存在常量池中,那么就直接返回常量池中的实例引用。如果字符串不存在常量池中,就会实例化该字符串并且将其放到常量池中。由于String字符串的不可变性我们可以十分肯定常量池中一定不存在两个相同的字符串。
String a="AA";
String b="AA";
String c=new String("AA");
a、b和字面上的AA都是指向JVM字符串常量池中的"AA"对象,他们指向同一个对象。
new关键字一定会产生一个对象AA,同时这个对象是存储在堆中。所以上面这一句应该产生了两个对象:保存在方法区中字符串常量池的AA和保存堆中AA。但是在Java中根本就不存在两个完全一模一样的字符串对象。故堆中的AA应该是引用字符串常量池中AA。所以c、堆AA、池AA的关系应该是:c--->堆AA--->池AA。
虽然a、b、c、c是不同的引用,但是从String的内部结构我们是可以理解上面的。String c = new String("AA");虽然c的内容是创建在堆中,但是他的内部value还是指向JVM常量池的AA的value,它构造AA时所用的参数依然是AA字符串常量。
字符串池的优缺点?
- 字符串池的优点就是避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能;另一方面,字符串池的缺点就是牺牲了JVM在常量池中遍历对象所需要的时间,不过其时间成本相比而言比较低。
equals和==?
- 对于==,如果作用于基本数据类型的变量(byte,short,char,int,long,float,double,boolean ),则直接比较其存储的"值"是否相等;如果作用于引用类型的变量(String),则比较的是所指向的对象的地址(即是否指向同一个对象)。
- equals方法是基类Object中的方法,因此对于所有的继承于Object的类都会有该方法。在Object类中,equals方法是用来比较两个对象的引用是否相等,即是否指向同一个对象。
- 对于equals方法,注意:equals方法不能作用于基本数据类型的变量。如果没有对equals方法进行重写,则比较的是引用类型的变量所指向的对象的地址;而String类对equals方法进行了重写,用来比较指向的字符串对象所存储的字符串是否相等。其他的一些类诸如Double,Date,Integer等,都对equals方法进行了重写用来比较指向的对象所存储的内容是否相等。
创建字符串的方式?
- 单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中;
- 使用new String("")创建的对象会存储到heap中,是运行期新创建的;
- 使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中;
- 使用包含变量的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在heap中;
String、StringBuffer、StringBuilder的区别?
- 可变与不可变:String是不可变字符串对象,StringBuilder和StringBuffer是可变字符串对象(其内部的字符数组长度可变)。
- 是否多线程安全:String中的对象是不可变的,也就可以理解为常量,显然线程安全。StringBuffer 与 StringBuilder 中的方法和功能完全是等价的,只是StringBuffer 中的方法大都采用了synchronized 关键字进行修饰,因此是线程安全的,而 StringBuilder 没有这个修饰,可以被认为是非线程安全的。
- String、StringBuilder、StringBuffer三者的执行效率如下:
- StringBuilder > StringBuffer > String 当然这个是相对的,不一定在所有情况下都是这样。比如String str = "hello"+ "world"的效率就比 StringBuilder st = new StringBuilder().append("hello").append("world")要高。因此,这三个类是各有利弊,应当根据不同的情况来进行选择使用:
- 当字符串相加操作或者改动较少的情况下,建议使用 String str="hello"这种形式;
- 当字符串相加操作较多的情况下,建议使用StringBuilder,如果采用了多线程,则使用StringBuffer。