String 类
String 类
概述
- String 是一种非常特殊的类,代表字符串,Java 程序中的所有字符串字面值,例如"abc"都作为 String 类的实例实现;
- String 是一个 final 类, 他的底层是一个 char 类型的 final 数组,代表不可变的字符序列。字符串是常量,用双引号引起来表示,他们的值在创建之后不能更改;
- String 实现了 Serializable 接口、表示字符串是支持序列化的,实现了 Comparable 接口,表示 String 类型的字符可以比较大小;
实例化方式:
两种实例化方式
方式一:通过字面量定义的方式
String s = "abc132";
是一种非常特殊的形式,这里暂且叫他形式赋值(字面量) 其在 Java 中被叫做直接量,跟 new 有着本质的区别 ,他是 Java 中唯一一个不需要 new 就产生的对象,本方法产生的数据存放在方法区的常量池中;
方式二:通过 new + 构造器的方式
- new 出来的对象通常会被放在堆里 而 形式赋值产生的直接量在创建的时候 会在 JVM 内部发生字符串扣留 -->1.先查看常量池中是否有内容相同的字符串,若有 ,则将其直接指向常量池中已有的字符串 ,偌常量池中没有声明的该字符串,则创建一个字符串将其放入常量池中;
String s = "abc";
s += "def"; // 这里也是会直接重新创建一个内存区域用来存储连接过的字符串
//当调用 String.replace 来修改字符串内容时,也会直接创建一个新的内存区域用来存储
若两种方式创建的方法不同,但是内容相同,那么 new 出来的 String 对象里的属性指向的还是同一个方法区里的常量池中的数据的地址;
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s1 == s2); //true
System.out.println(s1 == s3); //false
System.out.println(s3 == s4); //false
上述例子中,如果有变量参与进来,那么其将会被定义在堆空间当中,在堆空间当中 new 一个变量;
但是常量与常量的拼接结果在常量池,且常量池中不会存在相同内容的常量
intern( ):在调用 "ab".intern()
方法的时候会返回 ”ab”,但是这个方法会首先检查字符串池中是否有”ab”这个字符串,如果存在则返回这个字符串的引用,否则就将这个字符串添加到字符串池中,然会返回这个字符串的引用;
String 类常会用到的方法
String s1 = "Hello World";
System.out.println("原版" + s1); //原版 Hello World
- 从指定的字符串中,截取某一字符串
String str = "dsadasdaux1112";
int aux11 = str.indexOf("aux11");
String substring = str.substring(aux11, aux11 + 5);
System.out.println(substring);
- 获取字符串长度 --> length
System.out.println(s1.length()); //11
- 取指定索引位置的字符-->charAt(int index )
System.out.println(s1.charAt(0)); //H
System.out.println(s1.charAt(6)); //W
System.out.println(s1.charAt(7)); //o
- 判断字符串是否为空 返回布尔类型-->isEmpty( )
System.out.println(s1.isEmpty()); //false
- 转换大小写**--> **toLowerCase( )、toUpperCase( )
String s2 = s1.toLowerCase();//小写 //新创建
System.out.println(s1); //Hello World
System.out.println(s2); //小写 hello world
String s3 = s1.toUpperCase();
System.out.println(s3);//大写 HELLO WORLD
- 忽略前导和尾部空白-->trim( )
String s4 = " hello wo r l d ";
String s5 = s4.trim();
System.out.println("--" + s4 + "--");//-- hello wo r l d -- S
ystem.out.println("--" + s5 + "--"); //--hello wo r l d--
- equals()比较字符串内容
- equalsIgnoreCase 忽略大小写比较
String s6 = "hello world";
System.out.println(s6.equals(s1));//false
System.out.println(s6.equalsIgnoreCase(s1)); //true
- 连接字符 concat
String s7 = s1.concat("哈哈哈");
System.out.println(s7); //Hello World哈哈哈
- compareTo 调用者-被调用者 这里 a-b
String a = "a";
String b = "b";
System.out.println(a.compareTo(b)); // a -b = -1 会涉及到字符串排序
- 提取字符串
String s8 = s1.substring(0, 5); // 左闭右开区间
System.out.println(s8); // Hello
System.out.println(s1); // Hello World
- endWith 是否以指定字符串结尾
boolean ld = s1.endsWith("ld");
System.out.println(ld); //true
- startWith 是否以指定字符串开始
boolean hell = s1.startsWith("Hell");
System.out.println(hell); //true
- 字符串是否包含字符
boolean hello = s1.contains("Hello");
System.out.println(hello); //true
- indexOf 查找指定字符第一次出现的位置的索引
int wo = s1.indexOf("Wo"); // 有则返回索引 无则返回 -1
System.out.println(wo); // 6
int lo = s1.indexOf("lo", 2);
System.out.println(lo); //3
- lastIndexOf 从后往前找
- replaceAll 把字符串中的数字替换成,如果开头和结尾有“,”的话就去掉
String s9 = "2heladfoj545542dada1";
String s = s9.replaceAll("\\d", ",").replaceAll("^,|,$", ""); //正则表达式
System.out.println(s9); //2heladfoj545542dada1
System.out.println(s); //heladfoj,,,,,,dada
- 判断字符串是否全部由数字组成
boolean matches = s1.matches("\\d+");
System.out.println(matches); //false
- 判断是否为某地区被电话
String tel = "0349-1234567";
boolean matches1 = tel.matches("0349-\\d{7,8}");//后面跟了 7、8 位数字
System.out.println(matches1); //true
-
split 切分
-
String -> char [ ]
char[] chars = s1.toCharArray();
System.out.println(Arrays.toString(chars));
- 将 char 型数组转为 String
char[] ch1 = new char[]{'h', 'e', 'l', 'l', 'o'};
String ss = new String(ch1);
System.out.println(ss);
- String 转换为 byte[ ]
String str = "abc123汉字";
byte[] bytes = str.getBytes();//默认采用UTF-8
System.out.println(Arrays.toString(bytes));
byte[] gbks = str.getBytes("gbk"); //采用gbk编码格式
System.out.println(Arrays.toString(gbks));
StringBuilder
在Java8,String、StringBuilder、StringBuffer 等的底层实现都是字节数组 char [] value;
三者区别:
String、StringBuffer、StringBuilder 的区别
-
String:底层 final 的,不可变的字符序列
-
StringBuffer:底层非 final 的,可变的字符序列,线程安全,但是效率偏低
-
StringBuilder:底层非 final 的,可变的字符序列,效率高,但是线程不安全
上述三者的共同点是:java8 之前包括 8,他们的底层实现都是的字符数组 char [ ]
,在java9以及之后的版本中改为了 byte [] 数组;
StringBuilder 与 StringBuffer 都继承自 AbstractStringBuilder 类
三者的效率:
StringBuilder > StringBuffer > String
- 操作少量的数据: 适用 String
- 单线程操作字符串缓冲区下操作大量数据: 适用 StringBuilder
- 多线程操作字符串缓冲区下操作大量数据: 适用 StringBuffer
扩容问题:StringBuffer 类无参构造创建一个长度大小为 16 的 char 型数组,如果添加不下,那么就需要将原来的数组空充为原来的 2 倍 + 2,同时会将原有的数组复制到新的数组当中去
建议使用 StringBuffer 类中的有参构造 指定大小 容量 StringBuffer(int capacity)
常用基本功能
- 增 append
- 删 delete
- 改 replace
- 查 indexOf
- 插 insert
- 长度 length
- 遍历 toString( ) \ for 循环 +charAt( )
互相转换:
String --> StringBuffer、StringBuilder :直接调用他们的构造器 String 类型传参即可,反之亦然
也可以通过 toString 来转换
public class StringBufferTest {
public static void main(String[] args) {
StringBuffer s1 = new StringBuffer("abc");
System.out.println("长度为:" + s1.length());//3
System.out.println(s1);
s1.append("def");
System.out.println("长度为:" + s1.length());//6
s1.insert(2, "123");//在指定位置(非索引)之后插入指定字符串
System.out.println(s1);
s1.replace(2, 5, ""); //替换指定位置之后的指定字符串 左闭右开区间
System.out.println(s1);
s1.delete(3, 4); //删除指定位置之后的字符串 左闭右开区间
System.out.println(s1);
s1.reverse(); //当前字符串翻转
System.out.println(s1); //indexOf() 查询字符第一次出现位置的索引
//返回索引区间内的一个子字符串 左开右闭
String substring = s1.substring(0, 3);
System.out.println(substring);
String s3 = "abc";
StringBuffer stringBuffer = new StringBuffer(s3);
System.out.println(stringBuffer);
StringBuffer stringBuffer1 = new StringBuffer("def");
String s = stringBuffer1.toString();
System.out.println(s);
}
}
练习
上例子!
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s3 == s4); // false
拼接字符串
String s1 = "javaEE";
String s2 = "hadoop";
String s3 = "javaEEhadoop";
String s4 = "javaEE" + "hadoop";
String s5 = s1 + "hadoop";
String s6 = "javaEE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4); // true 常量和常量的拼接结果会在常量池中,且常量池中不会存在内容相同的常量值
System.out.println(s3 == s5); // false 只要有一个值是来自于变量的,那么拼接结果就会存在于堆中,在堆空间中 new 一块空间出来
System.out.println(s3 == s6); // false
System.out.println(s3 == s7); // false
System.out.println(s5 == s6); // false
System.out.println(s5 == s7); // false
System.out.println(s6 == s7); // false