【Java SE语法篇】10.String类

简介: 【Java SE语法篇】10.String类


前言

在程序开发中经常会用到字符串。字符串是指一连串的字符,它是由许多单个字符连接而成的,如多个英文字母所组成的英文单词。字符串可以包含任意字符,这些字符必须包含在一对双引号""之内,例如:“abc”。Java定义了3个封装字符串的类,分别是String类、StringBuffer类和StringBulider类。它们位于java.lang 包中,并提供了一系列操作字符串的方法,这些方法不需要导包就可以直接使用。下面将对String类、StringBuffer类和StringBulider类进行讲解。

1. String类

1.1 字符串的构造

String类提供了构造方法非常多,常用的就以下三种:

public class Main {
    public static void main(String[] args) {
        // 使用常量串构造
        String s1 = "hello";
        System.out.println(s1);
        // 直接new String对象
        String s2 = new String("hello");
        System.out.println(s2);
        // 使用字符数组进行构造
        char[] chars = {'h','e','l','l','o'};
        String s3 = new String(chars);
        System.out.println(s3);
    }
}

其他方法需要用到时,大家参考Java在线文档:String官方文档

【注意】:

  1. String是引用类型,内部并不存储字符串本身,在String类的实现源码中,String类实例变量如下:
public class Main {
    public static void main(String[] args) {
        // s1和s2引用的是不同对象  s1和s3引用的是同一对象
        String s1 = new String("hello");
        String s2 = new String("world");
        String s3 = s1; // s3这个引用指向了s1这个引用的对象
        System.out.println(s3); // hello
        System.out.println(s1.length());// 获取字符串的长度
        System.out.println(s1.isEmpty());// 如果字符串长度为0,返回true,否则返回false
        String s4 = "";
        System.out.println(s4.length()); // 0
        System.out.println(s4.isEmpty());// true
}
  1. 内存图:

  1. 在Java中""引起来的也是String类型对象
// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());// 5

1.2 String对象的比较

字符串的比较是常见操作之一,比如:字符串排序。Java中总共提供了4种方式:

1. ==比较是否引用同一个对象

注意:对于内置类型,==比较的是变量中的值;对于引用类型==比较的是引用中的地址。

public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int c = 10;
        // 对于基本类型变量,==比较两个变量中存储的值是否相同
        System.out.println(a == b);    // false
        System.out.println(a == c);    // true
        // 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
        String s1 = new String("hello");
        String s2 = new String("hello");
        String s3 = new String("world");
        String s4 = s1;
        System.out.println(s1 == s2);   // false
        System.out.println(s2 == s3);   // false
        System.out.println(s1 == s4);   // true
    }
}

2. equals()方法:按照字典序比较

字典序:字符大小的顺序

String类重写了父类Objectequals方法,Objectequals默认按照==比较,String重写equals方法后,按照 如下规则进行比较,比如:s1.equals(s2)

public class Main {
    public static void main(String[] args) {
        String s1 = new String("hello");
        String s2 = new String("hello");
        String s3 = new String("Hello");
        // s1、s2、s3引用的是三个不同对象,因此==比较结果全部为false
        System.out.println(s1 == s2);       // false
        System.out.println(s1 == s3);       // false
        // equals比较:String对象中的逐个字符
        // 虽然s1与s2引用的不是同一个对象,但是两个对象中放置的内容相同,因此输出true
        // s1与s3引用的不是同一个对象,而且两个对象中内容也不同,因此输出false
        System.out.println(s1.equals(s2));  // true
        System.out.println(s1.equals(s3));  // false
    }
}

【注意】:为什么以下代码输出的结果都是true

答:因为在 Java 中有一块特殊的内存(常量池),存储在堆上。

它的作用是什么呢?

  1. 只要是""双引号括起来的字符串存放在这里。
  2. 存储字符串之前它会找常量池里是否存在这个字符串,如果有就不存放了(常量池不会重复存放相同的值),所以上述代码中s1s2都指向常量池hello的地址。

3. compareTo()方法: 按照字典序进行比较

equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。具体比较方式:

  1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值
  2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值
public class Main {
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("ac");
        String s3 = new String("abc");
        String s4 = new String("abcdef");
        // s1 和 s2 比较大小 s1 > s2 返回大于0的数字 s1 < s2 返回小于0的数字 否则返回0
        // 返回差值就是对应acsii码的差值
        System.out.println(s1.compareTo(s2));   // 不同输出字符差值-1
        System.out.println(s1.compareTo(s3));   // 相同输出 0
        System.out.println(s1.compareTo(s4));   // 前k个字符完全相同,输出长度差值 -3
    }
}

4. 忽略大小写比较

  • equalsIgnoreCase()方法:与equals()方式相同,但是忽略大小写比较。
  • compareToIgnoreCase()方法:与compareTo()方式相同,但是忽略大小写比较。
public class Main {
    public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("Abc");
        System.out.println(s1.equals(s2)); // false
        System.out.println(s1.equalsIgnoreCase(s2)); // true
        System.out.println(s1.compareTo(s2));//32
        System.out.println(s1.compareToIgnoreCase(s2));// 0
    }
}

1.3 字符串查找

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

方法 功能
char charAt(int index) 返回index位置上字符,如果index为负数或者越界,抛出 IndexOutOfBoundsException异常
int indexOf(int ch) 返回ch第一次出现的位置,没有返回-1
int indexOf(int ch, int fromIndex) 从fromIndex位置开始找ch第一次出现的位置,没有返回-1
int indexOf(String str) 返回str第一次出现的位置,没有返回-1
int indexOf(String str, int fromIndex) 从fromIndex位置开始找str第一次出现的位置,没有返回-1
int lastIndexOf(int ch) 从后往前找,返回ch第一次出现的位置,没有返回-1
int lastIndexOf(int ch, int fromIndex) 从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返 回-1
int lastIndexOf(String str) 从后往前找,返回str第一次出现的位置,没有返回-1
int lastIndexOf(String str, int fromIndex) 从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返 回-1
public class Main {
    public static void main(String[] args) {
        String s1 = new String("hello");
        // 返回字符串对应下标的字符
        System.out.println(s1.charAt(1)); // e
        //返回对应字符出来的下标位置 从头开始查找
        System.out.println(s1.indexOf('e')); // 1
        //返回对应字符出来的下标位置 从指定位置查找
        System.out.println(s1.indexOf('l', 3)); // 3
        // 字符串查找 从一个字符串找另一个字符串
        System.out.println(s1.indexOf("llo")); // 2
        System.out.println(s1.indexOf("ll", 2));// 2
        // 返回对应字符出来的下标位置 从尾开始向前查找
        System.out.println(s1.lastIndexOf('l'));// 3
        // 返回对应字符出来的下标位置 从指定位置向前查找
        System.out.println(s1.lastIndexOf('l', 1));// -1
        System.out.println(s1.lastIndexOf("ll")); // 2
        System.out.println(s1.indexOf("ll", 1));// 2
    }
}

1.4 转换

1. 数值和字符串转化

public class Main {
    public static void main(String[] args) {
        // 数字转字符串
        String s1 = String.valueOf(123);
        System.out.println(s1);
        String s2 = String.valueOf(12.34);
        System.out.println(s2);
        String s3 = String.valueOf(true);
        System.out.println(s3);
        // 字符串转数字
        int num1 = Integer.parseInt("1234");
        System.out.println(num1);
        
        double num2 = Double.parseDouble("12.34");
        System.out.println(num2);
    }
}

2. 大小写转化

public class Main {
    public static void main(String[] args) {
        // 小写转大写
        String s1 = "hello";
        System.out.println(s1.toUpperCase());
        // 大写转小写
        String s2 = "HELLO";
        System.out.println(s2.toLowerCase());
    }
}

问题:转化为大写/小写是在原来的字符串上进行修改的?

答:不是!!!,转化为大写/小写之后,是产生了一个新的对象

通过String类源码中的toUpperCase()方法和toLowerCase()方法返回的都是一个新的字符串。

验证:


3. 字符串转数组

public class Main {
    public static void main(String[] args) {
        // 字符串转数组
        String s1 = "hello";
        char[] chars = s1.toCharArray();
        for (char ch  : chars) {
            System.out.println(ch);
        }
        
        // 数组为字符串
        String s2 = new String(chars);
        System.out.println(s2);
    }
}

4. 格式化

public class Main {
    public static void main(String[] args) {
        String s1 = String.format("%d-%d-%d",2021,5,19);
        System.out.println(s1);
    }
}

1.5 字符串替换

使用一个指定的新的字符串替换掉已有的字符串数据,可用的方法如下:

方法 说明
String replaceAll(String regex, String replacement) 替换所有的指定内容
String replaceFirst(String regex, String replacement) 替换收个内容
public class Main {
    public static void main(String[] args) {
        String s1 = "abcabcdeabcd";
        System.out.println(s1.replace('a', 'p')); // pbcpbcdepbcd
        System.out.println(s1.replace("ab","haha")); // hahachahacdehahacd
        System.out.println(s1.replaceAll("ab", "uuu")); // uuucuuucdeuuucd
        System.out.println(s1.replaceFirst("ab", "ha")); // hacabcdeabcd
    }
}

1.6 字符串拆分

可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串。

方法 功能
String[] split(String regex) 将字符串全部拆分
String[] split(String regex, int limit) 将字符串以指定的格式,拆分为limit组
public class Main {
    public static void main(String[] args) {
        String s1 = "name = zhangsan&age = 18";
        String[] strings = s1.split("&");
        for (int i = 0; i < strings.length; i++) {
            System.out.println(strings[i]);
        }
        
        String s2 = "Hello handsome hello beautiful give me some attention"; 
        // 帅哥美女点点关注
        String[] strings1 = s2.split(" ",12); 
        // 虽然不能分割12次 但是它能够保证能分割的最大次数 不够就不分了
        for (int i = 0; i < strings1.length; i++) {
            System.out.println(strings1[i]);
        }
    }
}

特殊情况:

public class Main {
    public static void main(String[] args) {
        String s1 = "192.168.1.2";
        String[] strings = s1.split("\\.");
        for (int i = 0; i < strings.length; i++) {
            System.out.println(strings[i]);
        }
        System.out.println("=========");
        String s2 = "C:\\APP\\Java\\jdk1.8\\bin\\java.exe";
        String[] strings1 = s2.split("\\\\");
        for (int i = 0; i < strings1.length; i++) {
            System.out.println(strings1[i]);
        }
        System.out.println("=========");
        
        String s3 = "name=zhangsan&age=18";
        String[] strings2 = s3.split("&|=");
        for (int i = 0; i < strings2.length; i++) {
            System.out.println(strings2[i]);
        }
    }
}

【注意事项】:

  1. 字符"|“,”*“,”+“都得加上转义字符,前面加上”\".
  2. 而如果是"“,那么就得写成”\\".
  3. 如果一个字符串中有多个分隔符,可以用"|"作为连字符.

多次拆分:

public class Main {
    public static void main(String[] args) {
        String s1 = "name=zhangsan&age=18";
        String[] strings = s1.split("&");
        for (String x:strings) {
            String[] strings2 = x.split("=");
            for (String x1 :strings2) {
                System.out.println(x1);
            }
        }
    }
}

1.7 字符串的截取

从一个完整的字符串之中截取出部分内容。可用方法如下:

方法 功能
String substring(int beginIndex) 从指定索引截取到结尾
String substring(int beginIndex, int endIndex) 截取部分内容
public class Main {
    public static void main(String[] args) {
        String s1 = "helloworld" ;
        System.out.println(s1.substring(5)); // world
        System.out.println(s1.substring(0, 5)); 
        // hello 包含 0 下标的字符, 不包含 5 下标
    }
}

1.8 其他操作

方法 功能
String trim() 去掉字符串中的左右空格,保留中间空格

代码案例:trim()方法:

public class Main {
    public static void main(String[] args) {
        String str = "   hello  world   " ;
        System.out.println("["+str+"]");// [   hello  world   ]
        System.out.println("["+str.trim()+"]");// [hello  world]  
    }
}

trim 会去掉字符串开头和结尾的空白字符(空格, 换行, 制表符等).

2. StringBuilde 类 和 StringBuffer类

由于String的不可更改特性,为了方便字符串的修改,Java中又提供StringBuilderStringBuffer类。这两个类大 部分功能是相同的,这里介绍 StringBuilder常用的一些方法,其它需要用到了大家可参阅 [StringBuilder在线文档](Overview (Java Platform SE 8 ) (oracle.com))

方法 功能
StringBuff append(String str) 在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、 double、float、int、long、Object、String、StringBuff的变量
char charAt(int index) 获取index位置的字符
int length() 获取字符串的长度
int capacity() 获取底层保存字符串空间总的大小
void ensureCapacity(int mininmumCapacity) 扩容
void setCharAt(int index, char ch) 将index位置的字符设置为ch
int indexOf(String str) 返回str第一次出现的位置
int indexOf(String str, int fromIndex) 从fromIndex位置开始查找str第一次出现的位置
int lastIndexOf(String str) 返回最后一次出现str的位置
int lastIndexOf(String str, int fromIndex) 从fromIndex位置开始找str最后一次出现的位置
StringBuff insert(int offset, String str) 在offset位置插入:八种基类类型 & String类型 & Object类型数据
StringBuffer deleteCharAt(int index) 删除index位置字符
StringBuffer delete(int start, int end) 删除[start, end)区间内的字符
StringBuffer replace(int start, int end, String str) 将[start, end)位置的字符替换为str
String substring(int start) 从start开始一直到末尾的字符以String的方式返回
String substring(int start,int end) 将[start, end)范围内的字符以String的方式返回
StringBuffer reverse() 反转字符串
String toString() 将所有字符按照String的方式返回
public class Main {
    public static void main(String[] args) {
        StringBuilder sb1 = new StringBuilder("hello");
        StringBuilder sb2 = sb1;
        // 追加:即尾插-->字符、字符串、整形数
        sb1.append(' ');                  // hello
        sb1.append("world");              // hello world
        sb1.append(123);                  // hello world123
        System.out.println(sb1);          // hello world123
        System.out.println(sb1 == sb2);   // true
        System.out.println(sb1.charAt(0));   // 获取0号位上的字符  h
        System.out.println(sb1.length());    // 获取字符串的有效长度14
        System.out.println(sb1.capacity());  // 获取底层数组的总大小
        sb1.setCharAt(0, 'H');     // 设置任意位置的字符 Hello world123
        sb1.insert(0, "Hello world!!!");         // Hello world!!!Hello world123
        System.out.println(sb1);
        System.out.println(sb1.indexOf("Hello"));          // 获取Hello第一次出现的位置
        System.out.println(sb1.lastIndexOf("hello"));  // 获取hello最后一次出现的位置
        sb1.deleteCharAt(0);                               // 删除首字符
        sb1.delete(0,5);                                   // 删除[0, 5)范围内的字符
        String str = sb1.substring(0, 5);                  // 截取[0, 5)区间中的字符以String的方式返回
        System.out.println(str);
        sb1.reverse();                      // 字符串逆转
        str = sb1.toString();               // 将StringBuffer以String的方式返回
        System.out.println(str);
    }
}

从上述例子可以看出:StringStringBuilder最大的区别在于**String的内容无法修改**,StringBuilder的内容可 以修改。频繁修改字符串的情况考虑使用StringBuilder

注意:StringStringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:

  • String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
  • StringBuilder变为String: 调用toString()方法。
相关文章
|
1天前
|
存储 安全 Java
java.util的Collections类
Collections 类位于 java.util 包下,提供了许多有用的对象和方法,来简化java中集合的创建、处理和多线程管理。掌握此类将非常有助于提升开发效率和维护代码的简洁性,同时对于程序的稳定性和安全性有大有帮助。
27 17
|
2天前
|
存储 安全 Java
如何保证 Java 类文件的安全性?
Java类文件的安全性可以通过多种方式保障,如使用数字签名验证类文件的完整性和来源,利用安全管理器和安全策略限制类文件的权限,以及通过加密技术保护类文件在传输过程中的安全。
|
6天前
|
Java 数据格式 索引
使用 Java 字节码工具检查类文件完整性的原理是什么
Java字节码工具通过解析和分析类文件的字节码,检查其结构和内容是否符合Java虚拟机规范,确保类文件的完整性和合法性,防止恶意代码或损坏的类文件影响程序运行。
|
6天前
|
存储 Java 编译器
java wrapper是什么类
【10月更文挑战第16天】
15 3
|
7天前
|
监控 安全 Java
在 Java 中使用线程池监控以及动态调整线程池时需要注意什么?
【10月更文挑战第22天】在进行线程池的监控和动态调整时,要综合考虑多方面的因素,谨慎操作,以确保线程池能够高效、稳定地运行,满足业务的需求。
77 38
|
4天前
|
安全 Java
java 中 i++ 到底是否线程安全?
本文通过实例探讨了 `i++` 在多线程环境下的线程安全性问题。首先,使用 100 个线程分别执行 10000 次 `i++` 操作,发现最终结果小于预期的 1000000,证明 `i++` 是线程不安全的。接着,介绍了两种解决方法:使用 `synchronized` 关键字加锁和使用 `AtomicInteger` 类。其中,`AtomicInteger` 通过 `CAS` 操作实现了高效的线程安全。最后,通过分析字节码和源码,解释了 `i++` 为何线程不安全以及 `AtomicInteger` 如何保证线程安全。
java 中 i++ 到底是否线程安全?
|
8天前
|
Java 调度
[Java]线程生命周期与线程通信
本文详细探讨了线程生命周期与线程通信。文章首先分析了线程的五个基本状态及其转换过程,结合JDK1.8版本的特点进行了深入讲解。接着,通过多个实例介绍了线程通信的几种实现方式,包括使用`volatile`关键字、`Object`类的`wait()`和`notify()`方法、`CountDownLatch`、`ReentrantLock`结合`Condition`以及`LockSupport`等工具。全文旨在帮助读者理解线程管理的核心概念和技术细节。
23 1
[Java]线程生命周期与线程通信
|
6天前
|
安全 Java
在 Java 中使用实现 Runnable 接口的方式创建线程
【10月更文挑战第22天】通过以上内容的介绍,相信你已经对在 Java 中如何使用实现 Runnable 接口的方式创建线程有了更深入的了解。在实际应用中,需要根据具体的需求和场景,合理选择线程创建方式,并注意线程安全、同步、通信等相关问题,以确保程序的正确性和稳定性。
|
4天前
|
缓存 Java 调度
Java中的多线程编程:从基础到实践
【10月更文挑战第24天】 本文旨在为读者提供一个关于Java多线程编程的全面指南。我们将从多线程的基本概念开始,逐步深入到Java中实现多线程的方法,包括继承Thread类、实现Runnable接口以及使用Executor框架。此外,我们还将探讨多线程编程中的常见问题和最佳实践,帮助读者在实际项目中更好地应用多线程技术。
11 3
|
6天前
|
监控 安全 Java
Java多线程编程的艺术与实践
【10月更文挑战第22天】 在现代软件开发中,多线程编程是一项不可或缺的技能。本文将深入探讨Java多线程编程的核心概念、常见问题以及最佳实践,帮助开发者掌握这一强大的工具。我们将从基础概念入手,逐步深入到高级主题,包括线程的创建与管理、同步机制、线程池的使用等。通过实际案例分析,本文旨在提供一种系统化的学习方法,使读者能够在实际项目中灵活运用多线程技术。

热门文章

最新文章