理解String 类(下)

简介: 理解String 类(下)

六、字符串查找



1. contains( ) 方法


主串通过 contains( ) 方法 调用子串


程序清单17:


public class Test17 {
    public static void main(String[] args) {
        String str1 = "abcdef";
        String str2 = "cde";
        System.out.println(str1.contains(str2));
    }
}


输出结果:


8f13be99a6f7461483d1dc26b059cfcc.png


2. indexOf( ) 方法


主串通过 indexOf( ) 方法 调用子串


如果主串中有子串的数据,那么就返回主串中的索引,即子串对应的第一个字符的位置,如果主串中没有子串的数据,则返回 -1.


程序清单18:


public class Test18 {
    public static void main(String[] args) {
        String str1 = "abcdef";
        String str2 = "cde";
        String str3 = "dec";
        System.out.println(str1.indexOf(str2));
        System.out.println(str1.indexOf(str3));
    }
}


输出结果:


4ba27ce9358b496889257153409fdc89.png


3. lastIndexOf( ) 方法


indexOf( ) 方法是在主串中从前往后找子串,lastIndexOf( ) 方法是在主串中从后往前找子串。虽然 lastIndexOf( ) 方法是从后往前找,但是输出的索引下标依然是从前往后算的。只不过,如果两个方法面对重复的字符,会出现不同的结果。 如下所示:


程序清单19:


public class Test19 {
    public static void main(String[] args) {
        String str1 = "{abcd}}";
        String str2 = "}";
        System.out.println(str1.lastIndexOf(str2));
        System.out.println(str1.indexOf(str2));
    }
}


输出结果:


02272ec2a0e045b78fd2728c1689db17.png


拓展:indexOf( ) 方法 和 lastIndexOf( ) 方法中可以添加第二个整型参数 : ( fromIndex ),表示从某个位置开始找,感兴趣的小伙伴可以自己测试一下。


4. startsWith( ) 方法


字符串通过调用 startsWith( ) 方法,来判断主串的头部是否是我们要输入的数据。传参的时候可以是一个参数,也可以是两个参数。第一个参数可以是字符,也可以是字符串;第二个参数表示的是偏移量,旨在通过某个位置开始判断。


代码如下:


程序清单20:


public class Test20 {
    public static void main(String[] args) {
        String str1 = "abcdef";
        System.out.println(str1.startsWith("a"));
        System.out.println(str1.startsWith("bcd"));
        System.out.println(str1.startsWith("c",2));
        //表示从偏移位置2 往后判断
    }
}


输出结果:


9d00188b259346a3b9eb6c344d326936.png


5. endsWith( ) 方法


startsWith( ) 方法是从头部开始判断,而 endsWith( ) 方法是从尾部开始判断,思想是相同的,但是 endsWith( ) 方法 在传参的时候,只能传一个参数,即我们要判断的字符或字符串。


程序清单21:

public class Test21 {
    public static void main(String[] args) {
        String str1 = "abcdef";
        String str2 = "cde";
        System.out.println(str1.endsWith("f"));
        System.out.println(str1.endsWith("bcd"));
    }
}


输出结果:


58949e2c240a4b8a8b54daab4c59eea8.png


七、字符串替换



1. replace( ) 方法


我们看到下图 replace( ) 方法,在底层的代码,当替换成功的时候,返回的是一个新创建的对象,而需要替换的字符的内容和输入字符的内容相同的时候,说明无须替换,那么这个时候,就返回原来的引用。


这就说明一个问题,在上文中的目录,我提到了一个关键点:字符串的内容不可变,也就是说,当我们表面上好像改变了原先字符串的数据,但实际上底层操作的时候,为我们 new 了一个新的对象,所以说我们看到被替换后的字符串,实际意义上是一个完完整整的一个新串,与原先的字符串没有半点关系。


9c16b54769cd4bcf924b0404792b1c99.png


程序清单22:


public class Test22 {
    public static void main(String[] args) {
        String str = "abcabeabdabxy";
        String ret1 = str.replace('a','z');
        String ret2 = str.replace("ab","zz");
        String ret3 = str.replace("ab","zzz");
        String ret4 = str.replaceFirst("ab","zz");
        System.out.println(ret1);
        System.out.println(ret2);
        System.out.println(ret3);
        System.out.println(ret4);
    }
}


输出结果:


1b875db52bf5476688f051e50f8b2d1e.png


八、字符串拆分



1. split( ) 方法


我们看到 split( ) 方法底层代码的返回类型是 String[ ] 类型,即一个字符串数组的类型。


ef3966b5d0d149dcb47d6981a014681f.png


程序清单23:


public class Test23 {
    public static void main(String[] args) {
        String str = "name=Jack&age=23";
        String[] strings = str.split("&");
        for (String s:strings) {
            System.out.println(s);
        }
    }
}


输出结果:


6eb2d7424e5545ff9cd4fed25da6bb4c.png


在我们通过 IDEA 编译器调试之后,我们可以发现字符串数组中下标 0 和 1 放了两个字符串。


f3fe1b83689f443f8657bda4de47ef43.png


我们需要注意的是:如果我们单纯地调用 split( ) 方法,只会分割一次,因为底层代码就是这么实现的,在后面我会提到多次分割。


程序清单24:


public class Test24 {
    public static void main(String[] args) {
        String str = "name=Jack&age=23";
        String[] strings = str.split("=", 2);
        for (String s:strings) {
            System.out.println(s);
        }
    }
}


输出结果:


74fc4b3cebbf40ab8b41a150b6fdc49e.png


这里我们需要注意下面的代码:在 split( “=”, 2 ) 中的参数2,代表的是按 " = " 分割成两组,而不是均匀分割成两组。


String[] strings = str.split("=", 2);


2. 使用 split( ) 方法 进行二次分割


程序清单25:


public class Test25 {
    public static void main(String[] args) {
        String str = "name=Jack&age=23";
        String[] strings1 = str.split("&");
        for (String s:strings1) {
            String[] strings2 = s.split("=");
            for (String ss: strings2) {
                System.out.println(ss);
            }
        }
    }
}


输出结果:


51eddcbd238a45669f9c29a8a934a108.png


在这里我就不进行调试了,调试的过程中是动态的,感兴趣的小伙伴可以自己她是过后观察。


3. 字符串拆分的特殊情况


对于一些转义字符的特殊情况,我们在给 split( ) 方法传参的时候,需要考虑进去。比方说:在程序清单26中,我们通过字符 " . " 来分割字符串,然而我们不能直接就这么传参了,我们需要通过 ’ \ ’ 转义才能达到我们的目的。


此外,字符 " | ‘’," * " , " + " 等等都得加上转义字符。


程序清单26:


public class Test26 {
    public static void main(String[] args) {
        String str = "192.168.1.1" ;
        String[] strings = str.split("\\.") ;
        for(String s: strings) {
            System.out.println(s);
        }
    }
}

输出结果:


b6df67541c754f6fb6e72a8bb8e03d1a.png


4. 按连接符实现多次拆分


在程序清单26中,我们可以通过连接符 ’ | ’ 实现不同分隔符之间的拆分。


程序清单26:


public class Test26 {
    public static void main(String[] args) {
        String str = "name=Jack&age=23";
        String[] strings = str.split("=|&|=");
        for (String s:strings) {
            System.out.println(s);
        }
    }
}


输出结果:


2400685b1d764c9ba84b667dfb76d099.png


九、字符串截取



1. subString( ) 方法


subString( ) 方法的底层代码,可以看到其返回类型是 String 类型。

并且,返回时创建了新的对象。


4ab9a77a45964f52a8f29a8385ee3122.png


我们先来展示程序清单27,再来分析代码是如何实现的。


程序清单27:


public class Test27 {
    public static void main(String[] args) {
        String str1 = "abcdef";
        String str2 = str1.substring(2);
        String str3 = str1.substring(0);
        String str4 = str1.substring(2,5);
        System.out.println(str2);
        System.out.println(str3);
        System.out.println(str4);
    }
}


输出结果:


8645a92cad87468d937a78312466bd3e.png


分析程序清单27的代码:


输出 str2 :是从字符串下标索引为2的字符开始往后截取(包括2下标),底层代码 new 了一个新对象。


输出 str3 :字符串下标索引为0的字符开始往后截取,等于拿到了原先的对象,这时候并没有重新创建对象。


输出 str4 :subString( ) 方法遵循左闭右开,左边下标索引为2可以取到字符,右边下标索引为5取不到字符。同时,底层代码 new 了一个新对象。


十、其他的一些字符串操作


1. trim( ) 方法


trim( ) 方法 用来除去字符串两边的空格,代码如下:


程序清单28:


public class Test28 {
    public static void main(String[] args) {
        String str1 = "    abc  xyz    ";
        System.out.print(str1);
        System.out.println("------------");
        String str2 = str1.trim();
        System.out.print(str2);
        System.out.println("------------");
    }
}


输出结果:


27e77cd517e34b51a0fbade91893b52d.png


2. 将字符串中的字符转换成大写 / 小写 [ 常用 ]


toUpperCase( ) 方法 和 toLowerCase( ) 方法


程序清单29:


public class Test29 {
    public static void main(String[] args) {
        String str1 = "abcdWXYZ123";
        String str2 = str1.toUpperCase();
        String str3 = str1.toLowerCase();
        System.out.println(str2);
        System.out.println(str3);
    }
}


输出结果:


343e8acb147041a78532d3bf7d94b0a5.png


3. 拼接字符串


程序清单30:


public class Test30 {
    public static void main(String[] args) {
        String str1 = "abcd";
        String str2 = "wxyz";
        String str3 = str1.concat(str2);
        System.out.println(str3);
    }
}


输出结果:


e7185b17f6874311bee98e726ab30843.png


4. 求字符串长度 [ 常用 ]


求字符串长度并不难,而我想说的是,这里需要区分:字符串求长度的格式 str.length( ) 和 数组求长度的个数的格式 arr.length。注意点:一个有括号,一个没括号。


程序清单31:


public class Test31 {
    public static void main(String[] args) {
        String str = "abcde";
        System.out.println(str.length());
        int[] arr = {1,2,3,4,5};
        System.out.println(arr.length);
    }
}


输出结果:


2402447289684232b9a0692c5afe449f.png


5. 判断字符串是否为空


程序清单32:


public class Test32 {
    public static void main(String[] args) {
        String str1 = "abcd";
        String str2 = " ";
        String str3 = "";
        System.out.println(str1.isEmpty());
        System.out.println(str2.isEmpty());
        System.out.println(str3.isEmpty());
    }
}


输出结果:


6902896337e94f21b6b19569241c1b53.png


十一、理解引用



程序清单33:


public class Test {
    public void change(String s, char[] ch){
        s = "world";
        ch[0] = 'g';
    }
    String str = new String("hello");
    char[] chars = {'a', 'b', 'c'};
    public static void main(String args[]){
        Test test = new Test();
        test.change(test.str, test.chars);
        System.out.println(test.str);
        System.out.println(test.chars);
    }
}


输出结果:


4cf154151e844f0d9d68306ae6ce5a31.png


这一题在我第一次做的时候,自己认为输出结果会是下面代码:


//错误答案
world
gbc


后来,我才想明白,当我们传参的时候,传了一个是 String 类型,一个是 char[ ] 类型,这两者在传参的时候传的其实都是引用类型。(这其实就是实参和形参之间对应的关系,通过改变形参并不影响传入的实参状态


说白了,就是把对象的地址传过去了。那么在 change( ) 方法接收的时候,等于拿到了两者的地址。后来,我们改变了引用变量 s ,让它指向了 " world “,那么就不再指向原先的” hello ",所以最终引用 s 与主函数中的引用 str 没有半毛钱关系。而引用 ch 就不同了,它是通过 ch[0] 直接访问到原先数组,通过改变数组下标为 0 的元素值,这会破坏原先数组的结构,所以最终数组元素变成了 [ gbc ]。 下图辅助理解:


2c29c02ccbc14338b51141fcd237d802.png


十二、StringBuilder 类 和 StringBuffer 类



我们查看底层代码,发现 StringBuilder 类 在底层实现的时候,调用了 append( ) 方法,在 append( )方法中返回的是原先的对象,并没有重新 new 一个新的对象。append( ) 方法在底层代码实现的作用就是:可以拼接字符串,然后一次一次地将字符串放入原先的对象中。


a1095a64039845af9527cb4436e8e272.png587d2ebd0f7848b3b63a0235837215b9.png546813e90e994160a022936050600b18.png


我们查看底层代码,发现 StringBuffer 类 在底层实现的时候,和上面的 StringBuilder 类很相似,唯一不同的就是 StringBuffer 类多了一个限定符 synchronized,这表示 StringBuffer 采用了同步处理,属于线程安全操作,会使程序执行起来更加安全,当然也会使程序执行起来相对 StringBuilder 于更慢一点。


de8ac7f820b849968adc924412df6aa0.pngb532f6df08fc445d915ee1ebf5dfbabe.pngb9eb8909521f49d29b7575984945fdad.png


在介绍过 StringBuilder 类 和 StringBuffer 类 两者对应的底层代码之后,因为两者很多地方是相似的,那么我直接以 StringBuilder 类 来演示一些操作字符串的方法。


1. append( ) 方法


append( ) 方法可以用来拼接很多不同类型的变量放入一个 StringBuilder 类的变量中,我们先来看一下编译器中 append( ) 方法,可以拼接的东西应有尽有!


9b495c46c32341678919a68df90b3b78.png


程序清单34:


public class Test34 {
    public static void main(String[] args) {
        StringBuilder str = new StringBuilder("abc");
        System.out.println(str);
        System.out.println("----------------");
        str.append("opq");
        System.out.println(str);
        System.out.println("----------------");
        str.append("xyz");
        System.out.println(str);
    }
}


输出结果:


47a72cac9a19461689335a4b64d5613d.png


在程序清单34中,我们可以发现 append( ) 方法在放字符串的时候,每次都放入了 str 中,那么实际上被改变的就是原先对象中的字符串内容。


2. 字符串逆置


程序清单35:


public class Test35 {
    public static void main(String[] args) {
        StringBuilder str = new StringBuilder("abcde");
        System.out.println(str);
        System.out.println(str.reverse());
    }
}


输出结果:


7b2786616ec849b8a294c8efa9744d77.png



3. StringBuilder 类 和 StringBuffer 类 的其他一些方法



在程序清单36中,通过 delete( ) 方法,我们删除对应索引下标的字符,遵循左闭右开原则。


程序清单36:


public class Test36 {
    public static void main(String[] args) {
        StringBuffer str = new StringBuffer("abcdefg");
        System.out.println(str);
        System.out.println(str.delete(1,4));
    }
}


输出结果:




在程序清单37中,通过 insert( ) 方法,我们在对应的索引下标处添加对应的数据。


程序清单37:


public class Test37 {
    public static void main(String[] args) {
        StringBuffer str = new StringBuffer("abcde");
        System.out.println(str);
        System.out.println(str.insert(0, "你好"));
        System.out.println(str.insert(2, "hello"));
    }
}


输出结果:


297bf1360f274996a84e27932153cff4.png


4. String、StringBuffer、StringBuilder 三者的区别


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

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

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


5. String 和 StringBuffer、StringBuilder 之间的转换


在这里,我们需要理解一点:String 表示 String 类,而 StringBuilder 是另一种类,StringBuffer 同样也是另一种类,这三者性质不同,但是可以互相转换。


在程序清单38中,我演示了两种转换形式:


① StringBuilder / StringBuffer 类 =》String 类
调用 toString( ) 方法
② String 类 =》StringBuilder / StringBuffer 类
利用 StringBuilder / StringBuffer 的构造方法


程序清单38:


public class Test {
    public static String transform1(){
        StringBuilder strb = new StringBuilder();
        strb.append(111);
        strb.append("hello");
        return strb.toString();
        //return strb; //error
    }
    public static StringBuilder transform2(){
        String str = "world";
        return new StringBuilder(str);
        //return str; //error
    }
    public static void main(String[] args) {
        System.out.println(transform1());
        System.out.println(transform2());
    }
}


输出结果:


9d19e3a8b7bf463daa8e114c27e59d9b.png


十三、其他类型与字符串类型之间的转换



1. 整型转字符串


程序清单39:


public class Test {
    public static String transform1(){
        return Integer.toString(123);
    }
    public static String transform2(){
        return Character.toString('c');
    }
    public static void main(String[] args) {
        System.out.println(transform1());
        System.out.println(transform2());
    }
}


输出结果:


b64e91c875d54051bae80ba95fc46e32.png


在上面,我演示了 toString( ) 方法


当然,我们也可以使用 String.valueOf ( ) 方法,此外,我们可以进行转换的类型有很多很多。


image.png


2. 字符串转整型


在下面的程序中,我先将整个字符串分割为一个数组元素中的三个元素,我将数组的第一个元素转换成了整数,使用了【 Integer.parseInt() 】方法,后两个元素直接赋值给了字符串。后来我又将刚刚数组的第一个元素转换成了字符串,通过给其加上一个空字符即可。


程序清单40:


public class Test {
    public static void main(String[] args) {
        String str = "123;opq;xyz";
        String[] result = str.split(";");
        for (String s : result) {
            System.out.print(s +" ");
        }
        int a = Integer.parseInt(result[0]);
        String b = result[1];
        String c = result[2];
        System.out.print("\n"+a +" ");
        System.out.print(b +" ");
        System.out.print(c +" \n");
        System.out.println("------------------");
        String str2 = result[0] + "";
        System.out.println(str2);
    }
}


输出结果:


6942a7be8ac141f7ad2ed207dfaf888e.png

目录
相关文章
|
27天前
|
API 索引
String类下常用API
String类下常用API
32 1
|
27天前
for循环和String类下方法的一个练习题
for循环和String类下方法的一个练习题
42 1
|
3天前
|
存储 安全 Java
Java——String类详解
String 是 Java 中的一个类,用于表示字符串,属于引用数据类型。字符串可以通过多种方式定义,如直接赋值、创建对象、传入 char 或 byte 类型数组。直接赋值会将字符串存储在串池中,复用相同的字符串以节省内存。String 类提供了丰富的方法,如比较(equals() 和 compareTo())、查找(charAt() 和 indexOf())、转换(valueOf() 和 format())、拆分(split())和截取(substring())。此外,还介绍了 StringBuilder 和 StringJoiner 类,前者用于高效拼接字符串,后者用于按指定格式拼接字符串
10 1
Java——String类详解
|
29天前
|
Java API 索引
【Java基础面试二十四】、String类有哪些方法?
这篇文章列举了Java中String类的常用方法,如`charAt()`、`substring()`、`split()`、`trim()`、`indexOf()`、`lastIndexOf()`、`startsWith()`、`endsWith()`、`toUpperCase()`、`toLowerCase()`、`replaceFirst()`和`replaceAll()`,并建议面试时展示对这些方法的熟悉度,同时深入理解部分方法的源码实现。
【Java基础面试二十四】、String类有哪些方法?
|
28天前
|
存储 SQL Java
Java 系类之 Java StringBuffer类详解
这篇文章详细介绍了Java中的StringBuffer类的使用,包括其构造方法、追加字符串、替换字符、反转字符串和删除字符串的方法,并提供了相应的示例代码。
|
28天前
|
安全 Java API
Java系类 之 String、StringBuffer和StringBuilder类的区别
这篇文章讨论了Java中`String`、`StringBuffer`和`StringBuilder`三个类的区别,其中`String`是不可变的,而`StringBuffer`是线程安全的可变字符串类,`StringBuilder`是非线程安全的可变字符串类,通常在单线程环境下性能更优。
Java系类 之 String、StringBuffer和StringBuilder类的区别
|
14天前
|
存储 C++
C++(五)String 字符串类
本文档详细介绍了C++中的`string`类,包括定义、初始化、字符串比较及数值与字符串之间的转换方法。`string`类简化了字符串处理,提供了丰富的功能如字符串查找、比较、拼接和替换等。文档通过示例代码展示了如何使用这些功能,并介绍了如何将数值转换为字符串以及反之亦然的方法。此外,还展示了如何使用`string`数组存储和遍历多个字符串。
|
1月前
|
安全 程序员 C++
C++ --> string类的使用(详细介绍)
C++ --> string类的使用(详细介绍)
37 5
|
1月前
|
存储 编译器 C语言
C++ --> string类模拟实现(附源码)
C++ --> string类模拟实现(附源码)
56 4
|
1月前
|
安全 Java
12 Java常用类(二)(String类+时间类+BigDecimal类等等)
12 Java常用类(二)(String类+时间类+BigDecimal类等等)
25 2