【Java SE】String类

Java SE中String类的介绍与使用

1. String类的介绍

String的应用场景非常多,也很实用,String给我们提供的功能也非常的丰富。那么String是什么呢?把一组字符(char)按照顺序串到一起就是字符串,而Java常常用""表示一个字符串,"hello","你好",Java的" "可以包含任意个字符。

相比之下,C中没有一个专门的“字符串”概念的,C的做法是使用char[]表示一个字符串。(最后一个字符,必须使用\0结尾)。

2. String的使用

2.1 构造String

构造一个String(创建一个String对象),有三种方法

public class Test1 {
    public static void main(String[] args) {
        //构造String对象
        //1. 直接通过字面值常量来构造
        String s1 = "hello";
        //2. 通过new的方式来构造,String也是类
        String s2 = new String("hello");
        //3. 通过字符数组来构造String
        char[] chars = {'h','e','l','l','o'};
        String s3 = new String(chars);
    }
}

Java中包名都是小写字母。字面值常量就是一见到字面就注定是常量的值,比如1,1.0,"hello"这种,String是标准库内置的类,使用这个类,不需要import,String类处于标准库中的java.lang这个包中。在Java中,更推荐使用第一种方法创建String,而不是new的方式。

第二种new String这样的做法,就需要从操作系统这里申请内存,并且创建字符串对象。而第一种方法,字符串常量池,直接String s1 = "hello",这样的时间开销会比上面的new的方法小很多。字符串常量池,是Java内置的机制,JVM运行时就会自动进行构造,不需要程序员来关注。常量池也不仅仅是只有"字符串常量”,还有一些其他的常量池。

2.2 String的内部实现

public class Test2 {
    public static void main(String[] args) {
//        String s1 = "abc";
//        String s2 = "abc";
//        // String 是引用类型, 使用 == 比较, 是判定两个引用保存的地址是否相同 (判定两个引用是否指向同一个对象)
//        System.out.println(s1 == s2); // true
        
        String s1 = new String("abc");
        String s2 = new String("abc");
        System.out.println(s1 == s2);  // false
    }
}

字符串常量值实际是StringTable类,实际是一个固定大小的HashTable

情况一:

 "abc”是字面值常量就会被放到JVM的字符串常量池中

 情况二:

把"abc"这个常量的每个字符,分别拷贝到两个String对象中。

3. String类的核心方法

这里介绍一些常用的,核心的方法,更多方法可以参考Java的官方文档(也可以直接看原码中的注释):Overview (Java SE 17 & JDK 17)

3.1 String对象的比较

①比较相等

1)两个String 引用,指向的对象是否是同一个==(学习语法印证下常量池的设定,实际开发中很少用)

2)两个String引用对应的对象,包含的字符内容是否是相同(equals),每个字符是否对应一致的

public class Test3 {
    public static void main(String[] args) {
        // 针对两个 String 引用来进行 equals
//        String s1 = "hello";
//        String s2 = new String("hello");
//        System.out.println(s1.equals(s2)); //true

//        // 也可以针对 String 字面值常量来 equals
//        String s = null;
//        // 这两个写法, 更推荐写成第二种写法;
//        System.out.println(s.equals("hello"));
//        System.out.println("hello".equals(s));

        String s1 = "hello";
        String s2 = "hello";
        System.out.println(s1.equals(s2));

    }
}

"hello"这个常量也是String类型,也可以使用访问String的各种方法

 推荐使用上面的这种写法。类似C语言的一个设定,if(10 == n) 以防写成if(n=10)

②比较大小关系

数字比较大小,很明确的规则,而字符串比较大小,则使用字典序(按照字母顺序排序)。

public class Test4 {
    public static void main(String[] args) {
        String s1 = "AAA";
        String s2 = "aaa";
        System.out.println(s1.compareTo(s2)); //-32
        System.out.println(s1.compareToIgnoreCase(s2)); //0
    }
}

abcd这些字符都是有对应的 ascii码值的,此处看到的-32,就是前一个字符串的第一个字符,减去后一个字符串的第一个字符的ascii,compareToIgnoreCase方法是忽略了大小写。

3.2 字符串查找

①charAt给定下标,获取到对应的字符.
②indexOf查找该字符串包含的某个子字符串,从左往右找
③lastlndexOf,也是查找子字符串,是从右往左找

①charAt

public class Test5 {
    public static void main(String[] args) {
        String s1 = "hello";
        System.out.println(s1.charAt(0));
        System.out.println(s1.charAt(1));
        System.out.println(s1.charAt(2));
        System.out.println(s1.charAt(3));
        System.out.println(s1.charAt(4));
//        System.out.println(s1.charAt(5));  //报错

        String s = "你好";
        System.out.println(s.charAt(0));
        System.out.println(s.charAt(1));
    }
}

注意:比较两个带有汉字的字符串的大小关系,如果只是比较相等/不等,当然ok,规则也一致~~,如果是比较"大于小于”,使用compareTo比较结果是无意义的。

②indexOf

把一个字符串其中的一部分拿出来,就可以称为"子串"。indexOf 就是在查找字符串中包含的子串(连续),查找指定的参数是否是该字符串的子串,如果是,是处于哪个位置。

public class Test6 {
    public static void main(String[] args) {
        String s1 = "abcdef";
        System.out.println(s1.indexOf("cdf"));  // -1
        String s = "abcabcabc";
        System.out.println(s.indexOf("abc"));  // 0
        System.out.println(s.lastIndexOf("abc")); // 6
    }
}

3.3 字符串的转换

①数字转换为字符串

 Java中String的拼接,+可以把其他类型,自动转换为String类型

 上面也是数字转换为字符串的方法

public class Test7 {
    public static void main(String[] args) {
//        int n = 10;
        double n = 10.5;

//        Boolean n = false;

        String s1 = "" + n;
        System.out.println(s1);

        String s2 = String.valueOf(n); // 数字转为字符串
        System.out.println(s2);
    }
}

②字符串转换为数字

String s = "10";
        int n = Integer.parseInt(s);
        System.out.println(s + 10);  //1010,而不是20
        System.out.println(n + 10); // 20

3.4 字符串转大小写

toUpperCase()转大写

toLowerCase()转小写

String s = "Hello";
        String s1 = s.toUpperCase();
        System.out.println(s1);
        String s2 = s.toLowerCase();
        System.out.println(s2);
        System.out.println(s);

【注意】此处的 toUpperCase 和toLowerCase都是只生成新的String,不修改本来的String。实际上,String 中的所有方法,都不会修改String本身,String这个对象,其实是一个“不可变对象",相当于"常量"。

3.5 字符串转数组

利用toCharArray()方法转为字符数组,或者利用getBytes()方法转为字节数组

        String s = "你好";
        //通过toCharArray转为字符数组
        char[] chars = s.toCharArray();
        for(char c : chars){
            System.out.println(c);
        }
        
        byte[] bytes = s.getBytes();
        for(byte b : bytes){
            System.out.printf("%x\n", b);
        }

String本身,就是按照byte[]的方式来存储的,字符,也是通过"字节"构成的。一个字节是8个二进制位(bit位),一个十六进制数字,正好就是4个bit位,一个字节,刚好是2个十六进制数字,如果按照二进制来打印,打出来的0101太多了,不方便看。按照十六进制打印,长度大幅度缩小,并且也很方便肉眼去换算到二进制。

汉字的编码方式有utf-8(一个汉字占3个字节)和utf-16(一个汉字占2个字节),而世界上最通用的编码方式是utf-8。

3.5 字符串格式化

int x = 10;
System.out.printf("x = %d\n", x);
String s = String.format("x = %d\n", x);
System.out.println(s);

构造格式化字符串,类似printf,format方法,就可以完成格式化创建字符串的操作。printf 只能打印,而String.format构造出来的字符串,不仅仅可以用来打印。

3.6 字符串替换

把字符串的一部分改成别的东西

String s = "大家今天过的很开心";
// replace 是替换所有的字符. 替换的结果是新的字符串.
String s2 = s.replace("大家","小红");
System.out.println(s);
System.out.println(s2);

3.7 字符串拆分

指定分隔符,把一个字符串,拆成多个部分,得到一个字符串数组~字符串拆分,是一个非常常见的场景,开发的时候,网络通信程序,网络上传输的都是"字符串"(二进制的串),但是通常发一次数据,就要携带多个信息。

        String s = "C++,Java,Python,C#,Javascript";
        String[] languages = s.split(",");
        for( String language : languages){
            System.out.println(language);
        }
        String s = "C++.Java.Python.C#.Javascript";
        String[] languages = s.split("\\.");
        for( String language : languages){
            System.out.println(language);
        }

 上面的‘.’是个正则表达式,针对.进行转义,可以通过\.表达原始的.。由于在Java的字符串常量中,要求\还需要被转义一下,所以需要\\。

3.8 字符串截取

字符串取子串,substring

从指定的位置截取到末尾或者是截取指定区间:[beg,end),前闭后开区间

        String s = "abcdefg";
        System.out.println(s.substring(2)); //cdefg
        System.out.println(s.substring(2, 4)); //cd
//        System.out.println(s.substring(2,8)); //越界报错
        // 虽然要求下标得是在合理范围, 但是 7 特殊. 取子串并不或访问 7 这个下标的元素.
        System.out.println(s.substring(2,7));

 3.9 去除两边的空格

        String s = "          \f      Hello World!      \n\t        ";
        String s2 = s.trim();
        System.out.println("[" + s + "]");
        System.out.println("[" + s2 + "]");

3.10 intern方法

intern()方法的作用就是手动把字符串添加到常量池中。而代码中写死的"hello"这种字符串常量,编译器编译期间就能都提出来,运行的时候直接把这些内容加到池子里,不需要程序员干预。

String类并没有提供任何一个public的,用来修改value 数组内容的方法。如果修改一个String,通常的做法就是创建一个新的String。String类不能被继承。

        String s = new String("Hello");
        // 此时 s2 的内容也是 "hello", 但是是指向常量池中的 "hello"
        String s2 = s.intern();
        System.out.println(s == "Hello");  //false
        System.out.println(s2 == "Hello");  //true

4. StringBuilder和StringBuffer 

String 不可变,StringBuilder 和StringBuffer可变。(优先使用StringBuilder),StringBuilder是新版本,StringBuffer是旧版本。

为啥要搞一个不可变的字符串,优先考虑使用不可变的字符串呢??计算机,更喜欢“不可变”的东西的,针对“不可变”可以做出一些优化手段,提高效率的。

String不可变优点
1.更方便的存储到"常量池"中了.

2.针对不可变的String,可以更好的计算 hash值(数据结构,哈希表的时候,详细展开)

3.天然线程安全(JavaEE初阶详细解释)

// Java 中提供的 "不可变的字符串"
        long beg = System.currentTimeMillis();
        String s = "hello";
        for(int i = 0; i < 10_0000; i++){
            s += i;
        }
        long end = System.currentTimeMillis();
        System.out.println(end - beg);  //2794
        System.out.println(s);

        // Java 还提供了可变的字符串 StringBuilder. 用法和 String 非常相似. 可以方便的和 String 相互转换.
        // 但是这个东西可以修改.
        // 记录程序开始的时间戳, 单位是毫秒.
        StringBuilder stringBuilder = new StringBuilder("Hello");
        long beg = System.currentTimeMillis();
        for(int i = 0; i < 100_0000; i++){
            // 类似于 String 的 += 这个过程不会创建新的 StringBuilder 对象, 都是针对同一个对象操作的.
            stringBuilder.append(i);
        }
        long end = System.currentTimeMillis();
        System.out.println(end - beg); //20
//        System.out.println(stringBuilder);
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值