@TOC
前言
String类是Java类中最重要也是最常用的一个大类,它包含了大量的成员方法功能十分强大,类的存在往往伴随着对象的创建,类的加载,引用类型的数据就存在地址的指向问题,而这在JVM中就有生动的体现
一.String类特性
**🟢String的对象用于保存字符串,简言之就是一组字符序列(采用Unicode编码一个字符占两个字节)
String类有很多的构造器,这决定了它在Java中的重要地位**
例如:
==🟢String(StringBuffer)String(byte, int, int,Charset)
String(StringBuilder)
String(String)String(byte, int)
String(char[])String(byte,String)
String(byte, int, int,String)String(byte, int, int)
String(char[]int, int)String(byte, Charset)
String(byte, int, int, int)String(byte)
String(char, boolean)String()String(int[, int, int)==
🟢String类实现了接口serializable这保证了String类可以串行化,实现了接口Comparable使String对象可以比较大小🟢String是一个final类它==不能被其他类继承==(查看源码可知)
🟢String类存放字符串内容是因为它具有==char类型的value[]属性==
例如:
**🟢可以注意到 这里的value[]属性是由 final来修饰的 而他是一个引用类型,这就说明字符串的地址是不可修改的
由此也派生出了两种不同的赋值方式**
二.String内存布局图
通过两种关于String类型的赋值方式来展示他的JVM内存布局图,以及字符串常量的创建过程
1.赋值方式一(🚩)
①String str="Hello";
:先从常量池查看是否有"Hello"数据空间,如果有则直接指向;如果没有则重新创建,然后指向。==str最终指向的是常量池的空间地址==
2.赋值方式二(🚩)
②String str2=new String("Hello");
🟢先在堆中创建空间,里面具有value属性,指向常量池的"Hello"空间。如果常量池没有"Hello",重新创建,如果有则直接通过value指向。最终指向的是堆中的空间地址。
根据以上的创建过程,不难看出方式一是==直接指向常量池中的字符串常量==,方式二则是==先指向堆中,然后根据堆中的地址指向常量池中的字符串常量==
于是就有:
String a="abc";
String b="abc";
System.out.println(a==b);
运行结果:
true
🏁上述代码的运行结果之所以为true,本质是两个引用类型比较的是地址,而a,b都指向的是常量池中的“abc”,所以他们相等
三.字符串特性
1.当常量相加时:
==编译器的优化==:字符串相加只会创建一个对象
String str="Hello"+"Java";
结合上面的内存图,我们很轻易想到,str指向了池中的“Hello”,“Java”两个对象的地址。但事实却与之相反
🏁编译器会判断常量池的对象是否有相同的指向,而在这里很显然符合,所以直接执行了如下的操作
String str="HelloJava";
事实在池中只创建了一个对象并被str指向
2.当变量相加时:
==StringBuilder的应用==
String a ="Hello";
String b ="Java";
String c = a + b;
上述代码共创建了三个对象,对象c的实现是通过堆中的对象指向池中的字符串常量
内存布局如图:
底层是由
`StringBuilder c=new StringBuilder();
c.append(a);
c.append(b);`
创建了StringBuilder对象,并使用append()方法实现了"c=a+b"
综上所述:
==当常量相加时——瞄准常量池==
==当变量相加时——瞄准堆==
四.String的一些常用方法
1.equals()判断字符串内容是否相等(注意有大小写之分)
String a = "hello";
String b = "Hello";
System.out.println(a.equals(b));
2.equalsIgnoreCase() 将字符串与指定的对象比较(不考虑大小写)
String name = "mike";
System.out.println("mike".equalsIgnoreCase(name)) //name可以是别的对象的引用
3.indexOf()返回指定字母索引值
String c = "hellojava";
int index = c.indexOf('j');
System.out.println(index);
4.subString()
==①截取索引值后的字符==
String names = "hello world";
System.out.println(names.substring(5));
==②截取索引起指定大小的字符==
String names = "hello world";
System.out.println(names.substring(0, 5));//表示从索引0开始截取,截取到索引5-1=4的位置
5.toUpperCase(),toLowerCase()大小写输出字符串
String d = "hELlo";
System.out.println(d.toUpperCase());
System.out.println(d.toLowerCase());
6.contact()字符串拼接
String e = "彭于晏";
e = e.concat("彭于晏").concat("好帅").concat("我好爱");
System.out.println(e);
7.toCharArray()将字符串转换成字符数组
String f = "hello";
char[] chs = f.toCharArray(); //转成字符数组
for (int i = 0; i < chs.length; i++) {
System.out.println(chs[i]);
}
8.compareTo()字符串比较
String h = "jeva"; //前大正,后大负 等反0
String i = "java"; //前部分始终相等 长度不等就返回长度差值(看源码)
System.out.println(h.compareTo(i));// 字符串比较 返回的是'e'-'a'=4的值
9.format()格式化字符串
String id = "蔡徐坤";
int age = 25;
double score = 90;
char sexy = '男';
String tip = "我会唱跳rap";
String formatStr = "我的姓名是%s年龄是%d,成绩是%.2f 性别是%c.我的特长是%s";
String info2 = String.format(formatStr, id, age, score, sexy, tip);
System.out.println(info2);
10.split()将一个字符串分割为子字符串,然后将结果作==为字符串数组返回==。
String str1 = "Hello Java Good Morning";
String[] str2 = str1.split(" "); //以空格分割字符串
System.out.println(Arrays.toString(str2))
运行结果:[Hello, Java, Good, Morning]
五.StringBuffer
1.String VS StringBuffer
🏁顾名思义就是给String加了一个buff 相当于他的一个加强类,他的char属性没有final修饰 这是他们最大的不同,可以理解成StringBuffer的对象是一个可变的容器String保存的是字符串常量,常量的值是不可以更改的,当我们要对String对象的内容进行修改时都是更改地址,原因是用于保存常量的char属性被final修饰
StringBuffer保存的是字符串里面的值可以动态更改,每次字符串常量的修改对应的是==堆中空间的扩容==,效率更高
通过查看源码可以发现造成这种差异的原因是因为char类型的属性没有final修饰,这也就保证了堆中的对象可以动态扩容修改,不需要再指向常量池中
2.StringBuffer常用方法
1.append()增
StringBuffer s = new StringBuffer("hello");
s.append("!");//增
s.append("Java");
System.out.println(s);
运行结果:
hello!Java
2.delete()删
StringBuffer s = new StringBuffer("helloJava");
s.delete(0, 2); //删除0-2的字符
System.out.println(s);
运行结果:
loJava
3.replace()改
StringBuffer s = new StringBuffer("helloJava");
s.replace(5, 8, "python"); //使用python替换5-8的字符
System.out.println(s);
运行结果:
hellopython
4.insert()插
StringBuffer s = new StringBuffer("helloJava");
s.insert(5, "!");// 在索引5之前插入!,索引值为5以及以后的字符后移
System.out.println(s);
运行结果:
hello!Java