• JavaSE学习值之--String类


      💕"不要同情自己,同情自己是卑劣懦夫的勾当!"💕

    作者:Mylvzi 

     文章主要内容:JavaSE学习值之--String类 

    目录

    前言:

    一.String类

    1.String类的属性

    2.字符串的构造

    注意:

    1.String类有求字符串长度的方法通过:str.length()   

    2.isEmpty方法用于判断字符串的长度是否为0

    3.被" "引起来的就是字符串,可直接调用方法 

    3.String类对象的比较

    1.==判断是否是同一引用(地址相同)

    2.equals 方法

    3.compareTo以及他的接口

    4. 字符串查找

    1.charAt方法--》返回对应索引上的字符

    2.indexOf方法,lastIndexOf 方法--》不止一个,有多个,构成了方法的重载

    1.单个字符(从前往后找)

     2.查找子字符串(从前往后找)

    5.字符串的转化

    1.数值和字符串之间的转化

    2.大小写互换--》toUpperCase  toLowerCase

    3.. 字符串转数组 

    4. 格式化(以特定的格式输出字符串)

    6.字符串替换

    7.字符串的拆分

    1.split方法--》返回值是String[],所以要用字符串数组接收

    2.特殊字符的拆分

    1.拆分IP地址

    2.多次分割(开发常用)

    7.字符串截取

    8.其他操作方法

    1.trim方法:

    8.字符串的不可变性

    1.这张图能反应很多信息:

    2.所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象

    二.StringBuilder和StringBuffer的介绍

    一.StringBuilder

    常见方法总结:

    1.append--》字符串追加

    2.setCharAt(int index, char ch)-->将index位置的字符重置为ch

    3.insert(int offset, String str) -->在offset位置插入:八种基类类型 & String类型 & Object类型数据

     4.deleteCharAt(int index)--》删除index位置字符 

    5.replace(int start, int end, String str)--》将指定区间的字符串设置为str

    6.StringBuffer reverse()-->倒置字符串

    7.toString方法-->以字符串(String)类型返回


    前言:

      在C语言中我们已经接触过字符串,在C语言中不存在字符串类型,存储字符串往往是通过字符数组或字符指针,同时C语言的库中也提供了很多与字符串有关的函数,如strcpy,strcat,strstr等等,但是这种将数据和操作方法分割的做法不符合面向对象编程的思想,所以在Java中提供了字符串类型--》String

      String类本质上是class,含有属性和方法,方法之中存放了大量且实用的与字符串有关的方法

    下面就为大家详细讲解String类

    一.String类

    1.String类的属性

    注意:Java中的字符串区别于C语言,并不存在“字符串以\0结尾”这种说法 

    2.字符串的构造

      下面介绍常见的三种字符串构造方法:

    1. /**
    2. * 字符串构造
    3. */
    4. // 1.直接构造
    5. String str1 = "hello";
    6. System.out.println(str1);
    7. // 2.实例化一个String类对象
    8. String str2 = new String("hello");
    9. System.out.println(str2);
    10. // 3.通过字符数组的转化
    11. char[] arr = {'h','e','l','l','o'};
    12. String str3 = new String(arr);
    13. System.out.println(str3);

    注意Java中String类是一种引用数据类型,存放的引用对象的地址,而不存储对象本身

    1. // String类是一种引用类型,存储的是对象的地址
    2. // s1和s2引用的是不同对象 s1和s3引用的是同一对象
    3. String s1 = new String("hello");
    4. String s2 = new String("world");
    5. String s3 = s1;
    6. System.out.println(s1.length()); // 获取字符串长度---输出5
    7. System.out.println(s1.isEmpty()); // 如果字符串长度为0,返回true,否则返回false

    注意:

    1.String类有求字符串长度的方法通过:str.length()   

     STtring类里面的length是一种方法,数组里面的是一种属性,方法有一个();

    2.isEmpty方法用于判断字符串的长度是否为0

    注意isEmpty判断的是字符串的长度,如果字符串是null,此时代表空引用,编译器会报错 

    1. String s1 = "";
    2. System.out.println(s1.length());// 输出0
    3. String s2 = null;
    4. System.out.println(s2.length());// 报错

    3.被" "引起来的就是字符串,可直接调用方法 

            System.out.println("hello".length());// 输出5

    3.String类对象的比较

    1.==判断是否是同一引用(地址相同)

    == 

    左右两边都是基本数据类型,比较的是值的大小,根据值是否相等返回false/true

    左右两边都是引用数据类型,比较的是引用对象的地址是否相同,也就是是否是同一引用

    1. // String类是一种引用类型,存储的是对象的地址
    2. // s1和s2引用的是不同对象 s1和s3引用的是同一对象
    3. String s1 = new String("hello");
    4. String s2 = new String("world");
    5. String s3 = s1;
    6. System.out.println(s1 == s2);// false
    7. System.out.println(s2 == s3);// false
    8. System.out.println(s1 == s3);// true

    来看一种特殊情况:

      当我们直接引用字符串”hello“ 时,str1和str2却相等了?这是为什么?引用类型比较的不是地址吗?是的,比较的是地址。但对于"hello"这样的字符串来说,他是存储在堆区之中的”常量池“上,地址是固定的。也就是说,当第一次使用hello给str1赋值后,常量区上就已经存放了hello这个字符串,再次赋值是会先从常量池中的"hello"获取,获取的和str1是一样的"hello"(地址和值都是一样的)

    2.equals 方法

      ==只能用来比较两个引用对象的地址是否相同,而大多数情况下我们是通过引用类型的内容来判断是否相等的,对于String类来说也是这样的,我们要比较的是字符串的具体内容,而String类中有一个自带的比较内容的方法-->equals(本质还是继承于Object类的

    )

    1. String str1 = "hello";
    2. String str2 = "hello";
    3. String str3 = "world";
    4. System.out.println(str1.equals(str2));// true
    5. System.out.println(str1.equals(str3));// false

    总结:
      equals方法用来判断两个字符串的内容是否相同 

    3.compareTo以及他的接口

    再来看String类的定义:

    可以看见String类实现了Comparable接口,所以就要重写接口中的compareTo方法

     

    比较思路: 

    如果两个字符串的长度不一样,先比较长度相同的部分,如果长度相同部分完全相同,则直接返回长度的差值(共同长度是最短字符串的长度) 

    代码示例: 

    1. String str1 = "hello";
    2. String str2 = "hello";
    3. String str3 = "world";
    4. String str4 = "helloworld";
    5. System.out.println(str3.compareTo(str1));// 15
    6. System.out.println(str1.compareTo(str2));// 0
    7. System.out.println(str4.compareTo(str1));// 输出5
    8. System.out.println("====================");
    9. String str5 = "abc";
    10. String str6 = "acc";
    11. System.out.println(str5.compareTo(str6));// 输出-1
    compareToIgnoreCase方法

      在一些情况下,我们认为大写和小写只是形式上的不同,内容却是相同的,比如"hello"=="HELLO",在不考虑大小写的情况下进行比较,就可以利用方法

    compareToIgnoreCase
    1. String str1 = "hello";
    2. String str2 = "HELLO";
    3. String str3 = "HEllo";
    4. System.out.println(str1.compareToIgnoreCase(str2));// 0
    5. System.out.println(str1.compareToIgnoreCase(str3));// 0

    总结:
    1.compareTo方法返回的Int类型的数据,本质上是对应字符串在字典上的顺序(字典中,前面的字母是小的,后面的字母大,小写比所有大写大) 

    2.忽略大小写带来的形式上的不同,我们可以利用compareToIgnoreCase方法

    3.自定义类型一定要重写equals方法和hashcode方法,因为你的逻辑是根据自定义类型的内容进行比较的

    4. 字符串查找

      字符串查找也是字符串中非常常见的用法,String类中也提供了很多字符串查找的方法

    1.charAt方法--》返回对应索引上的字符

    1. String str1 = "abcdef";
    2. System.out.println(str1.charAt(0));// 输出a
    3. System.out.println(str1.charAt(1));// 输出b
    4. System.out.println(str1.charAt(2));// 输出c
    5. System.out.println(str1.charAt(-1));// 异常
    6. System.out.println(str1.charAt(100));// 异常

    2.indexOf方法,lastIndexOf 方法--》不止一个,有多个,构成了方法的重载

    1.单个字符(从前往后找)
    1. String str1 = "abcdefghcde";
    2. System.out.println(str1.indexOf('a'));// 0
    3. System.out.println(str1.indexOf('b'));// 1
    4. System.out.println(str1.indexOf('c'));// 2
    5. System.out.println("==================");
    6. System.out.println("从指定index开始访问");
    7. System.out.println(str1.indexOf('c', 3));// 8 返回的是第二个c出现的位置
    8. System.out.println(str1.indexOf('a', 1));// -1 1代表从b开始,后面不含有a
    9. System.out.println("==================");
    10. System.out.println("从后往前找");
    11. System.out.println(str1.lastIndexOf('c'));// 8
    12. System.out.println(str1.lastIndexOf('e'));// 10
    13. System.out.println(str1.lastIndexOf('c', 4));// 2

     

    注意:indexOf方法只返回第一次出现的下标(从左往右)

     2.查找子字符串(从前往后找)
    1. String str1 = "abcdefghcde";
    2. // 返回子字符串第一次出现位置的下标
    3. System.out.println(str1.indexOf("ab"));
    4. System.out.println(str1.indexOf("cd"));
    5. System.out.println(str1.indexOf("de"));
    6. System.out.println("===================");
    7. System.out.println("从指定索引位置之后返回子字符串出现的位置");
    8. System.out.println(str1.indexOf("cd", 4));// 8
    9. System.out.println(str1.indexOf("de",6));// 9
    10. System.out.println("===================");
    11. System.out.println("从后往前查找");
    12. /**
    13. * 注意返回都是第一个字符的下标
    14. */
    15. System.out.println(str1.lastIndexOf("cd"));// 8
    16. System.out.println(str1.lastIndexOf("de"));// 9
    17. System.out.println(str1.lastIndexOf("cd", 5));// 2

    5.字符串的转化

    1.数值和字符串之间的转化

    1. class Student {
    2. String name;
    3. int age;
    4. public Student(String name, int age) {
    5. this.name = name;
    6. this.age = age;
    7. }
    8. }
    9. public class Test1 {
    10. public static void main(String[] args) {
    11. /**
    12. * 其他类型转字符串(布尔类型和引用类型也能转化)
    13. * String.valueOf方法
    14. */
    15. String s1 = String.valueOf(1234);
    16. String s2 = String.valueOf(12.34);
    17. String s3 = String.valueOf(true);
    18. String s4 = String.valueOf(new Student("Hanmeimei", 18));
    19. System.out.println(s1);
    20. System.out.println(s2);
    21. System.out.println(s3);
    22. System.out.println(s4);
    23. System.out.println("=======================");
    24. /**
    25. * 字符串转其他类型
    26. * 通过其他类型的包装类中的parse方法
    27. */
    28. int a = Integer.parseInt("12345");
    29. double b = Double.parseDouble("12.20");
    30. boolean c = Boolean.parseBoolean("true");
    31. System.out.println(a);
    32. System.out.println(b);
    33. System.out.println(c);

    2.大小写互换--》toUpperCase  toLowerCase

    1. String str1 = "hello";
    2. String str2 = "WROLD";
    3. String str3 = "Hello";
    4. // 小写转大写
    5. System.out.println(str1.toUpperCase());
    6. // 大写转小写
    7. System.out.println(str2.toLowerCase());
    8. System.out.println(str3.toLowerCase());

    3.. 字符串转数组 

    1. String str1 = "hello";
    2. char[] value = str1.toCharArray();
    3. for (int i = 0; i < value.length ; i++) {
    4. System.out.print(value[i] + " ");
    5. }
    6. System.out.println();
    7. System.out.println("====================");
    8. // 字符数组转字符串(字符串的构造)
    9. char[] value2 = {'h','e','l','l','o'};
    10. String str2 = new String(value2);
    11. System.out.println(str2);

     

    4. 格式化(以特定的格式输出字符串)

    1. String s = String.format("%d-%d-%d", 2019, 9,14);
    2. System.out.println(s);// 输出2019-9-14

    6.字符串替换

      用另一个字符串代替当前字符串中的某些内容

    1. String str1 = "hello world";
    2. // 单个字符替换
    3. System.out.println(str1.replace('o', 'x'));// hellx wxrld 两个o都被替换了
    4. // 字符串替换
    5. System.out.println(str1.replace("hello", "xxxxxxx"));
    6. // 替换首个位置
    7. // replaceFirst的参数只能是字符串
    8. System.out.println(str1.replaceFirst("o","x"));// hellx world 只替换第一个o
    9. // replaceAll 用于基于正则表达式的文本替换
    10. System.out.println(str1.replaceAll("o", "x"));
    11. // replace的返回值是一个新的字符串,不是对原字符串进行修改
    12. // java中字符串是常量,无法被修改
    13. String str2 = str1.replace('e','d');

    7.字符串的拆分

    1.split方法--》返回值是String[],所以要用字符串数组接收

    1. String str1 = "how are you man?";
    2. String[] value = str1.split(" ");
    3. for (String s:value) {
    4. System.out.println(s);
    5. }
    6. System.out.println("===================");
    7. // 就分两组
    8. String[] value2 = str1.split(" ",2);
    9. for (String s:value2) {
    10. System.out.println(s);
    11. }

      

    2.特殊字符的拆分

      在使用split方法时,传递的参数是字符,但是有些字符本身就有特定的作用(+-*\等等),需要使用转义字符进行转义

    1.拆分IP地址
    1. String str = "192.168.1.1" ;
    2. String[] result = str.split("\\.") ;
    3. for(String s: result) {
    4. System.out.println(s);
    5. }

    1. 字符"|","*","+"都得加上转义字符,前面加上 "\\" .

    2. 而如果是 "\" ,那么就得写成 "\\\\" .

    3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符 

    1. String str = "192\\168\\1\\1" ;// 在字符串中使用\需要先进行转义
    2. String[] result = str.split("\\\\") ;
    3. for(String s: result) {
    4. System.out.println(s);
    5. }
    2.多次分割(开发常用)

       在进行分割时,一个字符串内往往含有多个不同的符号,一次split只能以一个符号进行分割,如果想实现多次分割,可以利用嵌套的for循环进行多次分割

    1. public static void main(String[] args) {
    2. String str = "name=李四&age=17";
    3. String[] arr1 = str.split("&");
    4. for (int i = 0; i
    5. String[] tmp = arr1[i].split("=");
    6. System.out.println(tmp[0]+" = "+ tmp[1]);
    7. }
    8. }

    7.字符串截取

    从当前字符串某个索引位置处进行截取

    1. String str = "helloworld";
    2. System.out.println(str.substring(5));// 输出world
    3. System.out.println(str.substring(0, 5));// 输出hello java中的区间都是左闭右开的

    注意事项:

    1. 索引从0开始

    2. 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标 

    8.其他操作方法

    1.trim方法:

    代码示例: 

    1. String str = " hello world !!!!!!!!!";
    2. System.out.println(str.trim());

    注意:

    1.trim方法只能去除字符串左右两边的空格,中间的空格无法删除

    2.trim方法其实在搜索引擎中经常出现,比如你故意在搜索时在前面添加了一大堆的空格,而你在搜索的时候,浏览器会自动把字符前面的所有空格进行删除,这就是调用了trim方法

    8.字符串的不可变性

      String类型的数据是一种不可改变的数据类型,来看她的定义

    1.这张图能反应很多信息:

    1.String类被final修饰,代表不能被其他类继承

    2.字符串实际上是存储在Value数组之中的,value也是一种引用类型

    3.value数组被private修饰,代表无法在类外使用该数组,也就证明该数组的内容无法改变,也就是字符串的内容无法改变

    一个误区:

      很多人说String类无法改变是因为value数组被final修饰,这是错误的,因为value数组被final修饰,只能说明value不能指向其他的引用,但是其所指向的对象是可以改变的(类似于const char*) 

    1. final int[] arr = {1,2,3,4,5};
    2. arr[0] = 10000;
    3. System.out.println(Arrays.toString(arr));

    2.所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象

    StringBuilder也是与字符串相关的一个类,其中有一个append方法,用于字符串的追加

    可以发现,在对字符串s进行追加时,实际上是又重新创建了一个字符串,使这个字符串为两个字符串append之后的结果,最后再将这个字符串重新赋值给s 

    二.StringBuilder和StringBuffer的介绍

    前言:

      由于stirng的不可改变性,对于字符串的操作有了一定的限制,为了更加方便地操作字符串,引入两个新的类:StringBuilder和StringBuffer,这两个类的基本用法一致

    一.StringBuilder

    常见方法总结:

    1.append--》字符串追加
    1. //StringBuilder是一个类,必须先进行实例化对象
    2. StringBuilder str = new StringBuilder("hello");
    3. StringBuilder str2 = str;
    4. // 利用append进行追加 可追加字符,数字,字符串
    5. str.append(' ');
    6. str.append(123);
    7. str.append("world");
    8. str.append('!');
    9. System.out.println(str);

    注意:

    1.append方法的存在大大提高了新建字符串的效率,因为append方法在执行的时候是直接在位于缓冲区的字符数组之后添加字符的,并没有新建临时对象,减少了内存的不必要开辟和释放

    2.可直接打印StringBuilder类的对象,因为其内部重写了toString方法

    2.setCharAt(int index, char ch)-->将index位置的字符重置为ch
    1. StringBuilder str = new StringBuilder("hello");
    2. str.setCharAt(0,'!');
    3. str.setCharAt(1,'!');
    4. str.setCharAt(2,'!');
    5. System.out.println(str);

    3.insert(int offset, String str) -->在offset位置插入:八种基类类型 & String类型 & Object类型数据
    1. StringBuilder str = new StringBuilder("hello");
    2. // insert方法
    3. // 并没有删除原位置的字符,而是在其之前插入另一个数据
    4. str.insert(0,'!');
    5. System.out.println(str);// !hello
    6. str.insert(6,"world");
    7. System.out.println(str);// !helloworld
    8. str.insert(0,123456);
    9. System.out.println(str);// 123456!helloworld

    注意: insert方法并没有删除原位置的字符,而是在其之前插入另一个数据

     4.deleteCharAt(int index)--》删除index位置字符 
    1. StringBuilder str = new StringBuilder("hello");
    2. System.out.println(str.deleteCharAt(0));// ello
    3. System.out.println(str.deleteCharAt(0));// llo
    4. // delete 删除指定区间内的所有字符
    5. StringBuilder str2 = new StringBuilder("hello");
    6. System.out.println(str2.delete(0, 2));// llo
    5.replace(int start, int end, String str)--》将指定区间的字符串设置为str
    1. StringBuilder str = new StringBuilder("hello!!!!");
    2. str.replace(1,6,"world");
    3. System.out.println(str);// hworld!!!
    6.StringBuffer reverse()-->倒置字符串
    1. StringBuilder str = new StringBuilder("hello!!!!world");
    2. System.out.println(str.reverse());// dlrow!!!!olleh

    这是一个非常有用 的方法,在很多刷题网站中都有倒置字符串的实现,通过S听Builder自带的reverse方法可以快速实现!!! 

    源码:

    1. public AbstractStringBuilder reverse() {
    2. boolean hasSurrogates = false;
    3. int n = count - 1;
    4. for (int j = (n-1) >> 1; j >= 0; j--) {
    5. int k = n - j;
    6. char cj = value[j];
    7. char ck = value[k];
    8. value[j] = ck;
    9. value[k] = cj;
    10. if (Character.isSurrogate(cj) ||
    11. Character.isSurrogate(ck)) {
    12. hasSurrogates = true;
    13. }
    14. }
    15. if (hasSurrogates) {
    16. reverseAllValidSurrogatePairs();
    17. }
    18. return this;
    19. }

    7.toString方法-->以字符串(String)类型返回

     String和StringBuffer不能直接赋值,必须通过StringBuffer的toString方法才能转换

    1. StringBuilder str = new StringBuilder("hello!!!!world");
    2. // String str2 = str;// err
    3. String newstr = str.toString();
    4. System.out.println(newstr);// hello!!!!world

    StringBuilder和StringBuffer也包含String类型中常见的方法,如indexOf,charAt,substring,length等方法,其用法和String类基本一致,此处不再详细阐述

    总结:

    String类是一个非常常用的类,要掌握其包含的常见方法的使用,深入理解String不能被改变和继承的原因;同时为了解决String类的一些缺陷,引入了两个新的类 StringBuilder和StringBuffer,这两个类可以看作String类的更高效的版本,其中有很多方法与String类重合,但也有很多自己独有的,非常有效的方法,了解这些方法会大大提高我们的开发效率!!!

    三.再谈String类

    1.字符串常量池

      呃呃,笔者经过进一步的学习又了解到了关于String类的相关知识,在这里进行更多的补充

    先来看一下String的源码

    在Java中String是一个类,每个String对象都有两个属性  value和hash ,value就是存储的值,hash就是对象对应的hash值

    再来看下述代码

    1. String s1 = "hello";
    2. String s2 = "hello";
    3. String s3 = new String("hello");
    4. String s4 = new String("hello");;
    5. System.out.println(s1 == s2);// true
    6. System.out.println(s3 == s4);// false

    为什么s1和s2就相等呢?对象的比较不是根据对象的地址进行判断的么?在这里,引入一个概念--字符串常量池

      在Java中,所有被""引起来的都叫做字符串常量,所有的字符串都是存储到Java中一个名叫”字符串常量池“的存储区域中,但是官方并没有这个概念,而是使用一个叫做StringPool的方法将字符串常量存储起来,而StringPool的底层其实是StringTable,它是由哈希表实现的(使用c++编写)。

    1.String s1 = "hello";这句代码实际上是将hello存储到StringTable之中,建立了对应的映射关系

    2.String s2 = "hello";在为s2进行赋值时,会先在StringTable中判断hello是否存在,如果存在就不再重复放,如果不存在,将值存入;(hashTable的特性)

    3.hello此时已经存在于StringTable之中,不再存入,而是直接从表中获取数据,也就是说s1和s2拿到的数据的地址是相同的!!!

    而对于s3,s4来说,他们是通过new来实例化一个新的对象,则必然在内存中重新开辟一块内存,他们的地址不相同

     

    2.intern方法 

    先来看下面代码

    1. char[] arr = new char[] {'a','b','c'};
    2. String s1 = new String(arr);
    3. String s2 = "abc";
    4. System.out.println(s1 == s2);// false

    分析:

     

      运用我们前面学习过的知识很容易判断

    再来看下面代码

    1. char[] arr = new char[] {'a','b','c'};
    2. String s1 = new String(arr);
    3. s1.intern();
    4. String s2 = "abc";
    5. System.out.println(s1 == s2);// true

     为什么就输出true呢?intern方法是什么?

      intern方法就是将引用存入到常量池之中,intern方法是native的,底层是用c/c++写的

  • 相关阅读:
    在 C# 中对比KeyValuePair<TKey, TValue> 和 IDictionary<TKey, TValue>
    一文详解微服务架构
    DDD实践:实现基于快照机制的变更追踪
    如何在jar包外设置配置文件
    linux系统目录结构、上传下载文件、命令及用法
    【某南方·高中梦校面试】
    权威敏捷产品经理(CSPO)企业培训
    竞赛 题目:基于深度学习的中文对话问答机器人
    ADC噪声全面分析 -02- ADC 噪声测量方法和相关参数
    Android Camera性能分析 - 第18讲 预览Buffer Path详解
  • 原文地址:https://blog.csdn.net/Mylvzi/article/details/133531651