Java字符串(String与StringBuffer)及常用方法精密刨析

在Java中或者其他计算机语言中,字符串肯定是必不可少的,为了让许多Java初学者更好的学习字符串,我用这篇文章来详细讲解一下字符串和字符串常用的几个方法

我们先提出一个疑问:如何创建一个字符串?

创建字符串

这个问题很简单,只要不是新手或者小白应该都知道,有两种方法可以创建字符串,我们来看看

String s1 = "abc";
String s2 = new String("abc");

第一个,就是我们常用的定义变量方法,就像 int a = 1 一样,直接定义了给String类型变量并且赋值“abc”

第二个可能看起来比第一个复杂一点,我们第一个是定义了一个变量,而我们第二个,是直接创建了一个字符串对象,如果对象不理解可以去看看我这篇文章:

Java类与对象:类、对象与方法如何使用(什么是类?什么是对象?什么是方法?) - 小简博客 (janyork.com)icon-default.png?t=L9C2https://blog.janyork.com/index.php/archives/447/

其实这两种创建字符串方法的作用都相似,不过,既然我说了是相似不是相同,那么他们区别又在哪呢?

这里就要涉及到Java的栈区与堆区了,如果不懂,也没有关系,可以去了解一下,我们来分析分析这两个创建方法在栈区与堆区的不同

  • 第一种方法,仅仅是一个赋值语句,在创建的时候,JVM 会检查在字符串池中,是否已经存在该字符串,如果已经存在了,那么会返回这个字符串的引用给变量 s。如果不存在,那么会创建一个 abc 字符串对象,再赋值给 s1。因此,这句话可能只创建 1 个或者 0 个对象
  • 第二种方法会在内存中创建 1 个或者 2 个对象。把 new String(“abc”) 这句话拆成两个部分来看,一个是”abc”, 另一个是 new String()。如果 abc 字符串已经在字符串池中存在了,那么就不需要在创建 abc 字符串的对象了,但是 new String 这行代码会再构造出一个和 abc 一样的字符串,并且是放在堆上

这里为了让大家看明白,我使用一种分析图来让这个原理视觉化:

JDK7 把字符串池从方法区移动到了堆区,但这个基本原理是不变的。

所以说,我们使用的时候尽量不要使用 new String 这种方式

 这里只是扩展一下,不必要仔细研究,只要知道一般都是直接用第一种创建就可以

字符串的比较(equals()方法)

我们之前学过比较运算符,比较运算符可以对数字和字符类型,但是我们除了字符和数字类型的变量,还有一个类型,就是字符串String类型,那它不是数字也不是字符,那么我们怎么比较它判断它呢?

我们先来说说它的大小比较,大小比较一般就是用于排序或者判断大小,这里就有一种适合字符串比较的方法,专门用于String的比较,Java compareToIgnoreCase 方法

这个方法按照字典序将String的英文单词或者英文字符串按字母排序,这里不多讲,因为用的不多,想要了解可以看看我这篇文章:

Java compareToIgnoreCase() 方法如何使用? - 小简博客 (janyork.com)icon-default.png?t=L9C2https://blog.janyork.com/index.php/archives/421/

 我们主要是要知道字符串怎么判断相等,因为相等在我们程序中用的特别多,我们了看看如何判断恒等

我们知道,我们可以用 == 来判断数字与字符是否恒等,比如:

int a = 1;
if(a==1){
    //代码块
}

 这是一个简单的条件判断,但是如果我们用 == 来比较String呢?那么系统将会认为是 字符串==字符串 ,都是字符串,所以判断条件始终为true,永远是判断恒等的

那不可以用 == ,那怎么比较String呢?这里提到一个方法equals()

我们来介绍一下这个方法:

  • equals () 方法用于将字符串与指定的对象比较
  • String 类中重写了 equals () 方法用于比较两个字符串的内容是否相等

介绍也介绍了,我们来看看它这个方法怎么用吧!

我们先定义两个String字符串:

String name = "Jan";
String password = "123456";

我们这里定义了两个String,一个是名字,一个是密码,我们可以这样判断恒等

        if (name.equals("Jan")){
            System.out.println("用户名正确");
        }else{
            System.out.println("用户名错误");
        }

我们看看它的运行结果:

 这里已经判断出来了,判断用户名正确,可是大家有没有发现,我 if 的括号里面的判断条件下面画了波浪线,这是为什么呢?

因为IDEA是个特别智慧的开发工具,这里波浪线是因为它提醒我这个判断是死的始终为true,我们可以用Scanner把这个程序写活,我们给它加个Scanner试试

import java.util.Scanner;
public class eq {
    public static void main(String[] args) {
        Scanner x = new Scanner(System.in);

        String name = "Jan";
        String password = "123456";

//        用户输入
        System.out.print("输入你的用户名:");
        String name2 = x.next();
        System.out.print("输入你的密码:");
        String password2 = x.next();

        if (name.equals(name2)&&password.equals(password2)){
            System.out.println("登录成功");
        }else{
            System.out.println("用户名错误");
        }
    }
}

这样我们的代码就是活的了,不是死板的

看看运行效果:

 这个字符串比较的方法的使用就是这么简单了,不过字符串可不止这一个方法哦!

我们再提出一个疑问:使用什么方法可以获得字符串的长度? 

获取字符串的长度(length()方法)

对于这个问题,大家可能会想到,我们先前的数组长度就是用length获取的,那会不会String字符串也是用length获取?

恭喜,这样想方向就对了,但是还是有一点不一样的,比如,我们是用length()方法获取字符串长度,这里多了一个括号哦!

这个方法语法也很简单,就这样:

字符串名.length();

我们来写个代码试试:

import java.util.Scanner;
public class eq {
    public static void main(String[] args) {
        Scanner x = new Scanner(System.in);

        System.out.print("输入你的密码:");
        String password = x.next();

        if (password.length()<6){
            System.out.println("密码不可以低于6位数哦!");
        }
    }
}

这里我让用户输入一个密码,这个密码是字符串类型

我们在if的条件里面使用 .length() 获取字符串的长度,注意了:这个长度是一个 int 类型的值

条件是,如果String长度小于6,就输出密码不可以低于6位数

我们来看看效果:

我输入密码只要3个字符长度,所以输出了:密码不可以低于6位数

这个方法比较容易,就不多说废话了,我们在来学习一个方法!

老规矩,先提问:如何连接字符串?如果提取字符串?如何拆分字符串?

这里我提出了三个提问,所以说,分别对应String的三个方法

我们一个个分析吧!

连接字符串:concat()方法

基本语法是这样的:

String a = "....";
String b = "----"
a = a.concat(b);
//b是a要连接的字符串,连接起来应该是这样的:....----

//当然,你也可以这样:
String a = "CSDN";
a = a.concat("YYDS");
//连接起来应该是这样的:CSDNYYDS

我们先不演示了,看看第二个问题要使用的方法:

提取字符串:indexOf()方法

实际上提取字符串就是查找字符串中指定字符第一次出现的位置,谈不上提取,算是查找

indexOf() 方法有以下四种形式

  • public int indexOf(int ch): 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。

  • public int indexOf(int ch, int fromIndex): 返回从 fromIndex 位置开始查找指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。

  • int indexOf(String str): 返回指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。

  • int indexOf(String str, int fromIndex): 返回从 fromIndex 位置开始查找指定字符在字符串中第一次出现处的索引,如果此字符串中没有这样的字符,则返回 -1。

以上形式参数说明:

  • ch -- 字符,Unicode 编码。

  • fromIndex -- 开始搜索的索引位置,第一个字符是 0 ,第二个是 1 ,以此类推。

  • str -- 要搜索的子字符串。

四种形式的语法:

public int indexOf(int ch )



public int indexOf(int ch, int fromIndex)



int indexOf(String str)



int indexOf(String str, int fromIndex)

 我们不必管这些语法形式,因为我们实际代码一般不这么写!!!

我们一般直接:String变量名.indexOf(“查找的字符”)

比如我要在”CSDN“这个字符串中查找”D“所在位置,就是这样写:

String a = "CSDN";                                          
System.out.println("D所在位置:"+(a.indexOf("D")+1));            

这里要注意,字符串中的字符下标也是像数组一样,从0开始,所以它的实际位置需要+1,不然输出的是字符下标位置!

我们来看两个示例代码:

第一个是用于查找字符串,或字符 Unicode 编码在字符串出现的位置:

public class Main {
    public static void main(String args[]) {
        String string = "aaa456ac";  
        //查找指定字符是在字符串中的下标。在则返回所在字符串下标;不在则返回-1.  
        System.out.println(string.indexOf("b")); // indexOf(String str); 返回结果:-1,"b"不存在  
 
        // 从第四个字符位置开始往后继续查找,包含当前位置  
        System.out.println(string.indexOf("a",3));//indexOf(String str, int fromIndex); 返回结果:6  
 
        //(与之前的差别:上面的参数是 String 类型,下面的参数是 int 类型)参考数据:a-97,b-98,c-99  
 
        // 从头开始查找是否存在指定的字符  
        System.out.println(string.indexOf(99));//indexOf(int ch);返回结果:7  
        System.out.println(string.indexOf('c'));//indexOf(int ch);返回结果:7  
 
        //从fromIndex查找ch,这个是字符型变量,不是字符串。字符a对应的数字就是97。  
        System.out.println(string.indexOf(97,3));//indexOf(int ch, int fromIndex); 返回结果:6  
        System.out.println(string.indexOf('a',3));//indexOf(int ch, int fromIndex); 返回结果:6  
    }
}

这段代码的运行结果是:

-1
6
7
7
6
6

第二个指定子字符串在字符串中第一次出现处的索引,从指定的索引开始

public class Test {
    public static void main(String args[]) {
        String Str = new String("菜鸟教程:www.runoob.com");
        String SubStr1 = new String("runoob");
        String SubStr2 = new String("com");
 
        System.out.print("查找字符 o 第一次出现的位置 :" );
        System.out.println(Str.indexOf( 'o' ));
        System.out.print("‎从第14个位置查找字符 o 第一次出现的位置 :‎‎"‎‎ ‎‎)‎‎; ‎‎System‎‎.‎‎ ‎‎out‎‎.‎‎ ‎‎println‎‎(‎‎Str‎‎.‎‎ ‎‎indexOf‎‎(‎‎ ‎‎'‎‎o‎‎'‎‎, ‎‎14‎‎ ‎‎)‎‎)‎‎; ‎‎System‎‎.‎‎ ‎‎out‎‎.‎‎ ‎‎print‎‎(‎‎"‎‎子字符串 SubStr1 第一次出现的位置:‎‎"‎‎ ‎‎)‎‎; ‎‎System‎‎.‎‎ ‎‎out‎‎.‎‎ ‎‎println‎‎(‎‎ ‎‎Str‎‎.‎‎ ‎‎indexOf‎‎(‎‎ ‎‎SubStr1‎‎ ‎‎)‎‎)‎‎; ‎‎System‎‎.‎‎ ‎‎out‎‎.‎‎ ‎‎print‎‎(‎‎"‎‎从第十五个位置开始搜索子字符串 SubStr1 第一次出现的位置 :‎" );
        System.out.println( Str.indexOf( SubStr1, 15 ));
        System.out.print("子字符串 SubStr2 第一次出现的位置 :" );
        System.out.println(Str.indexOf( SubStr2 ));
    }
}

以上程序执行结果为:

查找字符 o 第一次出现的位置 :12
从第14个位置查找字符 o 第一次出现的位置 :17
子字符串 SubStr1 第一次出现的位置:9
从第十五个位置开始搜索子字符串 SubStr1 第一次出现的位置 :-1
子字符串 SubStr2 第一次出现的位置 :16

这个方法讲完了,我们来讲下一个

拆分字符串:split()方法

我们的split()方法的作用是将字符串拆开来

原理:

split() 方法根据匹配给定的正则表达式来拆分字符串。

注意 . 、 $、 | 和 * 等转义字符,必须得加 \\。

注意:多个分隔符,可以用 | 作为连字符。

我们写一个代码试试:

String str = "小学,初中,高中,大专,本科,研究生,博士";
String[] buff = str.split(",");

这句代码的意思就是以 “,” 这个逗号将字符串拆开来

我们这里创建了个数组buff

我们利用for循环遍历输出这个数组,这个代码实现的效果是这样的:

小学
初中
高中
大专
本科
研究生
博士

但是,注意了,像 . 和我们上面提到的转义字符,前面必须加上 \\ 才行

比如,这样:

String str2 = "小学.初中.高中.大专.本科.研究生.博士
String[] buff2 = str2.split("\\."); 

我们也可以设定要将这个字符串分成几份,比如这样:

String str = "小学,初中,高中,大专,本科,研究生,博士";
String[] buff = str.split(",",4);

这样就是限制它的分割份数,我这里是分成4份(括号里面,隔开,后面的数字就是份数,我这里是4),所以for循环输出后是这样的:

小学
初中
高中
大专.本科.研究生.博士

好了,这里慢慢理解吧,不懂可以私信问我或者加我QQ

别以为我们就讲完了,我们还有两个内容没讲呢!/偷笑

我们上面使用的方法都是针对于String类的,但是String类有个缺点,就是String类的对象是不可以多次修改的,如果要修改,就会产生新的String对象,这在运行时会产生影响

在使用 StringBuffer 类时,每次都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,所以如果需要对字符串进行修改推荐使用 StringBuffer

我们现在不需要去详细了解为什么,因为到后面自然会明白,慢慢来,别着急

以上方法实践代码:

import java.util.Scanner;
public class eq {
    public static void main(String[] args) {

        /*
         * concat()方法
         */
        String name = "CSDN";
        name = name.concat("YYDS");
        System.out.println(name);

        String name1 = "CSDN";
        String name2 = "YYDS";
        name1 = name1.concat(name2);
        System.out.println(name1);

        /*
        *indexOf()方法
         */
        String a = "CSDN";
        System.out.println("D所在位置:"+(a.indexOf("D")+1));
        /*
        *split()方法
         */
        String str = "小学,初中,高中,大专,本科,研究生,博士";
        String[] buff = str.split(",");
          for(int i=0;i<buff.length;i++){
             System.out.println(buff[i]);
          }

          String str2 = "小学.初中.高中.大专.本科.研究生.博士";
          String[] buff2 = str2.split("\\.");
          for(int i=0;i<buff.length;i++){ 
              System.out.println(buff2[i]);
          }
          
    }
}

String扩展 

我们的String字符串还有几个方法

比如lastIndexOf 方法,查找字符串中字符最后一次出现的位置,和indexOf相反,就不多讲了

 还有

substring方法:字符串的截取

String day = "Today is Monday"; 

System.out.println(day.substring(2));

这个 就是对象调用substring方法,方法后面括号中的数字的字符串下标,意思是截取从下标2开始到最后,所有会输出:day is Monday

也可以这样,设定一个结尾字符:

String day = "Today is Monday"; 

System.out.println(day.substring(2,5));

括号里面左边是开始位置,后面是结尾位置,我这里是2和5

所以会截取2-5这一段,所以这里会输出day

trim方法:过滤字符串中出现的空格 

这个了解一下就可以,反正也用不到!


str.trim(); //去掉首尾空格
str.replace(" ",""); //去除所有空格,包括首尾、中间
str.replaceAll(" ", ""); //去掉所有空格,包括首尾、中间
str.replaceAll(" +","");  //去掉所有空格,包括首尾、中间
str.replaceAll("\\s*", ""); //可以替换大部分空白字符, 不限于空格 ;
\\s* 可以匹配空格、制表符、换页符等空白字符的其中任意一个。

Java StringBuffer类的方法

StringBuffer对象的创建:

StringBuffer 对象名 = new StringBuffer("字符串内容");

StringBuffer对象创建String变量:

对象名.字符串名 ("字符串内容")

看到这,可能许多朋友不明白这个东西,到底有什么用,我写个代码,大家就明白了

上代码:

public class Demo{
  public static void main(String args[]){
    StringBuffer sBuffer = new StringBuffer("我的个人博客是:");
    sBuffer.append("blog");
    sBuffer.append(".janyork");
    sBuffer.append(".com");
    System.out.println(sBuffer);  
  }
}

运行后输出结果是:

我的个人博客是:blog.janyork.com

我这里定义了个StringBuffer对象,初始值为:我的个人博客

下面我利用对象调用append方法,赋值blog

然后我在下面连续两次使用append方法再次赋值,但是赋值并没有覆盖,而是拼接在一起了

但是,如果我们使用的是String对象来连续赋值的话,就会被覆盖,最终就只会输出:我的个人博客是:.com

 这就是StringBuffer对象的好处了

先别急着想append()方法是什么,我们下面会讲述的啦!

对于StringBuffer,我们有几个常用的方法要讲一下:

1 public StringBuffer append(String s)
将指定的字符串追加到此字符序列。
2 public StringBuffer reverse()
 将此字符序列用其反转形式取代。
3 public delete(int start, int end)
移除此序列的子字符串中的字符。
4 public insert(int offset, int i)
将 int 参数的字符串表示形式插入此序列中。
5 insert(int offset, String str)
将 str 参数的字符串插入此序列中。
6 replace(int start, int end, String str)
使用给定 String 中的字符替换此序列的子字符串中的字符。

我们不讲多余的,因为初级阶段,还用不到,不必浪费时间去研究去学习,因为你的Java逻辑还没有成熟,不如多花点时间去巩固基础,总不能走还不会就跑吧!

好的,我们这里主要只讲三个方法

分别是toString()方法、append()方法、insert()方法

我们先来讲讲第一个方法

转换为String:toString()方法

StringBuffer类成员toString函数可将其转换成String类型

StringBuffer a = new StringBuffer(“abcd”);

String b = a.toString();

这里我创建一个StringBuffer对象,对象名a,初始赋值abcd

下面我创建一个String对象b,b=对象名.toString() ,将a转换为String类型

大家只需要知道怎么转换就可以了,toString()这个方法还有很多用处,我们以后会接触到的,慢慢来!

拼接字符串:append()方法

我们上面开始已经提到过这个方法了,这个方法的作用就是拼接,并且不像String那样拼接,String对象拼接需要创建新的对象,而StringBuffer拼接可以直接拼接对象不会改变

比如看看我这个代码:

public class Test{
  public static void main(String args[]){
    StringBuffer sBuffer = new StringBuffer("aaa");
    sBuffer.append("bbb");
    sBuffer.append("ccc");
    sBuffer.append("ddd");
    System.out.println(sBuffer);  
  }
}

我创建一个StringBuffer对象,(说到这可能是我前面没讲明白,因为String本身就是一个类,我们平常定义一个String变量其实就是创建了一个String对象,只是它省略了new而已,慢慢的就会明白了),对象名为sBuffer,初始值为aaa

我们直接利用对象调用append方法,并且给出方法括号里面的值”bbb“

小提示:其实我们可以看出,这个方法其实就是一个有参方法括号里面是它的要传递的参数

我们在调用两次append方法,分别给出参数值ccc于ddd

这时候,append方法将aaa于bbb、ccc、ddd拼接在一起,并且赋值给sBuffer这个对象

然后我们输出,结果就是这样的:

aaabbbcccddd

这个方法很容易,我们看最后一个方法!

插入字符串:insert()方法

这个方法也很容易,我们来看看代码:

StringBuffer x = new StringBuffer("CSN");
        x.insert(2,"D");
        System.out.println(x);

说过的话就不在讲了,创建对象都懂

对象的初始值为”CSN“

我们用对象x调用这个方法,这也是个有参方法,括号里面两个数值,第一个是下标位置,第二个是要插入的字符串

我们这里插入一个D,插在下标2这个位置

字符串下标从0开始,所以这里会在第一个下标后,第二个下标前插入这个字符,并且下标2和它后面的下标都自动往后移了

所以这个D插在了S和N的中间

最后输出CSDN:


 

好了,我们的字符串终..终..终..终..终..终于讲完了,1024,所日快

猜你喜欢

转载自blog.csdn.net/qq_60750453/article/details/120933652