Java:认识String类

  在我们创建字符串时,我们会这么写String str1=“abcd”,如果类比int a=1的话,那么我们思考一下:String是不是与int一样是一种数据类型?

答:不是!String是一种类!让我们认识一下String类吧!

一、构造字符串

String构造字符串有三种方法:直接赋值法、利用字符数组构造字符串、调用构造方法

1、直接赋值法:

public class Test1 {
    public static void main(String[] args) {
        //直接赋值法:
        String str1="abc";
    }
}


2、利用字符数组构造字符串:

public class Test1 {
    public static void main(String[] args) {
        //直接赋值法:
        String str1="abc";

        //利用字符数组构造字符串
        char[] array={'a','b','c'};
        String str2=new String(array);
        System.out.println(str2);//打印str2
    }
}

>>先将字符串的每一个字符存入字符数组中

>> 然后在实例化String类的时候,调用构造函数,传入array字符数组

看看打印出来的str2是否未abc:



3、 调用构造方法:

其实,方式2也调用了构造方法,唯一不同的是,其实在调用String类构造方法的时候,也可以直接传入字符串!

public class Test1 {
    public static void main(String[] args) {
        //直接赋值法:
        String str1="abc";

        //利用字符数组构造字符串
        char[] array={'a','b','c'};
        String str2=new String(array);
        System.out.println("str2:"+str2);

        //调用构造方法
        String str3=new String("abc");
        System.out.println("str3:"+str3);

    }
}

看看打印出来的效果:



二、 String类中的方法

1、lenth方法

在有些时候,我们想要知道字符串的长度,那么就可以调用String类中的lenth方法!

int length(String str)
参数:String类的引用类型数据

功能:计算字符串内容的长度

返回值:
返回字符串的长度

让我们看看实例:

public class Test2 {
    public static void main(String[] args) {
        String str1="abcd";
        //求字符串长度
        System.out.println("str1:"+str1.length());
    }

}

程序运行结果: 



2、isEmpty方法

bollean isEmpty(String str)
参数:String类的引用类型数据

功能 :判断一个字符串是否未空字符

返回值:
为空:返回true
不为空:返回false

让我们看看实例:

已知str1为非空字符串,那么调用isEmpty方法时,方法判断该str1is not empty(不是空字符串),因此返回false

str2为空字符串,调用该方法时,方法判断该str2 is empty(是空字符串),因此返回true

public class Test2 {
    public static void main(String[] args) {
        String str1="abcd";//非空字符串
        String str2="";//空字符串
        String str3=null;//str3不指向任何对象

        System.out.println("str1:"+str1.isEmpty());//false
        System.out.println("str2:"+str2.isEmpty());//true


    }

}

 程序运行结果:

提问;str3不指向任何对象,那么调用该方法时会出现什么结果?

答:报错! 

public class Test2 {
    public static void main(String[] args) {
        String str1="abcd";//非空字符串
        String str2="";//空字符串
        String str3=null;//str3不指向任何对象

        System.out.println(str3.isEmpty());


    }

}



3、equals方法

在正式介绍这个方法之前,我们一起来思考一个问题!

public class Test2 {
    public static void main(String[] args) {
        //情况1:
        String str1="abc";
        String str2="abc";
        System.out.println(str1==str2);//打印结果是true or false?
        
        //情况2:
        String str3=new String("hello");
        String str4=new String("hello");
        System.out.println(str3==str4);//打印结果是true or false?

    }
    

}

 程序运行结果:

为什么会这样?

按照正常逻辑:

str1与str2指向的字符串内容相同,打印true没问题 !那么,str3与str4指向的字符串内容也相同,为什么返回false?

其实,这种逻辑是错误的,我们知道,str1、str2等都是引用数据类型,它们储存的内容都是一个地址,而不是字符串的内容。它们存储的是字符串的地址!

那么,按照这个逻辑推断:

str1与str2存储的地址是同一个地址!

str3与str4存储的地址不是同一个地址!

这是为什么?

这里涉及到字符串常量池的知识。

规定:只要是双引号引起来的字符串常量,都会存在一个字符串常量池中。

这个字符串常量池有独特的存储逻辑:

1、当要新存入一个字符串之前,会先检查这个内存(字符串常量池)有没有这个字符串?

2、如果没有,将这个字符串存进去

3、如果有,就不重复存储了

让我来示范一下情况1与情况2的内部原理:

情况1:

情况2:

 

通过解决这个问题,我们目前至少知道了一个事实:不能通过String类的引用数据类型(str1、str2等)来比较字符串内容是否相同! 

那么新的问题来了:该用什么方法来比较字符串内容是否相同?

答:使用equals方法!



 equals方法:

equals方法:
功能:比较字符串内容是否相同
返回值:
相同:返回true
不同:返回false

让我们看看实例:

public class Test3 {
    public static void main(String[] args) {
        String str1="abc";
        String str2="abc";
        String str3="a";
        System.out.println("str1 and str2  "+str1.equals(str2));
        System.out.println("str1 and str3  "+str1.equals(str3));

    }
}

程序运行结果:

可以看见:

str1与str2指向的字符串内容相同:返回true

str1与str3指向的字符串内容不同:返回false



 equalsIgnoreCase方法

bollean equlasIgnoreCase(String str)
参数:String类的引用类型数据

功能:比较字符串内容是否相同(忽略字母大小写)

返回值:
相同:返回true
不同:返回false

 让我们看看实例:

public class Test3 {
    public static void main(String[] args) {
        String str1="ABC";//大写
        String str2="abc";//小写
        String str3="a";
        System.out.println("str1 and str2  "+str1.equalsIgnoreCase(str2));
        System.out.println("str1 and str3  "+str1.equals(str3));

    }
}

程序运行:

可以看到,str1指向的字符串为“ABC”为大写;而str2指向的字符串为”abc“小写,调用这个方法返回的结果是true,可知:这个方法可以忽略大小写的区别! 



 4、compoTo方法 

int compareTo(String str)
参数:String类的引用类型数据

功能:比较字符串的大小

返回值:
1、先按字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
2、如果前k个字符相等,返回值是两个字符串的长度差值(k为其中两个字符串中的最小长度)

 让我们看看实例:

public class Test3 {
    public static void main(String[] args) {
        String str1="abc";
        String str2="abc";
        String str3="a";
        String str4="abd";
        //字符串"abc"与"abc"相同,返回0
        System.out.println("str1 and str2  "+str1.compareTo(str2));
        //字符串"abc"与字符串"a",前1个字符相同,输出长度差值2
        System.out.println("str1 and str3  "+str1.compareTo(str3));
        //字符串"abc"与字符串"abd",前两个字符相同,最后一个字符按照字典次序大小比较,差值为-1
        System.out.println("str1 and str4  "+str1.compareTo(str4));

    }
}

 程序运行:



compareToIgnoreCase方法: 

int compareTOIgnoreCase (String str)
参数:String类的引用类型数据

功能:与compareTo方法相同,不过新增加了忽略大小写的功能


5、charAt方法

charAt()是一个字符串查找方法!查找方法类似与数组访问!

char charAt(int index)
参数:数字下标

功能:输入下标,返回对应的字符

返回值:一个字符

让我们看看实例:

public class Test3 {
    public static void main(String[] args) {
        //依次打印出来str1中的每一个字符!!
        String str1="abc";
        
        char ch= str1.charAt(0);//"a"的下标为0
        System.out.println(ch);

        ch=str1.charAt(1);//"b"的下标为1
        System.out.println(ch);

        ch=str1.charAt(2);//"c"的下标为2
        System.out.println(ch);


    }
}

 程序运行:



7、indexOf方法

charAt()方法是通过传入下标返回对应的字符。

而indexOf ()方法恰恰相反,通过传入字符返回下标!

int indexOf(int  ch)
参数;可以传入整型数据,也可以传入一个字符,最终都会根据其ASCII码值寻找字符

功能:传入字符,返回其下标

返回值:
>>存在该字符:
返回该字符在字符串中的下标
>>不存在该字符:
返回一个负数

让我们来看看实例:

public class Test3 {
    public static void main(String[] args) {
        String str1="abcc";
        //'a'的下标是0
        int index=str1.indexOf('a');
        System.out.println(index);
        //'b'的下标是1
        index=str1.indexOf('b');
        System.out.println(index);
        //'c'的下标是2
        //注意:虽然有两个'c',但是由于这个方法的查找逻辑是从前往后,因此返回的下标是2,而不是3
        index=str1.indexOf('c');
        System.out.println(index);



    }
}

程序运行:



 另外,还存在两个参数的indexOf()方法!

int indexOf(int  ch,int fromIndex)
参数;可以传入整型数据,也可以传入一个字符,最终都会根据其ASCII码值寻找字符

功能:传入字符,传入起始下标,从起始下标开始,从前往后查找字符

返回值:
>>存在该字符:
返回该字符在字符串中的下标
>>不存在该字符:
返回一个负数

 让我们看看实例:

public class Test3 {
    public static void main(String[] args) {
        String str1="abcc";

        //从下标为2的地方开始寻找'c',返回下标2
       int index=str1.indexOf('c',2);
        System.out.println(index);

        //从下标为2的地方开始寻找'a',找不到,返回一个负数
        index =str1.indexOf('a',2);
        System.out.println(index);

    }
}

程序运行结果:

同理:转大写的方法为toUpperCase方法 



8、toLowerCase方法

这个方法的功能是将字符串中的大写字符转换为小写字符!

让我们看看例子:

public class Test3 {
    public static void main(String[] args) {
       String str1="AbcD";
       String str2=str1.toLowerCase();
        System.out.println(str2);

    }
}

 程序运行结果:



三、字符串类型转换

1、其他类型数据转换为字符串数据

public class Test3 {
    public static void main(String[] args) {
        //整型数据转换为字符串
      String str1=String.valueOf(1234);
      //浮点型数据转换为字符串
      String str2=String.valueOf(12.34);
      //bollean类型数据转换为字符串
        String str3=String.valueOf(true);

        System.out.println(str1);
        System.out.println(str2);
        System.out.println(str3);

    }
}

程序运行结果: 



2、字符串数据转换为数字类型数据

让我们看看实例:

public class Test3 {
    public static void main(String[] args) {
        //字符串转换为整型数据
       int date1=Integer.parseInt("1234");
       //字符串转换为浮点型数据
       double date2=Double.parseDouble("12.34");

        System.out.println(date1+1);
        System.out.println(date2+1);

    }
}

程序运行结果:

date1+1可以完成计算且不会报错,说明字符串"1234"已经成功转换为整型数据!



3、字符串转数组

有时候我们操作字符串可能不太方便,这个时候就可以将字符串转换为数组!

让我们来看看例子:

import java.util.Arrays;
import java.util.Locale;

public class Test3 {
    public static void main(String[] args) {
       String str1="AbcD";
       //把字符串转为数组
        char [] array=str1.toCharArray();
        System.out.println(Arrays.toString(array));

    }
}

 程序运行结果:



四、字符串内容替换方法 

1、replace方法:

String replace (char oldChar,char newChar)
功能:用新字符替换旧字符

参数:新字符  旧字符

返回:
返回一个String类的引用类型数据

让我们看看例子:

public class Test3 {
    public static void main(String[] args) {
       String str1="abab";
       String str2=str1.replace('a','d');
        System.out.println("str2:"+str2);
        System.out.println("str1:"+str1);//不会修改之前的字符串内容

    }
}

 程序运行结果:

注意:这个字符串替换后,是不会修改原来的字符串“abab"的!

 


replace方法的重载方法:

除了用新字符替换旧字符,replace方法也有另外一个重载方法,它可以实现新字符串替换旧字符串!

String replace(String oldString,String newString)
参数:旧字符串  新字符串
功能:用新字符串替换旧字符串

让我们看看例子: 


public class Test3 {
    public static void main(String[] args) {
      String str1="abcab";
      String str2=str1.replace("ab","kkk");//用新字符串替换旧字符串
        System.out.println(str2);

    }
}

程序运行:

可以看到,字符串中的”ab"整体被替换为“kkk”

五、字符串分割

1、 split方法

假如我们有一个字符串"acb&dfde&dr"想要以特殊字符为分割线,分割数组,该怎么做?

答:调用split方法! 

String [] split(String regex)
参数:分割字符

功能:根据传入的分割字符分割字符串,返回一个数组

返回值:String类的数组

 让我们看看实例:

public class Test3 {
    public static void main(String[] args) {
      String str1="acb&dfde&dr";
     //以"&"作为分割字符
     String[] strings=str1.split("&");
     //利用循环打印数组内容
      for (String s:strings){
          System.out.println(s);
      }
    }
}

程序运行:

注: 字符  |    *    ,    .  + 作为分割字符时,前面要加上”\\"转义字符,否则无法分割

如果一个字符串里面有多种分割符,可以用|作为连接符,连接不同的分割符

public class Test3 {
    public static void main(String[] args) {
      String str1="acb&dfde<dr";
     String[] strings=str1.split("&|<");
      for (String s:strings){
          System.out.println(s);
      }
    }
}



split的重载方法 

String [] split (String regesx,int limit)
参数:分割字符  最多分的组数

功能:根据分割字符最多分割成limit组字符串

返回值:返回String类的数组

 让我们看看例子:

public class Test3 {
    public static void main(String[] args) {
      String str1="acb&dfde&dr";
     //分割字符串
     String[] strings=str1.split("&",2);
     //打印数组
      for (String s:strings){
          System.out.println(s);
      }
    }
}

程序运行:

对比之前的split方法,这个方法只将这串字符串分割为2组!



 六、字符串截取

 String substring(int beginIndex) 
参数:传入起始下标

功能:从起始下标开始,截取自下标以后的字符串

返回值:返回字符串
        

让我们看看实例:

public class Test3 {
    public static void main(String[] args) {
      String str1="abcdef";
      String str2=str1.substring(1);//从下标1开始截取
        System.out.println(str2);
        
         str2=str1.substring(2);//从下标2开始截取
        System.out.println(str2);
      }
    }

程序运行:

 


substring的重载方法:

 String substring(int beginIndex, int endIndex) 
参数:起始下标  终止下标
功能:从起始下标开始截取字符串,直到终止下标前一个字符结束(左闭右开)

让我们看看实例:

public class Test3 {
    public static void main(String[] args) {
      String str1="abcdef";
      String str2=str1.substring(1,3);//截取下标[1,3)左闭右开
        System.out.println(str2);
        str2=str1.substring(1,4);//截取下标[1,4)
        System.out.println(str2);

      }
    }

程序运行:



七、 去除字符串空格

trim()方法是用来去除字符串前后空格的,不包括字符串中间的空格!

让我们直接看看例子:

public class Test3 {
    public static void main(String[] args) {
      String str1="   abcd  ef  ";
        System.out.println(str1);
        String str2=str1.trim();
        System.out.println(str2);

      }
    }

程序运行结果:

如图,分别打印了str1和str1去除空格后的str2。

可以发现:该方法只去除了字符串前后的空格,而没有去除字符串中间的空格!



八、字符串的不可变性

在我们之前学习的方法过程中,以转换大小写为例子!

public class Test3 {
    public static void main(String[] args) {
      String str1="abc";
      String str2=str1.toUpperCase();
      System.out.println("str1: "+str1);
      System.out.println("str2: "+str2);

      }
    }

在这个代码运行结果出来之前,我们可以思考一下:有两种可能!

猜想1:

这个toUpperCase()方法最终会返回一个字符串,返回的该字符串是str1指向的字符串。程序将str1指向的字符串内容修改后,再返回其字符串的地址。

猜想2:

程序重新产生了一个新的String类的对象,其内容为转换大写后的字符串!然后再返回这个全新的字符串。

 

看看程序运行的结果:

根据结果:我们得知:

1、str1指向的字符串内容没有改变!

2、toUpperCase方法重新产生了一个对象!猜想2正确!



前面介绍这么多!只为了引入现在的正题:字符串的不可变性 !

或许你会觉得奇怪,为什么不修改字符串的内容,而要重新生成一个新的对象?

说实话,不是toUpperCase方法不想改变字符串的内容 ,而是无法字符串的内容无法修改!

因为,字符串具有不可变性!

为什么不可变!我们一起来找找原因!

1、进入String类:

一个String类其中有两个成员变量,每当执行String str =“abc"的时候,这个字符串其实就是一个byte[ ]类型的数组value(第二个红色框)。

如图:

value 的内容是一个地址,这个地址指向字符串的地址!

那么:我们猜想,字符串的不可变性是不是因为这个value被final修饰呢?

因为我们知道,被final修饰的变量是不可改变的!

答:不是!

final修饰的value的内容是一个地址,不可改变的是value这个内容,而不是value指向的这个数组不可改变!

举个例子给大家看看!

public class Test3 {
    public static void main(String[] args) {
      byte [] value1=new byte[]{'a','b','c'};//创建一个byte类型的数组
      final byte [] value2=new byte[]{'a','b','c'};//创建一个byte类型的数组(final修饰)
      byte [] value3=new byte[]{'a'};
        
      value1=value3;//(1)可以执行
      value1[0]='c';//(2)可以执行
      
      value2=value1;//(3)不可以执行,对比(1)(3):说明被final修饰的value2不可以修改它的内容
      value2[0]=value1[0];//(4)可以执行,但是value2指向的数组的内容可以修改!
        
       
      }
    }

通俗点讲!value2就好像一个家庭地址!如果签订长期居住的合同(final修饰),这个家庭地址不可改变!但是家里面的家具等东西(数组)都是可以替换的! 

直到这里!我们得知:字符串的不可变性不是由于这个byte数组被final修饰!



真正原因在于权限!

这个value是由private修饰的,因此在这个类之外无法直接访问value,同时String类中又没有getValue方法,无法在其它类中获取value,因此,字符串具有不可改变性! 



九、StringBuilder类和StringBuffer类

关于字符串的类其实不只有String类,还有StringBuilder类和StringBuffer类!

但是使用它们构造字符串只能通过调用构造方法!

public class Test3 {
    public static void main(String[] args) {
       StringBuilder str1=new StringBuilder("abc");
       StringBuilder str2=new StringBuilder("abc");
        System.out.println(str1);
        System.out.println(str2);

      }
    }

它们都有一个字符串拼接方法append()方法。这个方法会拼接两段字符串!并且返回一个字符串!

举个例子,顺便说说这两个类的拼接与Stirng类的字符串有什么不同!

与String类的字符串不同的是:StringBulider类和StringBuffer类的字符串的拼接不会再产生一个新的对象!它是在原来的字符串上修改字符串的内容!



append方法使用:

public class Test3 {
    public static void main(String[] args) {
       StringBuilder str1=new StringBuilder("hello");
       StringBuilder str2=new StringBuilder("hello");
       str1.append("world");
       str2.append("world");


        System.out.println("str1: "+str1);
        System.out.println("str2: "+str2);



      }
    }

 程序运行结果:

可以看到,这个append方法直接修改了原字符串的内容!



 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值