Java学习苦旅(十四)——String

本篇博客将详细讲解java中的String类。

文章目录

  • 创建字符串
    • 常见的构造String的方式
  • 常量池
  • 字符串比较
  • 理解字符串不可变
  • 字符、字节与字符串
    • 字符与字符串
      • 将字符合并为字符串
      • 获取字符串中的某个字符
      • 将字符数组中部分字符合并成字符串
      • 将字符串转换为字符
      • 判断字符串是否由数字构成
    • 字节与字符串
      • 实现字符串与字节数组的转换
      • 编码转换处理
    • 小结
  • 字符串常见操作
    • 字符串比较
    • 字符串查找
    • 字符串替换
    • 字符串拆分
    • 字符串截取
    • 其他操作方法
  • StringBuffer和StringBuilder
  • 结尾

创建字符串

常见的构造String的方式

//方式一
String str = "hello";

//方式二
String str1 = new String("Hello");

//方式三
char[] array = {'a', 'b', 'c'};
String str2 = new String(array);

注意:

  • "hello"这样的字符串字面值常量,类型也是String。
  • String也是引用类型。

我们来看下面这段代码:

public class TestDemo {
    public static void func(String s, char[] array) {
        s = "abc";
        array[0] = 'x';
    }

    public static void main(String[] args) {
        String str = "aaa";
        char[] chars = {'b','b','c','c'};
        func(str, chars);
        System.out.println(str);
        System.out.println(Arrays.toString(chars));
    }
}

这段代码的结果为:

Java学习苦旅(十四)——String_第1张图片

为什么会出现这样的结果呢?我们来看看这段代码的内存图。

Java学习苦旅(十四)——String_第2张图片

所以才会上述的结果。

常量池

常量池一般有三类:Class文件常量池、运行时常量池和字符串常量池。

Class文件常量池:用于存放编译器生成的各种字面量和符号引用。

运行时常量池:当程序把编译好的字节码文件,加载到JVM当中后会生成一个运行时常量池。运行时常量池是存放在方法区当中的。

字符串常量池:主要存放字符串常量,本质上是一个哈希表。

字符串比较

在Java中,比较两个字符串是否相等,一般使用String类提供的equals方法。例如:

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

执行结果为:

Java学习苦旅(十四)——String_第3张图片

注意:

如果出现下面这样的代码,那么就会报错:

String str1 = null;
String str2 = new String("hello");
System.out.println(str1.equals(str2));

执行结果为:

Java学习苦旅(十四)——String_第4张图片

理解字符串不可变

我们先来看这样一段代码:

String str = "hello";
str = str + " world";
str += "!!!";
System.out.println(str);

执行结果为:

Java学习苦旅(十四)——String_第5张图片

这段代码,表明上好像是修改了字符串,但实际上并不是,而是创建了五个变量:

Java学习苦旅(十四)——String_第6张图片

如果实在是想修改字符串,可以这样做:

String str = "hello";
str = "a" + str.substring(1);
System.out.println(str);

执行结果为:

Java学习苦旅(十四)——String_第7张图片

当然,也可以使用反射的方法去修改:

String str = "hello";
// 获取 String 类中的 value 字段. 这个 value 和 String 源码中的 value 是匹配的.
Field valueField = String.class.getDeclaredField("value");
// 将这个字段的访问属性设为 true
valueField.setAccessible(true);
// 把 str 中的 value 属性获取到.
char[] value = (char[]) valueField.get(str);
// 修改 value 的值
value[0] = 'a';
System.out.println(str);

执行结果为:

Java学习苦旅(十四)——String_第8张图片

为什么 String 要不可变?

  1. 方便实现字符串对象池。如果 String 可变,那么对象池就需要考虑何时深拷贝字符串的问题了。

  2. 不可变对象是线程安全的。

  3. 不可变对象更方便缓存 hash code,作为 key 时可以更高效的保存到 HashMap 中。

字符、字节与字符串

字符与字符串

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

No 方法名称 类型 描述
1 public String(char value[]) 构造 将字符数组中所有内容变为字符串
2 public String (char value[], int offset, int count) 构造 将部分字符数组中的内容变为字符串
3 publilc char charAt(int index) 普通 取得指定索引位置的字符,索引从0开始
4 public char[] toCharArray() 普通 将字符串变为字符数组返回

代码示例:

将字符合并为字符串

char[] value = {'a','b','c','d','e'};
String str = new String(value);
System.out.println(str);

执行结果为:

Java学习苦旅(十四)——String_第9张图片

获取字符串中的某个字符

String str = "abcdef";
char val = str.charAt(3);
System.out.println(val);

执行结果为:

Java学习苦旅(十四)——String_第10张图片

将字符数组中部分字符合并成字符串

char[] value = {'a','b','c','d','e'};
String str = new String(value,1,3);
System.out.println(str);

执行结果为:

Java学习苦旅(十四)——String_第11张图片

将字符串转换为字符

String str = "abcdef";
char[] chars = str.toCharArray();
System.out.println(Arrays.toString(chars));

执行结果为:

Java学习苦旅(十四)——String_第12张图片

判断字符串是否由数字构成

public static void main(String[] args) {
    String str = "123a456";
    System.out.println(isNumber(str));
}

public static boolean isNumber(String s) {
    for (int i = 0; i < s.length(); i++) {
        char c = s.charAt(i);
        if (c < '0' || c > '9') {
            return false;
        }
    }
    return true;
}

执行结果为:

Java学习苦旅(十四)——String_第13张图片

字节与字符串

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

No 方法名称 类型 描述
1 public String(byte bytes[]) 构造 将字节数组变为字符数组
2 public String(byte bytes[], int offset, int length) 构造 将部分字节数组中的内容变为字符串
3 public byte[] getBytes() 普通 将字符串以字节数组的形式返回
4 public byte[] getBytes(String charsetName)throws UnsupportedEncodingException 普通 编码转换处理

代码示例:

实现字符串与字节数组的转换

byte[] bytes = {97,98,99,100,101,102};
String str = new String(bytes);
System.out.println(str);
System.out.println("========================");
String str2 = "abcdefg";
byte[] bytes1 = str2.getBytes();
System.out.println(Arrays.toString(bytes1));

执行结果为:

Java学习苦旅(十四)——String_第14张图片

编码转换处理

String str2 = "你好";
byte[] bytes1 = str2.getBytes("utf-8");
System.out.println(Arrays.toString(bytes1));

执行结果为:

Java学习苦旅(十四)——String_第15张图片

小结

byte[] 是把 String 按照一个字节一个字节的方式处理,这种适合在网络传输,数据存储这样的场景下使用,更适合针对二进制数据来操作。

char[] 是把 String 按照一个字符一个字符的方式处理,更适合针对文本数据来操作,尤其是包含中文的时候。

字符串常见操作

字符串比较

No 方法名称 类型 描述
1 public boolean equals(Object anObject) 普通 区分大小写的比较
2 public boolean equalsIgnoreCase(String anotherString) 普通 不区分大小写的比较
3 public int compareTo(String anotherString) 普通 比较两个字符串大小关系

代码示例:

String str1 = "hello";
String str2 = "HELLO";
System.out.println(str1.equals(str2));
System.out.println(str1.equalsIgnoreCase(str2));
System.out.println(str1.compareTo(str2));

运行结果为:

Java学习苦旅(十四)——String_第16张图片

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

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

字符串查找

No 方法名称 类型 描述
1 public boolean contains(CharSequence s) 普通 判断一个子字符串是否存在
2 public int indexOf(String str) 普通 从头开始查找指定字符串的位置,查到了返回位置的开始索引,如果查不到返回-1
3 public int indexOf(String str, int fromIndex) 普通 从指定位置开始查找子字符串位置
4 public int lastIndexOf(String str) 普通 由后向前查找子字符串位置
5 public int lastIndexOf(String str, int fromIndex) 普通 从指定位置由后向前查找
6 public boolean startsWith(String prefix) 普通 判断是否以指定字符串开头
7 public boolean startsWith(String prefix, int toffset) 普通 从指定位置开始判断是否以指定字符串开头
8 public boolean endsWith(String suffix) 普通 判断是否以指定字符串结尾

代码示例:

String str1 = "abcdefabcdef";
String str2 = "bcd";
System.out.println(str1.contains(str2));
System.out.println(str1.indexOf(str2,3));
System.out.println(str1.lastIndexOf(str2));
System.out.println(str1.startsWith("abba"));
System.out.println(str1.endsWith("ef"));

执行结果为:

Java学习苦旅(十四)——String_第17张图片

字符串替换

No 方法名称 类型 描述
1 public String replaceAll(String regex, String replacement) 普通 替换所有的指定内容
2 public String replaceFirst(String regex, String replacement) 普通 替换首个内容

代码示例:

String str1 = "abcabcabcddee";
System.out.println(str1.replace('a','x'));
System.out.println(str1.replace("ab","xy"));
System.out.println(str1.replaceAll("abc","y"));
System.out.println(str1.replaceFirst("abc","pppp"));

执行结果为:

Java学习苦旅(十四)——String_第18张图片

字符串拆分

No 方法名称 类型 描述
1 public String[] split(String regex) 普通 将字符串全部拆分
2 public String[] split(String regex, int limit) 普通 将字符串部分拆分,该数组长度就是limit极限

代码示例:

String str = "name=zhangsan&age=19";
String[] strings = str.split("&");
for (String s:strings) {
    System.out.println(s);
}
System.out.println("=================================");
for (String s:strings) {
    String[] ss = s.split("=");
    for (String tmp:ss) {
        System.out.println(tmp);
    }
}

执行结果为:

Java学习苦旅(十四)——String_第19张图片

注意事项:

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

例如:

String str = "192.68.1.1";
String[] strings = str.split("\\.");
for (String s:strings) {
    System.out.println(s);
}
System.out.println("==========================");
String str1 = "192.68.1.1";
String[] strings1 = str1.split("\\.",3);
for (String s:strings1) {
    System.out.println(s);
}
System.out.println("++++++++++++++++++++++++++");
String string = "java30 12&21#hello";
String[] strings2 = string.split(" |&|#");
for (String s:strings2) {
    System.out.println(s);
}

执行结果为:

Java学习苦旅(十四)——String_第20张图片

字符串截取

No 方法名称 类型 描述
1 public String substring(int beginIndex) 普通 从指定索引截取到结尾
2 public String substring(int beginIndex, int endIndex) 普通 截取部分内容

注意事项:

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

代码示例:

String str = "abcdefg";
System.out.println(str.substring(5));
System.out.println(str.substring(2,6));

执行结果为:

Java学习苦旅(十四)——String_第21张图片

其他操作方法

No 方法名称 类型 描述
1 public String trim() 普通 去掉字符串中的左右空格,保留中间空格
2 public String toUpperCase() 普通 字符串转大写
3 public String toLowerCase() 普通 字符串转小写
4 public native String intern() 普通 字符串入池操作
5 public String concat(String str) 普通 字符串连接,等同于“+”,拼接之后的对象不入池
6 public int length() 普通 取得字符串长度
7 public boolean isEmpty() 普通 判断是否为空字符串,但不是null,而是长度为0

StringBuffer和StringBuilder

首先来回顾下String类的特点:

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

我们先来看一下StringBuilder,

sb.append("abcdef");
sb.append("123");
System.out.println(sb);
System.out.println("========================");
System.out.println(sb.reverse());

运行结果为:

Java学习苦旅(十四)——String_第22张图片

注意:String和StringBuffer类不能直接转换。如果要想互相转换,可以采用如下原则:

  • String变为StringBuffer:利用StringBuffer的构造方法或append()方法。

  • StringBuffer变为String:调用toString()方法。

例如:

public static StringBuilder func() {
    String str = "abcd";
    return new StringBuilder(str);
}

public static String fun() {
    StringBuilder sb = new StringBuilder();
    return sb.toString();
}

String、StringBuffer、StringBuilder的区别:

  • String的内容不可修改,StringBuffer与StringBuilder的内容可以修改。

  • StringBuffer与StringBuilder大部分功能是相似的。

  • StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作。

结尾

本篇博客到此结束。
上一篇博客:Java学习苦旅(十三)——多态
下一篇博客:Java学习苦旅(十五)——异常

你可能感兴趣的:(Java学习苦旅,java,开发语言,后端)