JavaSE中的String类

news2024/10/5 18:27:29

1.定义方式

常见的三种字符串构造

public class Test1 {
    public static void main(String[] args) {
        // 使用常量串构造
        String str1 = "abc";
        System.out.println(str1);
        
        // 直接newString对象
        String str2 = new String("ABC");
        System.out.println(str2);
        
        // 使用字符数组进行构造
        char[] array = {'h','e','l','l','o'};
        String str3 = new String(array);
        System.out.println(str3);
    }
}

以上三种构造方法的解释:

 

注意: 

1.String是引用类型,内部并不存储字符串本身,在String类的实现源码中,String类实例变量如下:

public static void main(String[] args) {
        // s1和s2引用的是不同对象 s1和s3引用的是同一对象
        String s1 = new String("hello");
        String s2 = new String("world");
        String s3 = s1;
    }

在内存中的存储形式: 

s1和s3引用的是同一个对象

 2. 在Java中""引起来的也是String类型对象。

// 打印"hello"字符串(String对象)的长度
System.out.println("hello".length());

2.内存中的存储

字符串常量池

在JDK7 开始,字符串常量池被挪到堆里了,常量池可以说在堆内存中

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


存储逻辑:
1.先检查这个内存(字符串常量池)有没有这个字符串

2.如果没有,存进去
3.如果有,就不重复存储了。取出现有的对象即可。

练习一 

 我们知道 == 比较的是地址,通过对str1,2,3的比较我们可以知道它们在内存中是如何存储的!

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

        String str3 = "hello";
        System.out.println(str1 == str3);
    }

这个结果说明 str1 和 str2存放的地址是不一样的, str1 和 str3 存放的地址是一样的。

 

  1. 常量池只放字符串常量,比如该例中的"hello"
  2. str2 new一个String对象,在堆上开辟内存,假设内存地址是222,在这个String 对象中,存在一个value[] 保存着 orginal传入的字符串,这个val ==“hello”,因为在字符串常量池中已经有了"hello",所以val 直接指向 常量池中的"hello".但是str2 指向的依然是 222在堆中的空间。
  3. str3 也等于"hello",他也准备把hello放在常量池当中.此时常量池中已经存在"hello",那么之后str3 在存放"hello"地址的时候,就指向的是常量池中原来hello的地址。

练习二

public static void main(String[] args) {

        String str1 = "hello";
        String str2 = "hel"+"lo";
        System.out.println(str1==str2);

        String str3 = new String("hel")+"lo";
        System.out.println(str1==str3);

    }

在内存中的存储 :

  1. str1 指向字符串常量池中的 “hello”
  2. str2 是"hel"与"lo" 组合而成的,常量在编译的时候就已经确定了,所以在编译时,已经被处理为"hello",所以也指向 常量池中的"hello"。所以str1=str2 
  3. str3 首先new 了一个String(“hel”)对象,在堆中开辟一块空间,这个对象中的"hel"同时存放在常量池中,之后又在常量池中开辟一块空间存放 “lo”。两块部分之间的"+",将 String 的对象 与常量池中的 "lo"结合在堆中再次开辟一块新的空间,这块内存中的val ==“hello”,str3指向的是合并之后的对象 ,地址为333 

练习三

 public static void func(String str,char[] array){
        str = "abcdef";
        array[0] = 'g';
    }

    public static void main(String[] args) {
        String str1 = "hello";
        char[] val = {'a'};
        System.out.println(str1);
        System.out.println(Arrays.toString(val));
        func(str1,val);
        System.out.println("=================");
        System.out.println(str1);
        System.out.println(Arrays.toString(val));
    }

 

  1. str1 指向字符串常量区的"hello"
  2. val 作为数组引用,指向堆中开辟的数组空间
  3. str 作为函数的形参,接收str1实参的值,此时str指向常量区的”hello“,但是在方法的内部,str = “abcde”,在字符串常量区中有开辟一块"abcde"的内存,但因为是形参出了该方法体就会失效,所以并没有改变原来的值
  4. array 作为函数的形参,接收val 实参的值,此时array 指向堆中 开辟的数组空间,此时通过array 来改变数组元素的内容,最终 改变的也同样是val 实参的内容. 

3.常见操作

(1)String对象的比较

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

public static void main(String[] args) {
        //对于基本类型变量,==比较两个变量中存储的值是否相同
        int a = 10;
        int b = 20;
        int c = 10;
        System.out.println(a == b);
        System.out.println(a == c);
        
        // 对于引用类型变量,==比较两个引用变量引用的是否为同一个对象
        String s0 = "abc";
        String s1 = new String("abc");
        String s2 = new String("abc");
        //s1,s2的val指向的都是常量池中的"abc",但s1,s2指向的对象不同
        System.out.println(s1 == s2);
    }

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

字典序:字符大小的顺序

equals比较:String对象中的逐个字符

public static void main(String[] args) {
        String s1 = new String("abc");
        String s2 = new String("abc");
        String s3 = new String("ABC");
        System.out.println(s1.equals(s2));

        //忽略大小写比较
        System.out.println(s1.equalsIgnoreCase(s3));
    }

3.compareTo比较

int compareTo(String s) 方法: 按照字典序进行比较

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

1. 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值

2. 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值

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");
        System.out.println(s1.compareTo(s2));  // 不同输出字符差值-1
        System.out.println(s1.compareTo(s3));  // 相同输出 0
        System.out.println(s1.compareTo(s4));  // 前k个字符完全相同,输出长度差值 -3
    }



//忽略大小写比较compareToIgnoreCase
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");
    System.out.println(s1.compareToIgnoreCase(s2));   // 不同输出字符差值-1
    System.out.println(s1.compareToIgnoreCase(s3));   // 相同输出 0
    System.out.println(s1.compareToIgnoreCase(s4));   // 前k个字符完全相同,输出长度差值 -3
}

 (2)字符串的查找

public static void main(String[] args) {
        String str = "abcdefgabccd";
        System.out.println(str.charAt(2));//输出下标为2的字符c

        System.out.println(str.indexOf('a'));//返回a第一次出现的位置。没有则返回-1
        System.out.println(str.indexOf('a',3));//从3位置d开始找a第一次出现的位置,7

        System.out.println(str.indexOf("cd"));//返回字符串“cd”第一次出现的位置,即2
        System.out.println(str.indexOf("cd",5));//从下标为5的位置开始找返回字符串“cd”第一次出现的位置,即10

        System.out.println(str.lastIndexOf('a'));//从后往前找a第一次出现的位置,10
        System.out.println(str.indexOf('a',5));//从下标为5的位置后往前找a第一次出现的位置,7

        System.out.println(str.lastIndexOf("cd"));//从后往前找“cd”第一次出现的位置,10
        System.out.println(str.lastIndexOf("cd",5));//从下标为5的位置后往前找“cd”第一次出现的位置,2
    }

(3)转化

1. 数值和字符串转化  

public static void main(String[] args) {
        //数字转字符串
        String s1 = String.valueOf(1234);
        String s2 = String.valueOf(12.34);
        String s3 = String.valueOf(true);
        System.out.println(s1);
        System.out.println(s2);
        System.out.println(s3);

        //字符串转数字
        int data1 = Integer.parseInt("1234");
        double data2 = Double.parseDouble("12.34");
        System.out.println(data1);
        System.out.println(data2);
    }

2.大小写转换 

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

3. 字符串转数组  

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

        //数组转字符串
        char[] ch = {'a','b','c'};
        String str2 = new String(ch); 
        System.out.println(str2);
    }

 4.格式化

public static void main(String[] args) {

        String s=String.format("%d-%d-%d",2024,4,17);
        System.out.println(s);
    }

(4)字符串的替换

public static void main(String[] args) {
        String s = "hello";
        System.out.println(s.replaceAll("l","a"));
        //heaao
        System.out.println(s.replaceFirst("l", "a"));
        //healo
    }

(5)字符串拆分

1.字符串的整体拆分 

public static void main(String[] args) {
        String s = "aa bb cc dd";
        String[] result = s.split(" ");
        for (String str:result) {
            System.out.println(str);
        }

    }

 

2.字符串的部分拆分

String[] result1 = s.split(" ",2);
        for (String str1:result1) {
            System.out.println(str1);
        }

拆分是特别常用的操作. 一定要重点掌握. 另外有些特殊字符作为分割符可能无法正确切分, 需要加上转义.

3.IP地址的拆分

  • “ \. ”才能表示一个真正的 “.”
  • 同时"\"也需要进行转义,那么就又要再加一个斜杠。
  • “\\.”这时字符串才只能被 “ . ”分割。
String str = "192.168.1.1" ;
        String[] result2 = str.split("\\.") ;
        for(String str2: result2) {
        System.out.println(str2);
        }

 

注意事项:

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

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

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

public static void main(String[] args) {
        String s = "111@qq.com";
        String[] result = s.split("@|\\.");
        for (String str:result) {
            System.out.println(str);
        }
    }

(6)字符串的截取

public static void main(String[] args) {
        String str = "helloworld" ;
        System.out.println(str.substring(5));
        System.out.println(str.substring(0, 5));//[0,5)
    }

 

注意事项:

1. 索引从0开始

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

(7)其它操作方法

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

        String str1 = "HELLO WORLD";
        String str2 = "hello world";

        System.out.println(str1.toLowerCase());
        System.out.println(str1.toUpperCase());
    }

 

 4.字符串的特性

 (1)不可变性

String是一种不可变对象. 字符串中的内容是不可改变。字符串不可被修改,是因为:

1. String类在设计时就是不可改变的,String类实现描述中已经说明了

JDK1.8中 

String类中的字符实际保存在内部维护的value字符数组中,该图还可以看出:

1. String类被final修饰,表明该类不能被继承

2. value被修饰被final修饰,表明value自身的值不能改变,即不能引用其它字符数组,但是其引用空间中 的内容可以修改。 

3.又因为value被private封装了,源码中有没有get和set方法,使得字符串具有不可变性。

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

final修饰类表明该类不想被继承,final修饰引用类型表明该引用变量不能引用其他对象,

但是其引用对象中的内容是可以修改的。 

public static void main(String[] args) {
        final int[]array=new int[]{1,3,4};
       // array=new int[]{1,3,6};//报错
        array[0]=99;//可以修改
        System.out.println(Arrays.toString(array));
    }

 (2)字符串的修改

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

因此:尽量避免对String的直接需要

如果要修改建议尽量 使用StringBuffer或者StringBuilder。

5.StringBuffer 和 StringBuilder 

(1)常用方法

public static void main(String[] args) {
        // 追加:即尾插-->字符、字符串、整形数字
        StringBuilder sb1 = new StringBuilder("hello");
        StringBuilder sb2 = sb1.append("world");

        System.out.println(sb2);
        System.out.println(sb1);
        
        System.out.println(sb1 == sb2);
    }

String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可 以修改。频繁修改字符串的情况考虑使用StringBuilder。

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

String变为StringBuilder: 利用StringBuilder的构造方法或append()方法

StringBuilder变为String: 调用toString()方法。

(2)区别 

String 和 StringBuilder 及 StringBuffer 的区别

  1. String 进行拼接时,底层会被优化为StringBuilder
  2. String的拼接会产生临时对象,但是后两者每次都只是返回当前对象的引用。
  3. String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.

StringBuffer与StringBuilder大部分功能是相似的

StringBuffer 和 StringBuilder 的区别主要体现在线程安全上 。

该关键字相当于一把锁来保证线程的安全

 StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1602670.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ssm056基于Java语言校园快递代取系统的设计与实现+jsp

校园快递代取系统设计与实现 摘 要 现代经济快节奏发展以及不断完善升级的信息化技术,让传统数据信息的管理升级为软件存储,归纳,集中处理数据信息的管理方式。本校园快递代取系统就是在这样的大环境下诞生,其可以帮助管理者在短…

node基础 第二篇

01 ffmpeg开源跨平台多媒体处理工具,处理音视频,剪辑,合并,转码等 FFmpeg 的主要功能和特性:1.格式转换:FFmpeg 可以将一个媒体文件从一种格式转换为另一种格式,支持几乎所有常见的音频和视频格式,包括 MP…

工业控制(ICS)---OMRON

OMRON FINS 欧姆龙厂商 命令代码(Command CODE)特别多,主要关注读写相关,如: Memory Area Read (0x0101) Memory Area Write (0x0102) Multiple Memory Area Read (0x0104) Memory Area Transfer (0x0105) Parameter Area Read (0x0201) Pa…

ARM_day8:温湿度数据采集应用

1、IIC通信过程 主机发送起始信号、主机发送8位(7位从机地址1位传送方向(0W,1R))、从机应答、发数据、应答、数据传输完,主机发送停止信号 2、起始信号和终止信号 SCL时钟线,SDA数据线 SCL高电平,SDA由高到低——起始信号 SC…

Linux时间同步练习

题目如下: 一.配置server主机要求如下: 1.server主机的主机名称为 ntp_server.example.com 2.server主机的IP为: 172.25.254.100 3.server主机的时间为1984-11-11 11:11:11 4.配置server主机的时间同步服务要求可以被所…

突破数据存储瓶颈!转转业财系统亿级数据存储优化实践

1.背景 1.1 现状 目前转转业财系统接收了上游各个业务系统(例如:订单、oms、支付、售后等系统)的数据,并将其转换为财务数据,最终输出财务相关报表和指标数据,帮助公司有效地进行财务管理和决策。 转转业…

Matlab|基于改进遗传算法的配电网故障定位

目录 1 主要内容 2 部分代码 3 部分程序结果 4 下载链接 1 主要内容 该程序复现文章《基于改进遗传算法的配电网故障定位》,将改进的遗传算法应用于配电网故障定位中, 并引入分级处理思想, 利用配电网呈辐射状的特点, 首先把整个配电网划分为主干支路和若干独立…

Pr2024安装包(亲测可用)

目录 一、软件简介 二、软件下载 一、软件简介 Premiere简称“Pr”,是一款超强大的视频编辑软件,它可以提升您的创作能力和创作自由度,它是易学、高效、精确的视频剪辑软件,提供了采集、剪辑、调色、美化音频、字幕添加、输出、D…

minio如何配置防盗链

MinIO 是一个开源的对象存储服务器,用于存储大量的数据,同时提供了丰富的功能和 API。配置防盗链可以帮助你控制谁可以访问存储在 MinIO 上的对象。以下是在 MinIO 中配置防盗链的一般步骤: 编辑 config.json 文件: 找到 MinIO 服…

【Godot4自学手册】第三十七节钥匙控制开门

有些日子没有更新了,实在是琐事缠身啊,今天继续开始自学Godot4,继续完善地宫相关功能,在地宫中安装第二道门,只有主人公拿到钥匙才能开启这扇门,所以我们在合适位置放置一个宝箱,主人公开启宝箱…

vue+element作用域插槽

作用域插槽的样式由父组件决定&#xff0c;内容却由子组件控制。 在el-table使用作用域插槽 <el-table><el-table-column slot-scope" { row, column, $index }"></el-table-column> </el-table>在el-tree使用作用域插槽 <el-tree>…

【Java开发指南 | 第十一篇】Java运算符

读者可订阅专栏&#xff1a;Java开发指南 |【CSDN秋说】 文章目录 算术运算符关系运算符位运算符逻辑运算符赋值运算符条件运算符&#xff08;?:&#xff09;instanceof 运算符Java运算符优先级 Java运算符包括&#xff1a;算术运算符、关系运算符、位运算符、逻辑运算符、赋值…

C语言入门案例-学生管理系统

要求&#xff1a;学员管理系统可以实现对学员的添加、全部显示、查询、修改、删除功能 完整代码示例&#xff1a; #include <stdio.h> // 定义容量 #define NUM 100//自定义结构体 typedef struct st {char name[30];int age;char sex[10]; }STU;//传入四个初始数据 STU…

PyTorch深度学习入门-2

PyTorch深度学习快速入门教程&#xff08;绝对通俗易懂&#xff01;&#xff09;【小土堆】_哔哩哔哩_bilibili 一、神经网络的基本骨架 --nn.Module Neutral network torch.nn — PyTorch 2.2 documentation * import torch from torch import nnclass xiaofan(nn.Module):…

1997-2022年各省技术市场发展水平数据(原始数据+计算过程+计算结果)

1997-2022年各省技术市场发展水平数据&#xff08;原始数据计算过程计算结果&#xff09; 1、时间&#xff1a;2000-2022年 2、来源&#xff1a;国家统计局、统计年鉴 3、范围&#xff1a;30省 4、指标&#xff1a;技术市场成交额、国内生产总值、技术市场发展水平 5、计算…

Git回滚版本并push到远端master

1、查看日志 git log 2、还原最近的版本 () --git reset --hard commit-id 如&#xff1a;git reset --hard d84da14bf2743683eca7a015f56114faaa344f42 3、覆盖分支版本 git push -f origin dev 回滚本地master完成后&#xff0c;将回滚后的代码push到远端master&#xf…

VIT论文阅读

论文地址&#xff1a;https://arxiv.org/pdf/2010.11929.pdf VIT论文阅读 摘要INTRODUCTION结论RELATEDWORKMETHOD1.VISIONTRANSFORMER(VIT)整体流程消融实验HEAD TYPE AND CLASSTOKENpoisitional embedding 整体过程公式Inductive biasHybrid Architecture 2.FINE-TUNINGANDH…

Nginx第1篇-安装和简单配置

Nginx可以做什么 可以做静态HTTP服务器做负载均衡做正向代理做反向代理 正向代理和反向代理 正向代理&#xff1a; 是一个位于客户端和目标服务器之间的服务器(代理服务器)&#xff0c;为了从目标服务器取得内容&#xff0c;客户端向代理服务器发送一个请求并指定目标&…

Scala 02——Scala OOP

文章目录 Scala 02——Scala OOP前序类1. 类的基本结构2. 普通类和数据类的区别 继承1. extends2. override 抽象类抽象类的特点 单例对象1. 定义2. 场景3. 方法3.1 方法定义3.2 方法调用 特质1. 抽象类和特质的区别2. 强制混入语法3. 静态混入和动态混入 内部类Java和Scala内部…

单链表的应用

文章目录 目录1. 单链表经典算法OJ题目1.1 [移除链表元素](https://leetcode.cn/problems/remove-linked-list-elements/description/)1.2 [链表的中间节点](https://leetcode.cn/problems/middle-of-the-linked-list/description/)1.3 [反转链表](https://leetcode.cn/problem…