【Java基础知识】 字符串 String 类 知识总结

1.创建字符串

常用的构造String 的方式:

String str = "Hello";
String str2 = new String("hello");
char[] array = {'a','b','c'};
String str3 = new String(array);

要知道String不是基本数据类型,而是引用类型
那么对于以下代码:

String str1 = "Hello";
String str2 = str1;

引用str1,str2指向的是同一个对象,对象内存放的内容是"Hello" 字符串
但当修改str1时,str2却不会随之而改变比如:

Str1 = "world"

这个操作实现的功能是使得str1指向了一个新的String类型的对象。

2.字符串比较

(1)比较相等

通常,我们对于两个int类型的数据来比较相等时,会使用 ==操作符。
但是对于String类型的对象却不能使用这种方式,如果对两个String对象进行 ==的比较,比较的就是两个String类型的引用是否指向同一个对象!,而我们需要实现的功能是比较两个String类型对象中是否保存着同样的值。

在Java中,关于对象的比较有三种方式:比较值、比较身份、比较类型
而==操作符在Java中就是来比较身份的,指的是两个引用指向同一个对象

正确的方式是使用equals方法进行比较,事实上,如果我们比较的对象是引用类型,就要使用此种方法。

String str1 = new String("Hello");
String str2 = new Stirng("Hello");
 System.out.println(str1.equals(str2));

执行结果:true

另一种方法:

String str = new String("Hello"):
System.out.println(str.equals("Hello"));
//或者:
System.out.println("Hello".equals(str));

此方法是可以区分字符的大小写,如果我们可以忽略大小写,就可以使用 equalsIgnoreCase(String str)方法进行比较相等,使用方法同equals()

(2)比较大小

如果要比较两个字符串的大小关系,就可以使用compareTo(String str)方法。
在String类中compareTo()方法是一个非常重要的方法,该方法返回一个整型,该数据会根据大小关系返回三类内
容:
对于str1.compareTo(str2);

  1. 相等:返回0.
  2. str1小于str2:返回内容小于0.
  3. str1大于str2:返回内容大于0。

字符串的比较大小规则, 总结成三个字 “字典序”
相当于判定两个字符串在一本词典的前面还是后面. 先比较第一个字符的大小(根据 unicode 的值来判定), 如果不分胜负, 就依次比较后面的内容

3.字符串常量池

同样,对于上面的问题,如果我们写这样的代码:

String str1 = "Hello";
String str2 = "Hello";
System.out.pringln(str1 == str2);

执行结果:true

这就说明str1 和 str2 是指向同一个对象的,这里就需要提到字符串常量池的概念。

此时"Hello"这个字符串就被存储到常量池,如果再次创建(不是以new的方式)一个String对象的内容也为"Hello",那新的引用直接指向常量池的对象,而不会存储多次。但使用new方式创建对象就会给每一次创建的对象重新分配内存

这也是String类的共享模式设计
具体来说就是:

在JVM的底层实际上会自动维护一个对象池,也就是字符串常量池
1.如果现在采用了直接赋值的模式进行String类对象的实例化操作,那么该实例化对象的字符串内容就会自动保存到这个对象池中
2.如果下次继续使用直接赋值的方式实例化对象,此时对象池中若有指定的内容,将直接引用
3.如果没有,则开辟的字符串对象后将其保存在对象池中供下次使用

但由于使用new的构造方式对对象进行实例化时,会在内存中开辟两个空间,而且其中一块内存会成为垃圾空间(字符串常量是一个匿名对象,用了一次后就不再使用了,成为垃圾空间被JVM自动回收)。而且同一个对象会被存储多次,比较浪费空间。
在这里插入图片描述
如果我们希望将new出的对象也放入常量池,那就可以使用String的intern方法来对对象手动入池:

情况一:
String str1 = new String("Hello");
String str2 = "Hello";
System.out.println(str1 == str2);

执行结果:false

情况二:
String str1 = new String("Hello").intern;
String str2 = "Hello";
System.out.println(str1 == str2);

执行结果:true

如果两个对象都存放在对象池中,那么就可以使用 == 来判别相等,但建议使用 equals()方法。

所以,现在我们可以得到String类中两种对象实例化的区别:

  1. 直接赋值:只会开辟一个空间,并且该字符串对象可以自动保存在对象池中供下次使用。
  2. 构造方法:会开辟两快堆内存,其中一块成为垃圾空间,不会保存在对象池中,但可以使用intern()方法手动入池。

4.字符串的不可变性

字符串是一种不可变对象,它的内容是不可变的。也即若有代码String str = "hello"; 这个hello就是不可变的,只要创建了就不可以随意修改其中的某一个字母。但可以直接改变引用的指向,这两个概念是不同的。
String类的内部是基于char[ ]实现的,但String类中没有提供方法修改内部字符数组。

String str = "Hello";
str = str + "world";
str += "!";

执行结果:
Hello world!

这是不是改变了字符串呢?不是!这里是改变了str引用指向的对象。也即重新创建了一个Hello world!的对象,并让str引用指向这个对象。而原本的Hello并没有改变。

那如果想修改字符串内容呢?
这里介绍一个String类中的一个方法Substring方法,这个方法可以提取一个字符串中指定的部分。
在这里插入图片描述

情况一:
String str = "Hello";
str = "h" + str.substring(1);
System.out.println(str);

执行结果:hello

情况二:
String str = "Hello";
str = str.substring(0,3) + "p";
System.out.println(str);

执行结果:Help

substring函数中的第一的参数是复制的起始位置,第二个参数是终止位置,不包含该位置的字符。

为什么 String 要不可变?(不可变对象的好处是什么?)

  1. 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑何时深拷贝字符串的问题了.
  2. 不可变对象是线程安全的.
  3. 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中.

5.字符串的拆分

在String类中,使用的拆分字符串的方法是:
在这里插入图片描述
示例:

	String str = "hello world hello bit" ;
 	String[] result = str.split(" ") ; 
 	 // 按照空格拆分
 	 for(String s: result){ 
 	  System.out.println(s);
 	   }
 	  //拆分后的结果保存到一个String类型的数组中

字符串的部分拆分:

String str = "hello world hello bit" ; 
String[] result = str.split(" ",2) ; 
for(String s: result) {
	System.out.println(s); 
 }

有的特殊字符无法作为分隔符切分,就需要加上转义:

String str = "192.168.1.1" ; 
String[] result = str.split("\\.") ; 
for(String s: result) {
 System.out.println(s); 
 }
  1. 字符"|","*","+"都得加上转义字符,前面加上"\"
  2. 而如果是.那么就得写成"\\."
  3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符.

多次拆分:

String str =  "name=zhangsan&age=18" ;
String result = str.split("&");
for(innt i = 0; i < result.length; i++){
	String temp = result[i].split("=");
	System.out.println(temp[0]+"="temp[1]);
}

6.空字符串与值为null的字符串

前者是指字符串中没有任何内容,而后者是指字符串的值为null。
前者是指引用指向一个为空的字符串,后者是指没有对象与之关联。

前者判定:
if(str.length == 0)if(str.equals(""))为真
后者判定:
if(str == null)为真

7. StringBuffer和StringBuilder

任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的
指向而已。
那么如果我们要使字符串频繁修改,使用String方法就会产生很多无用对象,为了方便字符串的修改,提供StringBuffer和StringBuilder类。

StringBuffer类中最重要的就是append和insert方法,它们被重载以便接受任何类型的数据。
每个都有效地将给定的数据转换为字符串,然后将该字符串的字符附加或插入到字符串缓冲区。
append方法总是在缓冲区的末尾添加这些字符;
insert方法将insert添加到指定点。

 StringBuffer append(各种数据类型 b)
 StringBuffer insert(int offset,各种数据类型 b)

String和StringBuffer最大的区别在于:String的内容无法修改,而StringBuffer的内容可以修改。频繁修改字符串
的情况考虑使用StingBuffer。
除了append()方法外,StringBuffer也有一些String类没有的方法:

  • 字符串反转:
    public synchronized StringBuffer reverse()
  • 删除指定范围的数据:
    public synchronized StringBuffer delete(int start, int end)
  • 插入数据
    public synchronized StringBuffer insert(int offset, 各种数据类型 b)

请解释String、StringBuffer、StringBuilder的区别:
1.String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
2.StringBuffer与StringBuilder大部分功能是相似的
3.StringBuffer采用同步处理,属于线程安全操作;而StringBuilder采用异步处理,属于线程不安全操作

发布了62 篇原创文章 · 获赞 28 · 访问量 6077

猜你喜欢

转载自blog.csdn.net/Moo_Lavender/article/details/102746183