目录
六.String与char [ ] 类型和byte[ ]的转换
一.字符串的创建
- 直接赋值 String str = " hello world " ; //推荐使用
- 通过new来创建字符串对象 String str = new String(" hello world " );
- 通过char数组来创建字符串对象 char[ ] data ={ 'y', 'e', 's' }; String str = new String(data );
字面量
直接写出来的值就称其为字面量,例如数字10就是整型字面量——默认是int类型;10.2就是浮点型字面量——默认是double类型;上面字符串的第一种创建法创建的" hello world "就是字符串字面量——默认是String类型。
二.字符串的内存布局
String str = "hello world"; String str1 = str;
这两行代码在内存中中如何存储呢?
所以,它们在空间中如下图存储,相当于一个对象有两个引用
三. equals方法比较字符串是否相等
对于基本数据类型, == 比较的是两个变量的值
而对于引用数据类型,引用变量保存的是堆内存的地址而不是值,不能使用 == 比较内容是否相等
public static void main(String[] args) { String str = new String("hello"); String str1 = new String("hello"); System.out.println(str == str1);//输出false System.out.println(str.equals(str1));//输出true }
假设用户输入一个字符串str,要判断str的内容是否是“hello” ,我们可以使用下面两种语句:
- str.equals("hello");
- "hello".equals(str);
这里推荐使用第二种语句,equals方法是通过对象调用的,它是一个成员方法。使用第一种方法是,如果用户输入为空就会报错。因为null对象不能调用成员方法,必须通过具体对象来调用成员方法。
static String str ;
public static void main(String[] args) {
System.out.println(str.equals("hello"));
}
把输出语句换成第二种方法,输出结果就为false,因为"hello"是字符串的字面量,也就是字符串的匿名对象。
System.out.println("hello".equals(str));
四.字符串的常量池
public static void main(String[] args) {
String str = "yes";
String str1 = "yes";
String str2 = "yes";
System.out.println(str == str1);
System.out.println(str1 == str2);
}输出true
true
上面我们说过,使用==比较的是字符串的地址,那么也就是说str、str1、str2他们指向的同一个地址。这是为什么呢?
JVM会对字符串创建一个字符串的常量池,使用直接赋值法创建字符串时,字面量是第一次出现,JVM就会创建一个String对象并且扔到常量池中。当字面量再次出现时,并不会创建新的对象,而是复用已有的对象
我们可以理解“池”就是复用已有变量,保证效率
String str = "yes";
String str1 = new String("yes");
System.out.println(str == str1);
//结果为false
我们知道,有new就有新空间,str1没有入池。只有直接赋值法创建的变量才会入池
使用intern() 手工入池
String str = new String("hello").intern();
String str1 = "hello";
System.out.println(str == str1);
//结果为true
为什么推荐使用直接赋值法创建对象呢?我们分析一下下面这个语句一共创建了几个对象
String str1 = new String("yes");
也就是说,一共创建了两个对象
new了之后,str就指向了下面的空间,之前的空间就没有没有任何的引用指向,变成了垃圾空间。所以每次通过new来创建字符串对象 就会创建两个对象,其中一个是垃圾空间。因此,更推荐使用直接赋值法。
五.字符串的不可变性
① 例
String str = "hello";
str = "world";
System.out.println(str);
//输出:world
这里输出不是最初的str,为什么说字符串“不可变”呢?让我们看看它们在空间上如何变化
str指向从“hello”变成“world”,而原字符串并没有任何改变。
② 例
static String str = "hello";
static char[] data = {'a','b','c'};
public static void main(String[] args) {
change(str,data);
System.out.println(str);
System.out.println(data);
}
public static void change(String s ,char[] a){
s = "world";
a[0] = 'g';
}
输出结果:
调用change方法时,实参的值传给了形参,当s=world之后,s就不再指向"hello"。而数组data传给a之后,在原数组上做出了修改,因为s和data指向的同一空间,所以对数组的改变main方法中data是可见的。
字符串本身是不变的,变的只引用的指向,这就是字符串的不可变性。
修改字符串本身
想要修改字符串变量的内容,只能通过反射破坏封装
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
String str = "hello";
//通过反射获取到String类的value数组
Field field = String.class.getDeclaredField("value");
//value的private定义取消
field.setAccessible(true);
//获取到str对象内部的value数组
char[] value = (char[]) field.get(str);
value[0] = 'H';
System.out.println(str);
}
//输出:Hello
当字符串需要频繁修改时,使用两个sb类:
- StringBuffer:线程安全
- SrtingBuilder:线程不安全
两个类在使用上没有任何区别,通常使用SrtingBuilder,它的效率高,使用方法如下
public static void main(String[] args) {
//String -> StringBuilder
//方法一,通过构造方法转
StringBuilder sb = new StringBuilder("hello");
//方法二,调用append方法
sb.append("world");
sb.append("!!!");
//StringBuilder -> String
String str = sb.toString();
System.out.println(sb);
}
//输出结果:helloworld!!!
SrtingBuilder的一些特殊方法
因为SrtingBuilder可以修改内容,String类内容无法修改,所以它具有一些String不具有的一些方法。
1.reserve方法——反转
public static void main(String[] args) {
StringBuilder sb = new StringBuilder("hello world");
System.out.println(sb.reverse());
System.out.println(sb);
}
//结果:
dlrow olleh
dlrow olleh
可以看到sb本身也被修改了
2.delete( int start, int end )——删除指定范围的内容
StringBuilder sb = new StringBuilder("hello world");
sb.delete(5,10);
System.out.println(sb);
//输出:hellod
从输出结果可以看到索引为10的‘d’并没有被删除(要记得索引下标是从0开始的),也就是说这是一个左闭右开区间 [5,10) 。Java中区间的取值一般来说都是左闭右开区间。
3.insert ( int start ,插入的数据 )在索引为start的位置插入数据
StringBuilder sb = new StringBuilder("hello world");
//System.out.println(sb.reverse());
sb.insert(5,"呵呵");
System.out.println(sb);
//输出结果:hello呵呵 world
六.String与char [ ] 类型和byte[ ]的转换
1.String -> char[ ]
String str = "hello";
char[] a = str.toCharArray();
System.out.println(Arrays.toString(a));
//输出:[h, e, l, l, o]
2.获取字符串中索引下标对应的字符,通过遍历也可实现String -> char[ ]
String str = "hello";
char b = str.charAt(1);
System.out.println(b);
//输出:e
3.char[ ] -> String
char[] a = {'a','b','c','1','2'};
String str =new String(a);//全部转换
String str1 = new String(a,1,3);//部分转换
System.out.println(str);
System.out.println(str1);
//结果:abc12
bc1
4.String -> byte[ ]
String str = "hello world";
byte[] b = str.getBytes();
System.out.println(Arrays.toString(b));
//输出结果:[104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100]
**char通常是处理文本内容时使用,byte一般在网络传输或者输入输出中(读写文件)使用例如判断网速时默认单位就是byte。
七.字符串常用操作
字符串的比较
- equals方法
- equalsIgnoreCase方法——不区分大小写的比较
- compareTo方法——比较两个字符串大小关系
String str = "hello";
String str1 = "Hello";
System.out.println(str.equals(str1));
System.out.println(str.equalsIgnoreCase(str1));
System.out.println(str.compareTo(str1));
//输出结果:
false
true
32
*输出的32是大小写字母的ASCLL相差的单位
字符串查找
上表中最常使用的是第一个方法,代码示例如下:
String str = "hello";
System.out.println(str.contains("ell"));
System.out.println(str.contains("world"));
//结果:
true
false
其他的几种方法读者下去可以多多尝试
字符串替换
- replaceAll (a , b )——将字符串中所有a换成b
- replaceFirst ( a, b )——替换首个内容
String str = "hello";
String str1 = str.replaceAll("l","h");
String str2 = str.replaceFirst("l","h");
System.out.println(str1);
System.out.println(str2);
//结果:hehho
hehlo
要记住,String的所有修改操作的内部都是创建一个新的字符,一定要记住字符串的不可变性!!!
字符串拆分
- public String[ ] split (String regex ) ——将全部字符串拆分
- public String[ ] split (String regex,int limit)——部分拆分,限制个数
String str = "hello Java I came";
String[] str1 = str.split(" ");//按空格拆分
String [] str2 = str.split(" ",2);//按空格拆成2个
System.out.println(Arrays.toString(str1));
System.out.println(Arrays.toString(str2));
//输出结果:[hello, Java, I, came]
[hello, Java I came]
注意事项:
一些特殊字符作为分割符号时要转义处理,|、*、+ 前面加上“\”,如果是“.” 前面加上“\\”
String str = "192.168.1.1";
String[] sr1 = str.split("\\.");
System.out.println(Arrays.toString(sr1));
//输出结果:[192, 168, 1, 1]
字符串截取
- substring方法
String str = "helloworld";
System.out.println(str.substring(5));//从索引开始截取到结尾
System.out.println(str.substring(5,8));//截取部分,左闭右开区间
//结果:world
wor
其他操作方法
有关String类的内容就到这里啦,一定要理解字符串的不可变性!!!