String类


文章目录

  • String类
  • 1. 创建字符串
  • 2. 字符串比较相等
  • 3. 字符串常量池
  • 4. 字符串不可变
  • 5. 字符,字节,字符串
  • 5.1 字符与字符串
  • 5.2 字节与字符串
  • 5.3 小结
  • 6. 字符串常见操作
  • 6.1 字符串比较
  • 6.2 字符串查找
  • 6.3 字符串替换
  • 6.4 字符串拆分
  • 6.5 字符串截取
  • 6.6 其他操作方法
  • 7. StringBuffer 和 StringBulider


1. 创建字符串

常见的构造String的方式

//方式一
String str = "hello";
//方式二
String str2 = new String("hello");
//方式三
char [] array = {'a','b','c'};
Strin str3 = new String(array);

注意事项

  • "hello"这样的字符串字面常量,类型也是String
  • String是引用类型,String str = “hello”; 这样的代码内存布局如下

java拆分字符串成集合 java string拆分_System

str1 = "world";
System.out.println(str2);
//执行结果
hello

修改str1之后,str2没有发生变化,实际上,str1 = “wordl” 是将str1这个引用指向了一个新的对象

java拆分字符串成集合 java string拆分_字符串_02

2. 字符串比较相等

两个int型变量,判断其相等可以使用==完成

int x = 10;
int y = 10;
System.out.println(x==y);
//执行结果
true

String类对象上使用== ?代码1:

String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);
//执行结果
true

代码2:

String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2);
//执行结果
false

分析两种创建String方式的差异

代码1:

java拆分字符串成集合 java string拆分_字符串常量池_03

str1 和 str2 是指向同一个对象的,此时像"hello" 这样的字符串常量实在字符串常量池

字符串常量池:如 “Hello” 这样的字符串字面值常量, 也是需要一定的内存空间来存储的. 这样的常量具有一个特点, 就是不需要修改(常量). 所以如果代码中有多个地方引用都需要使用 “Hello” 的话, 就直接引用到常量池的这个位置就行了, 而没必要把 “Hello” 在内存中存储两次.

代码2:

java拆分字符串成集合 java string拆分_java_04

通过 String str1 = new String(“Hello”); 这样的方式创建的 String 对象相当于再堆上另外开辟了空间来存储"Hello" 的内容, 也就是内存中存在两份 “Hello”

String 使用 == 比较并不是在比较字符串内容, 而是比较两个引用是否是指向同一个对象

Java 中要想比较字符串的内容, 必须采用String类提供的equals方法

String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1.equals(str2));
//执行结果
true

equals使用注意事项

String str = new String("Hello");
// 方式一
System.out.println(str.equals("Hello"));
// 方式二
System.out.println("Hello".equals(str));

str如果是null,那方式一的代码会抛异常,方式二不会

注意事项: “Hello” 这样的字面值常量, 本质上也是一个 String 对象, 完全可以使用 equals 等 String 对象的方法.

3. 字符串常量池

  • 直接赋值
String str1 = "hello" ;//存入字符串常量池,
String str2 = "hello" ;//检查字符串常量池中是否有hello,如果有就直接引用这个hello
String str3 = "hello" ; 
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // true
System.out.println(str2 == str3); // true

如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中.如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用

  • 采用构造方法
String str = new String("hello");

这样会在堆上开辟新的内存空间,不会进入字符串常量池

我们可以使用 String 的 intern 方法来手动把 String 对象加入到字符串常量池中

// 该字符串常量并没有保存在字符串常量池之中
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

String类中两种对象实例化的区别

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

4. 字符串不可变

字符串是一种不可变对象. 它的内容不可改变.
String 类的内部实现也是基于 char[] 来实现的, 但是 String 类并没有提供 set 方法之类的来修改内部的字符数组.

String str = "hello" ; 
str = str + " world" ; 
str += "!!!" ; 
System.out.println(str); 
// 执行结果
hello world!!!

形如 += 这样的操作, 表面上好像是修改了字符串,实际上并不是String对象本身发生了改变,而是str引用指向了其他的对象

5. 字符,字节,字符串

5.1 字符与字符串

字符串内部包含一个字符数组,String 可以和 char[] 相互转换.

方法名称

类型

描述

public String(char vlaue[])

构造

将字符数组中的所有内容变为字符串

public String(char value[],int offset,int count)

构造

将部分字符数组中的内容变为字符串

public char charAt(int index)

普通

取得指定索引位置的字符,索引从0开始计算

public char[] toCharArray()

普通

将字符串变为字符数组返回

代码示例

public static void main(String[] args) {
    char [] val = {'a','b','c','d','e'};//将字符数组转成字符串
	String str = new String(val);
	System.out.println(str);
	String str1 = new String(val,1,3);//偏移量从0开始记,
	System.out.println(str1);//这里是把偏移量1到3的字符转成字符串
	System.out.println("==========================");
	String str2 = "hello";
	char ch = str2.charAt(1);//获取字符串1下标的字符
	System.out.println(ch); //打印e
	char [] chars = str2.toCharArray();//把str2指向的字符串对象 ,转成字符数组
	System.out.println(Arrays.toString(chars));
	}
//执行结果
abcde
bcd
==========================
e
[h, e, l, l, o]

给定字符串一个字符串, 判断其是否全部由数字所组成

public static void main(String[] args) {
    String str = "123456798";
    System.out.println(isNumber(str)?"字符串由数字组成":"字符串有非数字成员");
}
public static boolean isNumber(String str){
    char[] data = str.toCharArray();
    for (int i = 0; i < data.length; i++) {
        if(data[i] < '0' || data[i] > '9'){
            return false;
        }
    }
    return true;
}
//执行结果
字符串由数字组成

5.2 字节与字符串

字节常用于数据传输以及编码转换的处理之中,String 也能方便的和 byte[] 相互转换

方法名称

类型

描述

public String(byte bytes[])

构造

将字节数组转成字符串

public String(byte bytes[],int offset,int length)

构造

将部分字节数组中的内容转成字符串

public byte[] getBytes()

普通

将字符串以字节数组的形式返回

代码示例:实现字符串与字节数组的转换

public static void main(String[] args) {
        String str = "helloworld";
        byte [] bytes = str.getBytes();
        for (int i = 0; i < bytes.length; i++) {
            System.out.print(bytes[i]+ " ");
        }
        System.out.println();
        System.out.println(new String(bytes));
    }
//执行结果
104 101 108 108 111 119 111 114 108 100 
helloworld

5.3 小结

  • byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合
    针对二进制数据来操作.
  • char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候

6. 字符串常见操作

6.1 字符串比较

方法名称

类型

描述

public boolean equal(Object anObject)

普通

区分大小写的比较

public boolean equalsIgnoreCase(String anotherString)

普通

不区分大小写的比较

public int compareTo(String anotherString)

普通

比较两个字符串大小关系

代码示例

public static void main(String[] args) {
        String str = "hello";
        String str1 = "Hello";
        System.out.println(str.equals(str1));
        System.out.println(str.equalsIgnoreCase(str1));
    }
//执行结果
false
true

在String类中compareTo()方法是一个非常重要的方法,该方法返回一个整型,该数据会根据大小关系返回三类内容:

  1. 相等:返回0.
  2. 小于:返回内容小于0.
  3. 大于:返回内容大于0。
System.out.println("A".compareTo("a")); // -32 
System.out.println("a".compareTo("A")); // 32 
System.out.println("A".compareTo("A")); // 0 
System.out.println("AB".compareTo("AC")); // -1 
System.out.println("刘".compareTo("杨"));

compareTo()是一个可以区分大小关系的方法,是String方法里是一个非常重要的方法。
字符串的比较大小规则, 总结成三个字 “字典序” 相当于判定两个字符串在一本词典的前面还是后面. 先比较第一个字符的大小(根据 unicode 的值来判定), 如果不分胜负, 就依次比较后面的内容

6.2 字符串查找

方法名称

类型

描述

public boolean contains(CharSequence s)

普通

判断一个子字符串是否存在

public int indexOf(String str)

普通

从头开始查找指定字符串的位置,查到了返回位置的开始索引,如果查不到返回-1

public int indexOf(String str,int fromIndex)

普通

从指定位置开始查找子字符串位置

public int lastIndexOf(String str)

普通

从后向前查找子字符串的位置

public int lastIndexOf(String str,int fromIndex)

普通

从指定位置从后向前查找

public boolean startsWith(String prefix)

普通

判断是否以指定字符串开头

public boolean startsWith(String prefix,int toffset)

普通

从指定位置开始判断是否以指定字符串开头

public boolean endsWith(String suffix)

普通

判断是否以指定字符串结尾

代码示例

public static void main(String[] args) {
        String str = "helloworld";
        String str1 = "world";
        System.out.println(str.contains(str1));//判断字符串str1在str中是否存在
        System.out.println(str.indexOf(str1));
    //从头开始找str1的位置,找到返回str1开始的索引 5
        System.out.println(str.indexOf(str1,6));//从6位置开始找world 找不到
        System.out.println(str.lastIndexOf(str1));//从后向前找
        System.out.println(str.lastIndexOf(str1,3));//从倒数第三个位置开始找,找不到
        System.out.println(str.startsWith(str1));//判断是否以str1字符串开头
        System.out.println(str.startsWith(str1,5));
    //从偏移量为5的位置开始,判断是否以str1字符串开头
        System.out.println(str.endsWith(str1));//判断是否以str1字符串结尾
    }

6.3 字符串替换

方法名称

类型

描述

public String replaceAll(String regex,String replacement)

普通

替换所有的指定内容

public String replaceFirst(String regex,String replacement)

普通

替换首个内容

public static void main(String[] args) {
        String str = "helloworld";
        System.out.println(str.replaceAll("l","o"));//将所有的l替换成o
        System.out.println(str.replaceFirst("l","o"));//将第一个l替换成o
    }
//执行结果
heoooworod
heoloworld

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

6.4 字符串拆分

可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串

方法名称

类型

描述

public String [] split(String regex)

普通

将字符串完全拆分

public String [] split(String regex,int limit)

普通

将字符串拆分,该数组长度就是limit极限

代码示例:实现字符串的拆分处理

public static void main(String[] args) {
        String str = "he llo wo rl d";
        String [] s = str.split(" ");//按空格拆分 定义一个String类型的数组s接收拆分出来的字符串
        for (String s1:s) {  //遍历s数组,打印出里面的字符串
            System.out.println(s1);
        }
    }
//执行结果
he
llo
wo
rl
d

代码示例:字符串的部分拆分

public static void main(String[] args) {
        String str = "hello world hello java";
        String [] s = str.split(" ",2);//按空格拆分,最多拆成2个,不是平均拆分
        for (String s1:s) {
            System.out.println(s1);
        }
    }
//执行结果
hello
world hello java

注意事项:有些特殊字符作为分隔符可能无法正确切分,需要加上转义

代码示例:拆分IP地址

public static void main(String[] args) {
        String str = "192.168.1.1" ;
        String[] result = str.split("\\.") ;
        for(String s: result) {
            System.out.println(s);
        }
    }
//执行结果
192
168
1
1

注意事项

  1. 字符"|“,”*“,”+“都得加上转义字符,前面加上”\".
  2. 而如果是"“,那么就得写成”\\".
  3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符

代码示例:多次拆分

public static void main(String[] args) {
        String str = "name=zhangsan&age=18" ;
        String[] result = str.split("&") ;
        for (int i = 0; i < result.length; i++) {
            String[] temp = result[i].split("=") ;
            for (String s:temp) {
                System.out.println(s);
            }
        }
    }
//执行结果
name
zhangsan
age
18

6.5 字符串截取

从一个完整的字符串之中截取出部分内容。可用方法如下:

方法名称

普通

描述

public String substring(int beginIndex)

普通

从指定索引截取到结尾

public String substring(int beginIndex,int endIndex)

普通

截取部分内容

public static void main(String[] args) {
        String str = "helloworld";
        System.out.println(str.substring(5));//从偏移量为5的位置截取到结尾
        System.out.println(str.substring(2,5));//从偏移量为2的位置开始截取到偏移量为5的位置
    }

注意事项

  1. 索引从0开始
  2. 注意前闭后开区间的写法, substring(2, 5) 表示包含 2 号下标的字符, 不包含 5 号下标

6.6 其他操作方法

方法名称

类型

描述

public String trim()

普通

去掉字符串中的左右空格,保留中间的空格

public String toUpperCase()

普通

字符串转大写

public String toLowerCase()

普通

字符串转小写

public native String intern()

普通

字符串入池操作

public String concat(String str)

普通

字符串连接,相当于"+",拼接后的字符串不入池

public int length()

普通

取得字符串的长度

public boolean isEmpty()

普通

判断是否为空字符串,不是null,而是长度为0

代码示例:trim()

public static void main(String[] args) {
    String str = "  hello  world   ";
    System.out.println(str.trim());
    String s = "   hello  world  ";
    System.out.println("[" + s + "]");
    System.out.println(s.trim());
}
//执行结果
hello  world
[   hello  world  ]
hello  world

代码示例:大小写转换,字符串连接

public static void main(String[] args) {
    String str = "abc";
    System.out.println(str.toUpperCase());
    String s = "ABC";
    System.out.println(s.toLowerCase());
    System.out.println(str.concat(s));
    }
//执行结果
ABC
abc
abcABC

代码示例:length() ,isEmpty()

public static void main(String[] args) {
    String str = "hello hhhh 哈哈";
    System.out.println(str.length());
    System.out.println(str.isEmpty());
    System.out.println("".isEmpty());
    System.out.println(new String().isEmpty());
}
//执行结果
13
false
true
true

7. StringBuffer 和 StringBulider

任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指向而已。
通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer和StringBuilder类。
StringBuffer 和 StringBuilder 大部分功能是相同的,
在String中使用"+"来进行字符串连接,但是这个操作在StringBuffer类中需要更改为append()方法:

public class Test{ 
    public static void main(String[] args) { 
        StringBuffer sb = new StringBuffer();
        sb.append("Hello").append("World"); 
        fun(sb); 
        System.out.println(sb); 
    }
    public static void fun(StringBuffer temp) {
        temp.append("\n").append("HelloJava");
    } 
}

String和StringBuffer最大的区别在于:String的内容无法修改,而StringBuffer的内容可以修改。频繁修改字符串的情况考虑使用StingBuffer

注意:String和StringBuffer类不能直接转换。如果要想互相转换,可以采用如下原则:
String变为StringBuffer:利用StringBuffer的构造方法或append()方法
StringBuffer变为String:调用toString()方法。

除了append()方法外,StringBuffer也有一些String类没有的方法:

  • 字符串反转
StringBuffer sb = new StringBuffer("helloworld"); 
System.out.println(sb.reverse()); 
//执行结果
dlrowolleh
  • 删除指定范围的数据
StringBuffer sb = new StringBuffer("helloworld"); 
System.out.println(sb.delete(5, 10));
//执行结果
hello
  • 插入数据
StringBuffer sb = new StringBuffer("helloworld"); 
System.out.println(sb.delete(5, 10).insert(0, "你好")); 
//执行结果
你好hello

String、StringBuffer、StringBuilder的区别

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