String 字符串常用操作

本文详细探讨了Java中String字符串的不可变性,分析了其内部实现原理,并介绍了字符串的创建方式、转换方法、修改(实际是创建新对象)、比较、查找、判断、替换、截取、去空格、转大小写、入池、拼接、长度和是否为空的检查,以及字符串的拆分操作,特别是涉及到特殊符号和转义字符的情况。

目录

String字符串不可以改变的根本原因:

String两种对象实例化的区别:

字符和字符串的转化:

字节和字符串的转化:

字符串的修改:

一、借助原字符串:

二、借助反射(不常用):

字符串的比较:

字符串的查找:

字符串的判断:

字符串的替换:

字符串的截取:

字符串的去空格、转大小写、入池、拼接、长度、是否为空的:

字符串的拆分:

一、根据特定符号拆分,可以多次拆分,需要用String[ ] 接受。

二、有的分割时由于部分符号具有特殊含义,所以需要转义。

1、拆分一个IP,其中的 “.” 需要注意。

2、两个“ \\ ”需要转义。

3、当符号较多时可以用“ | ”连接起来。

三、关于分割时候的转义需要注意以下几点


String字符串不可以改变的根本原因:

String 类内部以 private final char[ ] value 的形式存储,

但类内并未提供修改 char[ ] 内值的方法。

字符串为何不可变的根本原因要看 String 源码:String 内字符串的存储是以字符数组的形式,而且该字符数组被 private final 修饰。

在这里要注意两点:

一、final 修饰后,value[ ] 中的 “value” 不能改变,即长度不可改变,但 value[ ] 中元素是可以改变的,如下图所示:

二、private 修饰后,类外不可访问该属性,但是类内可以有利用上述方法的间隙以此在String类内部修改元素,以此修改字符串。然而,String类并没有给出这种方法。

再次重申字符串不能改变的根本原因:“如果要增加长度或者减少长度就必须新创建一个字符数组,value的值就会变,这里被final修饰,所以长度就不能变。另一种情况就是长度不变,修改字符数组里的值也是不行的,因为String类没有提供这种方法。”

另外值得一提的是,像以下哪种情况:

 且包含之后字符串的各种操作使得看似字符串发生了改变,实际上都是生成了新的对象,只不过是修改了s1这个引用类型的指向。

最后一点:

StringBuilder 和 StringBuffer 是可以修改内容的,因为这两个都是通过append() 方法进行赋值:

 String类的 += 操作实际上是通过StringBuffer实现的。


String两种对象实例化的区别:

String str1 = "Java";
String str2 = new String("Java");

str1 是直接赋值:只开辟一块堆内存空间,该字符串可以自动保存在对象池(字符串常量池,字符串常量池在堆中)中供下次使用。

str2 是构造方法:开辟两块堆内存空间,通过一块引用内存指向另一块字符串内存,不会自动保存在对象池中,需用 intern() 手动入池

常用直接赋值法。


字符和字符串的转化:

转化类型特性表达式备注

字符转字符串

全转String str = new String(ch);
部分转String str = new String(ch, 0 ,2);0表示起始下标,2表示长度
字符串转字符全转

Char[ ] ch = str.tocharAt();

部分取Char ch = str.charAt(2);2表示下标

字节和字符串的转化:

转化类型特性表达式备注

字节转字符串

全转String str = new String(bytes1);
部分转String str = new String(bytes1, 0 ,2);0表示起始下标,2表示长度

字符串转字节

(全转)

默认转

byte[ ] bytes1 = str.getBytes();

按照UTF-8转化
GBK转byte[ ] bytes1 = str.getBytes("GBK");按照GBK转化

字符串的修改

这里的修改是表面上的修改,并非改变内部value值,并非说string可变。

一、借助原字符串:

str = "A" + str.substring(1)

注意:()中的 1 代表在下标为 1 的前一个位置插入修改,且修改后会抛弃前面的内容。

//修改字符串之一:借助原字符串               
String str = "lhou";              
str = "z"+str.substring(1);              
System.out.println(str); //结果为 zhou              
str = "z"+str.substring(2);//前面的会扔掉             
System.out.println(str); //结果为 zou

二、借助反射(不常用):

Field valueField = String.class.getDeclaredField("value");

valueField.setAccessible(true);

char[ ] value = (char[ ])  valueField.get(str);

value[0] = 'a';

通过反射修改该字段的访问属性,获取value后通过 value[ ] 修改值。

注意:[ ] 中的 0 代表该字符串下标,且修改后不会抛弃前面的内容。

//修改字符串之二:借助反射               
String str = "moximoxi";               
// 获取 String 类中的 value 字段. 这个 value 和 String 源码中的 value 是匹配的               
Field valueField = String.class.getDeclaredField("value");               
// 将这个字段的访问属性设为 true //main方法要抛异常               
valueField.setAccessible(true);               
// 把 str 中的 value 属性获取到.              
char[] value = (char[]) valueField.get(str);              
// 修改 value 的值               
value[0] = 'o';               
System.out.println(str);              
value[3] = 'z';               
System.out.println(str);//只修改具体某一位不会抛弃前面的

字符串的比较

类型代码注意点
区分大小写的比较str1.equals(str2);

str1 > str2,返回 true

str1 = str2,返回 0

str1 < str2,返回 false

不区分大小写的比较str1.equalsIgnoreCase(str2);

str1 > str2,返回 true

str1 = str2,返回 0

str1 < str2,返回 false

比较两个字符串大小的关系str1.compareTo(str2);

str1 > str2,返回正整数

str1 = str2,返回 0

str1 < str2,返回负整数

注:str1 与 str2 的比较并非源码中的内容,只是该方法在本层面的直观体现。以下皆同


字符串的查找

类型代码注意点
查找一个字符串是否存在

str1.contains(str2);

存在返回 true,不存在返回 false
从头开始查找一个字符串是否存在str1.indexOf(str2);存在返回下标,否则返回-1
str1.indexOf(str2, 2);2代表从指定下标位置开始查找
从后往前查找一个字符串是否存在str1.lastIndexOf(str2);存在返回下标,否则返回-1
str1.lastIndexOf(str2, 2)2代表从指定下标位置开始查找

字符串的判断

类型代码注意点
判断是否以指定字符串开头

str1.startsWith("ab");

是返回 true,不存在返回 false
判断指定位置是否以指定字符串开头str1.startsWith("a", 3);区分大小写的判断,3代表下标
判断是否以指定字符串结尾str1.endsWith("a");不能指定位置

字符串的替换

类型代码注意点
只替换首个

str1.replaceFirst("zhou", "liu");

主要基于正则表达式
全部替换str1.replace("zhou", "liu");主要基于字符和字符串
str1.replaceAll("\\d", "L");主要基于正则表达式

1、正则表达式:又名规则表达式,指通过指定的规则寻找字符串。

2、当生成一个 String 类的时候,从方法表面上看是替换了,实际上生成了新的对象。所以修改一个String类的时候,都生成了新的对象,是表面的指向变了。


字符串的截取

类型代码注意点
有头无尾的截取str1.substring(3);

3 代表元素下标

有头有尾的截取str1.substring(3, 7);3代表开始,7代表结束  [ )

字符串的去空格、转大小写、入池、拼接、长度、是否为空的

类型代码注意点
去掉左右的空格str.trim();中间空格仍旧保留
字符串转大写str.toUpperCase();

全部都转

字符串转小写str.toLowerCase();全部都转
字符串入池str.intern();手动入池
字符串拼接str.concat("enen!");等于“+”,不入池
取得字符串长度str.length();字符串结尾的“\0”只存在C语言中
判断是否为空字符串str.isEmpty();

非 null,而是字符串内部长度为空

空格(      )并非为空

注:str.intern();使用时:常量池中存在直接返回,没有的话创建新的


字符串的拆分

一、根据特定符号拆分,可以多次拆分,需要用String[ ] 接受。

String str = "周周&刘刘!哲学&编程!冲冲&冲冲";          
System.out.println(str);//先看看元代码              
String[] strings = str.split("!"); //第一次按照!拆分              
for(String s : strings) { //遍历循环打印出来                       
     System.out.println(s); //添加这条打印后,结果会是一次分割穿插在二次分割的结果中。                  
     String[] ss = s.split("&");                       
     for (String tmp : ss){                               
            System.out.println(tmp);                       
     }               
}

二、有的分割时由于部分符号具有特殊含义,所以需要转义。

1、拆分一个IP,其中的 “.” 需要注意。

String str = "192.168.1.1" ;
String[] result = str.split("\\.",7) ;//超出范围最多就分最多分多少组
for(String s: result) {
        System.out.println(s);
}

2、两个“ \\ ”需要转义。

String str = "192\\168\\1\\1" ;
String[] result = str.split("\\\\",7);
for(String s: result) {
          System.out.println(s);
}

3、当符号较多时可以用“ | ”连接起来。

String str = "哇 不要紧&其实#我*才是@老大" ;
String[] result = str.split(" |&|#|\\*|@", 7);
for(String s: result) {
         System.out.println(s);
}

三、关于分割时候的转义需要注意以下几点:

1、字符| ”、“ * ”、“ +都得加上转义字符,前面加上\

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

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值