IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 【JAVA系列】String类的手术刀剖析 -> 正文阅读

[Java知识库]【JAVA系列】String类的手术刀剖析


一、什么是字符串?

一般来说:

我们说字符串一般指用双引号“”括住的。例如:“aasdfasf”,这是字符串
用单引号’ '括住的,例如:‘asdfasf’,‘你好’,这些都是字符

专业来说:

字符串就是一个或多个字符组成的连续序列,程序需要存储的大量文字、字符都使用字符串进行表示、处理。

二、创建字符串

字符串的创建方法有以下几种:

  1. 使用字符串常量直接初始化
  2. 使用构造方法创建并初始化
  3. 串联方式生成字符串
public static void main(String[] args) {
        String str1="bingo";//直接赋值创建对象str1
        
        String str2=new String("bingo1");//利用构造法创建并初始化对象str2

        String str3="bin"+"go";  //利用串联方式生成新的字符串str3
    }

三、字符串的比较

1.==与equals

==完成的是两个对象的堆内存地址相等判断
equals完成的是字符串内容的比较

String str1 = "Hello";
        String str2 = "Hello";
        String str3 = new String("Hello");
        System.out.println(str1 == str2);//ture
        System.out.println(str1 == str3);//false
        System.out.println(str1.equals(str2));//ture
        System.out.println(str1.equals(str3));//ture

结果如下:
在这里插入图片描述
为什么会出现这样的结果呢?在这里我们需要先了解一下什么是字符串常量池。

2.字符串常量池

为了提高性能和减少开销,JVM提供了一个特殊的内存——常量池。
常量池,就是存储常量的内存空间,有String字符串常量池、包装类常量池等。

   public static void main(String[] args) {

        String str1 = "Hello";//直接赋值创建对象str1
        String str2 = "Hello";//直接赋值创建对象str2
        String str3 = new String("Hello");//利用构造法创建并初始化对象str3
        System.out.println(str1 == str2);//ture
        System.out.println(str1 == str3);//false
        System.out.println(str1.equals(str2));//ture
        System.out.println(str1.equals(str3));//ture
    }

在上面创建字符串有两种方式,一是直接赋值,二是采用构造方法。
那么它们二者在创建时,内存是如何分配的呢?

2.1直接赋值内存分配

我们先来看直接赋值:
如果字符串对象使用直接赋值方式完成,那么str1在第一次定义字符串的时候会自动在堆内存之中定义一个新的字符串常量“hello”,如果之后还有其他字符串对象,比如说str2也是采用直接赋值方式实例化,并且此内容已经存在,那么就不会开辟新的字符串常量,而是直接指向已经开辟的空间,也就是同样指向“hello”开辟的空间。
在这里插入图片描述上面的这种模式,我们称为共享设计模式。

【共享设计模式】

在JVM底层,准备出一个对象池(多个对象),如果现在按照某一个特定方式进行对象实例化的操作,那么次对象的内容会保存到对象池之中,而后如果还有其他的对象也采用了固定的方式声明了与之相同的内容,则此时将不会保存新对象到对象池之中,而是从对象池中取出已有的对象内容继续使用。这样一来就可以有效的减少垃圾空间 的产生。

2.2构造方法内存分配

  public static void main(String[] args) {

        String str1 = "Hello";//直接赋值创建对象str1
        String str2 = "Hello";//直接赋值创建对象str2
        String str3 = new String("Hello");//利用构造法创建并初始化对象str3
        String str4 = new String("Hello");//利用构造法创建并初始化对象str4
        System.out.println(str1 == str2);//ture
        System.out.println(str1 == str3);//false
        System.out.println(str1.equals(str2));//ture
        System.out.println(str1.equals(str3));//ture
        
    }

通过分析,我们可以看到,两次采用构造方法创建字符串,开辟了两块块新的堆内存,并且内容与已有的堆内存一模一样,这就意味着有一块堆内存将称为垃圾。
在这里插入图片描述在这个时候如果我们想解决这个问题,可以采用String类中的intern()方法手工入池。

在这里插入图片描述在这个时候,内容格局指向变化如下图:

在这里插入图片描述

四、字符串不可变

字符串的内容一旦定义,就表示开辟好了指定的空间,那么字符串的内容就不能被改变

在这里插入图片描述
我们看到上面这个例子,不禁疑惑:不是说字符串内容不能改变吗?为什么这里改变了?

其实并不是的,我们画图分析:
在这里插入图片描述
可以看出,字符串内容并没有改变,改变的知识String类对象的引用,并且会产生大量字符串垃圾。

因此,应该尽量避免出现不断修改字符串内容的现象,以免出现大量垃圾。

五、String类的常见用法

1.字符与字符串

方法名称描述
public String(char[] value)将接收到的字符数组变为字符串
public String(char[] value,int offset,int count)将部分字符数组变为字符串
public char charAt(int index)返回指定索引位置上的字符内容
public char[] toCharArray()将字符串变为字符数组

求字符串中指定位置的字符:

 public static void main(String[] args) {
        String str="Chinese";//直接赋值
        System.out.println(str.charAt(1));//取出字符串中第二个字符,也就是下标为1的字符
    }


//打印结果为h

再看下一个例子:

    public static void main(String[] args) {
        String str = "helloworld" ;
// 将字符串变为字符数组
        char[] data = str.toCharArray() ;
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i]+" ");
        }
// 字符数组转为字符串
        System.out.println(new String(data)); // 全部转换
        System.out.println(new String(data,5,5)); // 部分转换
    }

在这里插入图片描述

2.字节与字符串

方法名称描述
public String(byte[] bytes)将全部字节数组变为字符串
public String(byte[] bytes,int offset,int length)将部分字节数组变为字符串
public byte[] getBytes将字符串变为字节数组
public byte[] getBytes(String charsetName) throws UnsuppotedEncodingException将字符串转码
public static void main(String[] args) {
        String str = "helloworld" ;
// 将String 转为 byte[]
        byte[] data = str.getBytes() ;
        for (int i = 0; i < data.length; i++) {
            System.out.print(data[i]+" ");
        }
// 将byte[] 转为String
        System.out.println(new String(data));
 //将部分byte[]变为String
        System.out.println(new String(data,4,3));
    }

在这里插入图片描述
二者使用场景:

  • byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合
    针对二进制数据来操作.
  • char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候.

3.字符串查找

方法名称描述
public boolean contains(String s)判断某一个子字符串是否存在,JDK1.5之后提供
public int indexOf(String str)由前向后查找指定子字符串的位置,找不到返回-1
public int indexOf(String str,int fromIndex)由指定位置查找字符串位置,找不到返回-1
public int lastIndexOf(String str)由后向前查找指定字符串位置,找不到返回-1
public int lastIndexOf(String str,int fromIndex)由指定位置从后向前查找
public boolean startsWith(String prefix)判断是否以指定的字符串开头
public boolean startsWith(String prefix,int toffset)从指定位置开始判断是否以指定的字符串开头
public boolean endsWith(String suffix)判断是否以指定的字符串结尾
    public static void main(String[] args) {
        String str="**hello$$world##";//字符串
        if(str.contains("hello"));//查找hello是否存在
        System.out.println("内存存在");
        if(str.indexOf("r")!=-1){//查找hello是否存在
            System.out.println("内容存在,字符串位置:"+str.indexOf("r"));
        }
        if(str.indexOf("o",6)!=-1){//由指定位置开始查找
            System.out.println("内容存在,字符串位置:"+str.indexOf("o",6));
        }
        if(str.lastIndexOf("w",12)!=-1){//由指定位置从后向前开始查找
            System.out.println("内容存在,字符串位置:"+str.lastIndexOf("w",12));
        }
        System.out.println(str.startsWith("**"));//判断字符串的起始内容
        //判断字符串str中,索引位置为7的位置是否以$$开始
        System.out.println(str.startsWith("$$",7));
        System.out.println(str.endsWith("##"));//判断字符串是否以”##“结束
    }

在这里插入图片描述

4.字符串替换

public static void main(String[] args) {
        String str="helloworld";
        //所有字串出现的位置都替换
        System.out.println(str.replaceAll("o","@@"));
        //替换第一次出现字符字串
        System.out.println(str.replaceFirst("l","***"));
    }

在这里插入图片描述【注意】

由于字符串是不可变对象, 替换不修改当前字符串, 而是产生一个新的字符串

5.字符串拆分

 public static void main(String[] args) {
        String str="hello world welcome";
        String data[]=str.split(" ");//按照空格拆分
        for(int i=0;i<data.length;i++){
            System.out.println(data[i]);
        }
        System.out.println("========================");
        String data1[]=str.split(" ",2);//指定位置按照空格拆分
        for(int i=0;i<data1.length;i++){
            System.out.println(data1[i]);
        }
    }

在这里插入图片描述【注意】

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

6.字符串截取

public static void main(String[] args) {
        String str="Hellojava!!!";
        System.out.println(str.substring(5));//截取从指定位置到末尾的字串
        System.out.println(str.substring(0,4));//截取从指定位置到结束位置的字串
    }

在这里插入图片描述

7.常用字符串方法

 public static void main(String[] args) {
        String str="Hello World ...";
        System.out.println("原始字符串内容【"+str+"】"+",长度:"+str.length());//求字符串长度
        //先把字符串str前后空格去掉,再求长度
        System.out.println("原始字符串内容【"+str.trim()+"】"+",长度:"+str.trim().length());
        //判断字符串”“是否为空,true
        System.out.println("".isEmpty());
        System.out.println(str.isEmpty());
        //字符串字符全变大写
        System.out.println("Hello World".toUpperCase());
        //字符串字符全变小写
        System.out.println("Hello World".toLowerCase());
        //字符串连接
        System.out.println(str.concat("java"));
    }

在这里插入图片描述

六、StringBuffer 和 StringBuilder

我们在上面说过,String类对象的内容一旦被初始化就不能再改变,对于String类的每次改变(例如字符串连接等)都会生成一个新的字符串,比较浪费内存。

那么我们如何修改字符串呢?

StringBuffer类 和 StringBuilder类用于内容可以改变的字符串,二者大部分功能相同。
String和StringBuffer最大的区别在于:String的内容无法修改,而StringBuffer的内容可以修改。频繁修改字符串的
情况考虑使用StingBuffer。

public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        sb.append("Hello").append("World");
        fun(sb);
        System.out.println(sb);
    }
    public static void fun(StringBuffer temp) {
        //通过.append修改字符串
        temp.append("\n").append("........");
    }public static void main(String[] args) {
        StringBuffer sb = new StringBuffer();
        sb.append("Hello").append("World");
        fun(sb);
        System.out.println(sb);
    }
    public static void fun(StringBuffer temp) {
        //通过.append修改字符串
        temp.append("\n").append("........");
    }

在这里插入图片描述
StringBuffer 的其他功能:

字符串反转:public synchronized StringBuffer reverse()

public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("helloworld");
        System.out.println(sb.reverse());
    }

//打印结果:dlrowolleh

删除指定范围的数据:public synchronized StringBuffer delete(int start, int end)

public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("helloworld");
        System.out.println(sb.delete(5, 10));//删除5-10之间字符
    }
//打印结果:hello

删除指定范围的数据:public synchronized StringBuffer delete(int start, int end)

public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("helloworld");
        //删除下标5-10的内容
        System.out.println(sb.delete(5,10));
    }
//打印结果:hello

插入数据:public synchronized StringBuffer insert(int offset, 各种数据类型 b)

public static void main(String[] args) {
        StringBuffer sb = new StringBuffer("helloworld");
        //删除5-10之间字符串,并且在下标为0的位置插入“你好”
        System.out.println(sb.delete(5, 10).insert(0, "你好"));
    }
//打印结果:你好hello

String、StringBuffer、StringBuilder的区别

  1. String的内容不可修改,StringBuffer与StringBuilder的内容可以修改
  2. StringBuffer与StringBuilder大部分功能是相似的
  3. StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作

近来反思

人最大的痛苦便是不自知,面对未来的恐惧而方向尽失,坠入迷途。无法确定自己将要去哪,为何坚持。望得太远,便会丢失当下,沉迷当下,便会囿于自我,万物总是平衡才得恰当,多一点少一点都不行。既然无法预知未来,就先把手上事情搞好!

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-11-23 12:12:19  更:2021-11-23 12:13:27 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 2:41:53-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码