String详解

导读:本篇文章讲解 String详解,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com

目录:

1 String 概述

2 String不可变的好处

3 String,StringBuffer和 StringBuilder的区别

4 字符串常量池(String Pool)

5 new String(String类中两种对象实例化的区别)

6 String 常用方法字符串构造、String对象的比较 、字符串查找、转化、字符串替换、字符串拆分、字符串截取、其他操作方法



1 String 概述

String 被声明为 final,因此它不可被继承。
在 Java 8 中, String 内部使用 char 数组 存储数据。

4de595615e2c4f7f8d2c6618ea4a20ff.png在 Java 9 之后, String 类的实现改用 byte 数组存储字符串,同时使用coder来标识使用了哪种编 码。

bbe920db9d344b4fa50a552a013f73f4.png

value 数组被声明为 final,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内 部没有改变 value数组的方法,因此可以保证 String 不可变。


2 String不可变的好处

所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象。

可以缓存 hash 值

 因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得hash 值也不可变,因此只需要进行一次计算 。

String Pool 的需要

如果一个 String 对象已经被创建过了,那么就会从 String Pool 中取得引用 。只有 String 是不可变的,才可能使用 String Pool(确实也是,如果改变的话,那么多个引用指向内存中字符串地址,那么就不对应了)。

3ef8285d39f54df4a9672d55a88a741b.png

安全性

String 经常作为参数, String 不可变性可以保证参数不可变 。例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中 ,String 被改变,改变 String 对象的那一方以为现在连接的是其它主机,而实际情况却不一定是。 

线程安全

String 不可变性天生具备线程安全 ,可以在多个线程中安全地使用。


3 String,StringBuffer和 StringBuilder的区别

 

String和StringBuilder最大的区别在于
String
的内容无法修改,而
StringBuilder
的内容可
以修改。频繁修改字符串的情况考虑使用StringBuilder。
注意:String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
StringBuilder变为String: 调用toString()方法

可变性

String的内容不可修改

StringBuffffer与StringBuilder的内容可以修改

StringBuffffer与StringBuilder大部分功能是相似的

线程安全

String 不可变,因此是线程安全的
StringBuilder 不是线程安全的
StringBuffer 是线程安全的,内部使用 synchronized 进行同步


4 字符串常量池(String Pool)

字符串常量池(String Pool)保存着所有字符串字面量 (literal strings),这些字面量在编译时期就确定 。不仅如此,还可以使用 String 的 intern() 方法在运行过程中将字符串添加到 String Pool 中。 当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等( 使 用 equals() 方法进行确定 ),那么就会返回String Pool中字符串的引用 ;否则,就会在 String Pool 中添加一个新的字符串,并返回这个新字符串的引用。

下面示例中, s1 和 s2 采用 new String() 的方式新建了两个不同字符串,而 s3 和 s4 是通过 s1.intern() 方法取得一个字符串引用。 intern() 首先把 s1 引用的字符串放到 String Pool 中,然后返回这个字符串引用。因此 s3 和 s4 引用的是同一个字符串。

2523055801d8428ca636d62c09979330.png

 如果是采用”bbb” 这种字面量的形式创建字符串,会自动地将字符串放入 String Pool 中。

52c50589e90849efa186197837a3d9a8.png


5 new String

使用这种方式一共会创建两个字符串对象(前提是 String Pool 中还没有 “abc” 字符串对象)。
● “abc” 属于字符串字面量,因此编译时期会在String Pool中创建一个字符串对象 ,指向这个 “abc” 字符串字面量;
● 而使用 new 的方式会在堆中创建一个字符串对象。
创建一个测试类,其main 方法中使用这种方式来创建字符串对象。
如果是直接赋值的,String s = “abc”。那么就会先去字符串常量池看看,如果有,就直接赋值
没有就在字符串常量池中创建一个再赋值。但是 new出来的是不会入池的,想要入池还要用到
intern方法。(intern 是一个native方法(Native方法指:底层使用C++实现的,看不到其实现的源代码),该方法的作用是手动将创建的String对象添加到常量池中

以下是 String 构造函数的源码,可以看到, 在将一个字符串对象作为另一个字符串对象的构造函数参数时,并不会完全复制 value 数组内容,而是都会指向同一个 value 数组 。

bec4d4978e074574bf92db6a710df2b0.png

String类中两种对象实例化的区别
JDK1.8中:
1.
String str = “hello”
只会开辟一块堆内存空间,保存在字符串常量池中,然后str共享常量池中的String对象
 
2.
String str = new String(“hello”)
会开辟两块堆内存空间,字符串”hello”保存在字符串常量池中,然后用常量池中的String对象给新开辟的String对象赋值。
 
3.
String str = new String(new char[]{‘h’, ‘e’, ‘l’, ‘l’, ‘o’})
现在堆上创建一个String对象,然后利用copyof将重新开辟数组空间,将参数字符串数组中内容拷贝到 String对象中。

 


6 String 常用方法 

字符串构造
String
是引用类型,内部并不存储字符串本身
String类常用的构造方式以下三种:
public static void main(String[] args) { 
   // 使用常量串构造 
   String s1 = "hello bit"; 
   System.out.println(s1); 

   // 直接newString对象 
   String s2 = new String("hello bit"); 
   System.out.println(s1); 

   // 使用字符数组进行构造
   char[] array = {'h','e','l','l','o','b','i','t'}; 
   String s3 = new String(array); 
   System.out.println(s1); 
}

 

String对象的比较

1.
==
比较是否引用同一个对象
注意:对于内置类型,==比较的是变量中的值;对于引用类型==比较的是引用中的地址。
public static void main(String[] args) { 
  int a = 10; 
  int b = 20; 
  int c = 10; 

  // 对于基本类型变量,==比较两个变量中存储的值是否相同 
  System.out.println(a == b); // false 
  System.out.println(a == c); // true 

  // 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象 
  String s1 = new String("hello"); 
  String s2 = new String("hello"); 
  String s3 = new String("world"); 
  String s4 = s1; 
  System.out.println(s1 == s2); // false 
  System.out.println(s2 == s3); // false 
  System.out.println(s1 == s4); // true 
}
2.
boolean equals(Object anObject)
方法:按照字典序比较
字典序:字符大小的顺序
String类重写了父类Object中equals方法,Object中equals默认按照==比较,String重写equals方法后,按照如下规则进行比较,比如: s1.equals(s2)
public boolean equals(Object anObject) { 
  // 1. 先检测this 和 anObject 是否为同一个对象比较,如果是返回true 
  if (this == anObject) { 
  return true; 
  }

  // 2. 检测anObject是否为String类型的对象,如果是继续比较,否则返回false 
  if (anObject instanceof String) { 
  // 将anObject向下转型为String类型对象 
  String anotherString = (String)anObject; 
  int n = value.length; 

  
  // 3. this和anObject两个字符串的长度是否相同,是继续比较,否则返回false 
  if (n == anotherString.value.length) {
    char v1[] = value;
    char v2[] = anotherString.value; 
    int i = 0; 
    // 4. 按照字典序,从前往后逐个字符进行比较 
    while (n-- != 0) { 
      if (v1[i] != v2[i]) 
        return false; 
      i++; 
    }
    return true; 
   } 
 }
 return false; 
}
public static void main(String[] args) { 
  String s1 = new String("hello"); 
  String s2 = new String("hello"); 
  String s3 = new String("Hello"); 

  // s1、s2、s3引用的是三个不同对象,因此==比较结果全部为false 
  System.out.println(s1 == s2); // false 
  System.out.println(s1 == s3); // false 

  // equals比较:String对象中的逐个字符 
  // 虽然s1与s2引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true 
  // s1与s3引用的不是同一个对象,而且两个对象中内容也不同,因此输出false 
  System.out.println(s1.equals(s2)); // true 
  System.out.println(s1.equals(s3)); // false 
}

 

3. int compareTo(String s) 方法: 按照字典序进行比较

与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:
1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
public static void main(String[] args) { 
  String s1 = new String("abc"); 
  String s2 = new String("ac"); 
  String s3 = new String("abc"); 
  String s4 = new String("abcdef"); 
  System.out.println(s1.compareTo(s2)); // 不同输出字符差值-1 
  System.out.println(s1.compareTo(s3)); // 相同输出 0 
  System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3 
}
4. int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较

 

public static void main(String[] args) { 
  String s1 = new String("abc"); 
  String s2 = new String("ac"); 
  String s3 = new String("ABc"); 
  String s4 = new String("abcdef"); 
  System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1 
  System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0 
  System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3 
}

 字符串查找

方法
功能
char charAt(int index)
返回index位置上字符,如果index为负数或者越界,抛出
IndexOutOfBoundsException异常
int indexOf(int ch)
返回ch第一次出现的位置,没有返回-1
int indexOf(int ch, int
fromIndex)
从fromIndex位置开始找ch第一次出现的位置,没有返回-1
int indexOf(String str)
返回str第一次出现的位置,没有返回-1
int indexOf(String str, int
fromIndex)
从fromIndex位置开始找str第一次出现的位置,没有返回-1
int lastIndexOf(int ch)
从后往前找,返回ch第一次出现的位置,没有返回-1
int lastIndexOf(int ch, int
fromIndex)
从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返
回-1
int lastIndexOf(String str)
从后往前找,返回str第一次出现的位置,没有返回-1
int lastIndexOf(String str, int
fromIndex)
从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返
回-1

转化 

1.
数值和字符串转化
// 数字转字符串
String s1 = String.valueOf(1234);
 
// 字符串转数字
int data1 = Integer.parseInt(“1234”);
double data2 = Double.parseDouble(“12.34”);

2. 大小写转换

// 小写转大写
s1.toUpperCase();
// 大写转小写
s2.toLowerCase();

3.字符串转数组  

// 字符串转数组
char[] ch = s.toCharArray();
// 数组转字符串
String s2 = new String(ch);

4. 格式化

public static void main(String[] args) {
String s = String.format(“%d-%d-%d”, 2019, 9,14);
System.out.println(s);
}

字符串替换  

方法
功能
String replaceAll(String regex, String replacement)
替换所有的指定内容
String replaceFirst(String regex, String replacement)
替换首个内容

注意事项: 由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串.  

 

字符串拆分  

方法 功能
String[] split(String regex)
将字符串全部拆分
String[] split(String regex, int limit)
将字符串以指定的格式,拆分为limit组
注意事项:
1. 字符”|”,”*”,”+”都得加上转义字符,前面加上 “\\” .
2. 而如果是 “\” ,那么就得写成 “\\\\” .
3. 如果一个字符串中有多个分隔符,可以用”|”作为连字符

 示例: 多次拆分

 

String str = “name=zhangsan&age=18” ;
String[] result = str.split(“&”) ;
for (int i = 0; i < result.length; i++) {
String[] temp = result[i].split(“=”) ;
System.out.println(temp[0]+” = “+temp[1]);
}
字符串截取
方法 功能
String substring(int beginIndex)
从指定索引截取到结尾
String substring(int beginIndex, int endIndex)
截取部分内容
1. 索引从0开始
2. 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标

 

其他操作方法  

方法 功能
String trim()
去掉字符串中的左右空格,保留中间空格
String toUpperCase()
字符串转大写
String toLowerCase()
字符串转小写

 

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/94629.html

(0)
小半的头像小半

相关推荐

极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!