Java核心类(1 - String)

String类

在Java中,String是一个引用类型,它本身也是一个class。但是,Java编译器对String有特殊处理,即可以直接用"..."来表示一个字符串:

String s = "HelloWorld!";

实际上,字符串在String内部是通过一个char[]数组表示的,因此下列写法也是正确的:

String s = new String(new char[]{'H','w','l','l','o','!'});

Java字符串一个重要特点就是字符串不可变。这种不可变是通过内部的private final char[]字段,以及没有任何修改char[]的方法实现的。

String s = "abcd";
System.out.println(s);
s="1234";
System.out.println(s);

输出:
abcd
1234

从上述结果可以看出s的值确实改变了,那么为什么还说String对象是不可改变的呢?s只是一个String对象的引用,并不是对象本身、引用只是一个4字节的数据,里面存放了它所指的对象地址,通过这个地址可以访问对象。
一开始,s指向"abcd"这个具体的对象,当s="1234"这句代码执行过后,内存中新开辟出一段空间存字符串"1234",然后s指向这个新字符串,而原字符串"abcd"在内存中依旧存在,并未改变。

下面的只是一些常用的String类方法,如果想要详细了解String类,可以参考Java官方文档:
https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/lang/String.html

字符串比较

当我们想比较两个字符串内容是否相等,我们必须要使用equals()方法,而不能使用==

public class Main{
    public static void main(String[] args) {
        String s1 = "Hello";
        String s2 = "Hello";
        System.out.println(s1==s2);
        System.out.println(s1.equals(s2));
    }
}

true
true

从表面上看,两个字符串用==equals()比较都为true,但实际上那只是因为Java编译器在编译期,会自动的把所有相同的字符串当做一个对象放入常量池,自然s1s2的引用就是相等的。
所以,这种==比较返回true纯属巧合,换一种写法就会出错,比如:

public class Main{
    public static void main(String[] args) {
        String s1 = "HELLO";
        String s2 = "hello".toUpperCase();
        System.out.println(s1==s2);
        System.out.println(s1.equals(s2));
    }
}

输出:
flase
true
可以看出,两个字符串比较,必须使用equals()方法。
要忽略大小写比较,可以使用equalsIgnoreCase()方法。

下面总结一些String类常用的方法:

注意:索引号是从0开始的

包含子串

//查看是否包含子串
"Hello".contains("ll");   //  true

contains()方法的参数是CharSequence而不是String,因为CharSequenceString的父类。

搜索子串

//查找字符串第一次出现的位置(索引)
"Hello".indexof("l");   //  2

//查找字符串最后一次出现的位置(索引)
"Hello".lastIndexof("l");   //  3

//检查原字符串是否是以字符串a开始的
"Hello".startsWith("He");   //   true

//检查原字符串是否是以字符串b结尾的
"Hello".sendsWith("lo");   //   true

提取子串

"Hello".substring(2);  //   "llo"  截取索引号2及以后的字符串
"Hello".substring(2,4); //    "ll" 截取索引号2到4(不含4)的字符串

去除首尾空白字符

//使用trim()可以去除首尾空白字符(空格,\t,\r,\n)
"\r \tHello\n   ".trim(); //   "Hello"  

//使用strip()除了可以去除首尾空白字符,还可以去除类似中文的空格字符\u3000
"\u3000\r \tHello\n  \u3000 ".strip(); //   "Hello"

判断是否为空或空白字符串

"".isEmpty(); //true , 因为字符串的长度为0
"   ".isEmpty();  //false , 因为字符串的长度不为0
"   \n".isBlank();  //true , 因为该字符串只包含空白字符
"Hello \n".isBlank(); //false	 , 因为该字符串包含非空白字符

替换子串

String s = "Hello";
System.out.println(s.replace("l","w"));
System.out.println(s.replace("ll","~~"));

输出:
Hewwo
He~~o

分割字符串

public class Main{
    public static void main(String[] args) {
        String s = "A,B,C,D";
        String[] ss = s.split("\\,"); //{"A","B","C","D"} 正则表达式
        for(String a:ss){
            System.out.println(a);
        }
    }
}

输出:
A
B
C
D

拼接字符串

String[] arr = {"A","B","C"};
String s= String.join("***",arr); //  "A***B***C"

格式化字符串

public class Main{
    public static void main(String[] args) {
        String s = "Hello %s, your score is %d!";
        System.out.println(s.formatted("Bob",100));
        System.out.println(String.format("Hello %s, your score is %d!","Alan",78));
    }
}

输出:
Hello Bob, your score is 100!
Hello Alan, your score is 78!

formatted()方法从JDK13开始提供

常用的占位符:

  • %s:显示字符串,不确定用啥占位符就始终用%s,它可以显示任何数据类型;
  • %d:显示整数;
  • %x:显示十六进制整数;
  • %f:显示浮点数,%.2f表示显示两位小数。

类型转换

要把任意基本数据类型或引用类型转换为字符串,可以使用静态方法valueOf()。这是一个重载方法,编译器会根据参数自动选择合适的方法:

String.valueOf(123); //"123"
String.valueOf(154.34); //"154.34"
String.valueOf(true); //"true"
String.valueOf(new Object()); //类似java.lang.Object@4c873330

要把字符串转换为其他类型,就需要根据情况。例如,把字符串转换为int类型:

int n1 = Integer.parseInt("123"); // 123
int n2 = Integer.parseInt("ff",16); //按十六进制转换,255

把字符串转换为boolean类型:

boolean a = Boolean.parseBoolean("true");  //true
boolean b = Boolean.parseBoolean("FALSe");  //false

parseBoolean()方法是无视字符串的大小写的,因为他的函数体是return "true".equalsIgnoreCase(s);

转化为char[]

Stringchar[]类型可以互相转换,方法是:

char[] s1 = "Hello".toCharArray(); // String -> char[]
String s2 = new String (s1);  // char[] -> String

StringBuilder

Java编译器对String做了特殊处理,使得我们可以直接使用+进行拼接字符串。例如:

public class Main{
    public static void main(String[] args) {
        String s = "";
        for(int i=0;i<10;i++)
            s=s+","+i;
        System.out.println(s);
    }
}

输出:
,0,1,2,3,4,5,6,7,8,9

但是这样直接进行拼接字符串是低效的,在每次循环中,都会创建新的字符串对象,然后扔掉旧的字符串对象,这个就是之前讲过的字符串的不可变性。这样,绝大多数字符串都是临时对象,不但浪费内存,还会影响GC效率。

拓展:
GC:Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,在使用JAVA的时候,一般不需要专门编写内存回收和垃圾清理代 码。这是因为在Java虚拟机中,存在自动内存管理和垃圾清扫机制,可以自动清除无用对象。

为了高效拼接字符串,Java标准库提供了StringBuilder,他是一个可变对象,可以预分配缓冲区,这样往StringBuilder中新增字符时,不会创建新的临时对象:

public class Main{
    public static void main(String[] args) {
        StringBuilder Str = new StringBuilder();
        for(int i=0;i<10;i++){
            Str.append(",");
            Str.append(i);
        }
        String s = Str.toString();
        System.out.println(s);
    }
}

输出:
,0,1,2,3,4,5,6,7,8,9

StringBuilder还可以进行链式操作。

public class Main{
    public static void main(String[] args) {
        StringBuilder Str = new StringBuilder();
        for(int i=0;i<10;i++){
            Str.append(",")
                  .append(i);
        }
        System.out.println(Str);
    }
}

输出:
,0,1,2,3,4,5,6,7,8,9

如果我们查看StringBuilder源码,我们可以发现,进行链式操作的关键是,定义的append()方法会返回this,这样,就可以不断调用自身的其他方法。
StringBuilderappend()方法源码如下:

public StringBuilder append(String str) {
        super.append(str);
        return this;
    }

注意:对于普通的字符串+操作,并不需要我们将其改写为StringBuilder,因为Java编译器在编译时就自动将多个连续的+操作编码为StringConcatFactory的操作。在运行期,StringConcatFactory会自动把字符串连续操作优化为数组复制或者StringBuilder操作。

StringJoiner

可以使用StringJoiner方法来用分隔符拼接数组。

public class Main {
    public static void main(String[] args) {
        StringJoiner stringJoiner = new StringJoiner(",","Hello ","!");
        String[] names = {"Alan","Join","Mike"};
        for(String s : names){
            stringJoiner.add(s);
        }
        System.out.println(stringJoiner.toString());
    }
}

输出:
Hello Alan,Join,Mike!

StringJoiner(分解符,前缀,后缀)
如果不需要指定开头和结尾,那么可以使用String.join()

public class Main {
    public static void main(String[] args) {
        String[] names = {"Alan","Join","Mike"};
        String s = String.join(",",names);
        System.out.println(s);
    }
}

输出:
Alan,Join,Mike

String.join(分解符,字符串数组)

posted @ 2020-09-26 16:15  Cherish486  阅读(30)  评论(0编辑  收藏  举报