String类作为Java中三大特殊类之一,一个很重要的类,项目开发中基本都会用到。
实例化方式
1.直接赋值
String str = "Hello World" ; // str是一个对象,那么"Hello Worldt" 保存在堆内存中
System.out.println(str) ;
这种方法最为常用。
2.通过构造方法赋值
String str = new String("Hello World") ;
System.out.println(str) ;
类对象使用构造方法实例化是标准做法。
字符串相等比较
通常,==对于基本类型而言,比较的是数值是否相等。
如下代码,String类对象通过 ==比较:
String str1 = "Hello" ;
String str2 = new String("Hello") ;
System.out.println(str1==str);
结果输出为false。对于String类实例化对象比较相等,可以使用String类提供equals()方法。
例如:
String str1 = "Hello" ;
String str2 = new String("Hello") ;
System.out.println(str1.equals(str2));
结果输出为true。
原因总结如下:
(1)“==”操作符用于比较两个变量的的值是否相等,对于基本类型而言,比较的就是数值的大小;对于引用类型而言,比较的实际上对象中保存的地址是否等待而不会比较内容。
(2)字符串内容比较时需要使用String类提供的equals()方法:str1.equals(str2)。还可以用不区分大小写比较方法:equalsIngoreCase();
String类的匿名对象
在java之中,本身也没有直接提供字符串常量的概念,所有使用 “”定义的内容本质上来讲都是String的匿名对象,即所有的字符串常量都是String类的匿名对象。
例如:
String str1 = "Hello" ;
本质上就是将一个匿名的String类对象设置有名字str1,而且匿名对象一定保存在堆内存中,而str1保存在栈内存中。
在比较两个字符串是否等于特定字符串时,将字符串常量写在equals前面,通过字符串常量来比较(避免用户str输入空,出现空指针异常)。
例如:
String str1 = "Hello" ;
System.out.println(“Hello”.equals(str1));
实例化的区别
1.直接赋值
String str1="hello";
String str2="hello";
String str3="hello";
对应的内存开辟如下:
从图中分析可以得出并没有开辟新的内存。
这种现象解释如下:
在JVM内部维护一个字符串常量池(对象数组)。若采用直接赋值的方式进行String类的实例化操作,那么JVM将该对象会自动保存到对象池之中。若下一次继续使用直接赋值的方式实例化String对象,先在对象池中寻找是否有指定内容对象,若有,直接引用。否则创建新空间,将新对象入池以供下次使用。
2.构造方法赋值:
对于下面代码
String str = new String("hello")
内存开辟过程如下:
通过分析可知,如果使用String构造方法就会开辟两块堆内存空间,并且其中一块堆内存将成为垃圾空间。此外,也会对字符串共享产生问题(即新产生的String类引用对象无法入池)。
解决入池操作:String类提供的 public String intern() ;
总结:
1.直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
2. 构造方法:会开辟两块堆内存空间,其中一块成为垃圾空间,不会自动保存在对象池中,可以使用intern()方法手工入池。
字符串不可变更
观察下面代码:
String str1 = "Hello" ;
str1= str1 + " World" ;
str1 += "!!!" ;
System.out.println(str1); // Hello World!!!
观察下图:
从图中可以发现字符串上没有发生任何变化,但是字符串对象的引用一直在改变,而且会形成大量的垃圾空间。
所有的语言对于字符串的底层实现,都是字符数组,数组的最大缺陷就是长度固定。在定义字符串常量时,它的内容不可改变。所以开发中尽量不要出现上面的代码。
StringBuffer类与StringBulider类
两个类为了方便进行字符串内容的修改,两个类提供了同样的的构造方法和常用方法,但是StringBuffer采用同步处理,属于线程安全操作;而StringBuilder采用异步处理,属于线程不安全操作。这里以StringBuffer类为例讲解。
1.StringBuffer类的append()方法
public synchronized StringBuffer append(各种数据类型 b)
在StringBuffer类中使用append()方法进行字符串连接。
例如:
public class test{
public static void main(String[] args){
//StringBuffer类测试
StringBuffer str=new StringBuffer();
//堆内存上进行连接
str.append("hello").append("aduduo");
System.out.println(str);
}
}
String和StringBuffer类不能直接转换。如果要想互相转换,可以采用如下原则:
(1) StringBuffer转为String:
a.通过StringBuffer的构造方法:
public StringBuffer(String str);
b.通过 StringBuffer append (String str);
(2) String转为 StringBuffer:
调用StringBuffer的toString的方法;
2.StringBuffer类的其它方法:
(1)字符串反转
public synchronized StringBuffer reverse()
(2)删除指定范围的数据
public synchronized StringBuffer delete(int start, int end)
(3)插入数据
public synchronized StringBuffer insert(int offset, 各种数据类型 b)
3.请解释String、StringBuffer、StringBuilder的区别:
(1)String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.;
(2)StringBuffer采用同步处理,属于线程安全操作,性能较低;而StringBuilder采用异步处理,属于线程不安全操作,性能较高;
(3)普遍场景下,推荐使用StringBulider,当String对象使用“+”进行字符串拼接时,javac编译器会将String对象变为StringBuilder类对象而后调用appen()方法来修改字符串内容,减少无用空间的开辟。拼接完成后,通过toString()方法转化为String类对象返回;
字符串与基本数据类型转换
String类型与基本数据类型转换
1.String类型变为基本数据类型
(1)String变为int 类型(Integer类):public static int parseInt(String s) throws NumberFormatException;
(2)String变为double类型(Double类):public static double parseDouble(String s) throws NumberFormatException;
(3) String变为Boolean类型(Boolean类):public static boolean parseBoolean(String s);
当String类对象中包含了非数字,在运行时会抛出NumberFormatException异常。
2基本数据类型转换变为变为String类型:
(1)通过“+”方法;
(2)通过String类的构造方法;
(3)推荐:使用String.valueOf(所有基本类型);