希望通过博客和大家相互交流,相互学习,如有错误,请评论区指正
String类
在C语言当中是没有字符串类型的,通常是用字符数组来表示. Java当中是有字符串类型的,String类,在后期对字符串操作会很方便 从官方文档中可以看出,String类被final修饰,是不能被继承的
定义字符串
方式1:
String str = "hello";
方式2:
String str = new String("hello");
方式3:
char[] arr = {'h', 'e', 'l', 'l', 'o'};
String str = new String(arr);
String是java.lang底下的类,可以不用导入包
打印字符串
System.out.println(str);
字符串常量池
首先看如下代码:
public static void main(String[] args) {
String str1 = "hello";
String str2 = new String("hello");
String str3 = "hello";
System.out.println(str1 == str2);
System.out.println(str1 == str3);
}
运行结果: 关于运行结果为什么是这样,我们通过图来说明
注意:
- 在JDK1.7之后字符串常量池被放到了堆中,并且内容是不重复的
- 常量在编译期就已经准备好了
使用 String 的 intern 方法来手动把 String 对象加入到字符串常量池中
public static void main(String[] args) {
String str1 = "hello";
String str2 = new String("hello").intern();
System.out.println(str1 == str2);
}
如下图: intern()会判断当前的字符串在常量池中是否存在,如果存在,把常量池中的引用复制给当前的引用类型变量
字符串比较
1. equals方法比较字符串相等
方法原型:
public boolean equals(Object anObject)
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
}
代码中给出了两种比较的方式,但只有第二种能够实现字符串的比较,方式1是在比较引用,方式2是调用String类中的equals方法来实现字符串比较相等
String源码: Object源码: 其实可以看出,String类中的equals是重写了Object中的equals方法,如果没重写的话,默认是调用Object中的equals方法,比较的是两个引用
注意事项:
String str1 = null;
String str2 = "hello";
System.out.println(str2.equals(str1));
System.out.println(str1.equals(str2));
2. 忽略大小写比较字符串相等
public boolean equalsIgnoreCase(String anotherString)
String str11 = "Hello";
String str12 = "hEllo";
System.out.println(str11.equalsIgnoreCase(str12));
true
3. 比较字符串大小关系
要比较两个字符串的大小关系肯定是不能直接用两个引用去比较的,这样比没有意义
String源码 可以发现String类实现了Comparable接口
底层就是将字符串中的字符一一比较
若str1 > str2 返回正数
str1 < str2 返回负数
str1 == str2 返回0
实例:
String str1 = "Hello";
String str2 = "Welcome";
System.out.println(str1.compareTo(str2));
-15
字符串不可变
如下代码:
str1 = "Welcome";
str1 += "to";
str1 += "Java";
通过这三行代码拼接字符串,字符串拼接的本质其实还是重新创建了对象 常量池中会一次存放出现的三个字符串,并不是String对象本身发生了变化,而是创建了新的String对象,str1指向了新的对象
利用反射修改原有对象的内容
反射是面向对象编程的一种重要特性, 有些编程语言也称为 “自省”
指的是程序运行过程中, 获取/修改某个对象的详细信息(类型信息, 属性信息等), 相当于让一个对象更好的 “认清 自己”
如下代码
public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
String str1 = "Welcome";
Field field = String.class.getDeclaredField("value");
field.setAccessible(true);
char[] arr = (char[])field.get(str1);
arr[0] = 'b';
System.out.println(str1);
}
运行结果:
字符、字符串、字节
字符与字符串
1. 字符数组转字符串
public String(char value[])
char[] arr2 = {'a', 'b', 'c'};
String str3 = new String(arr2);
System.out.println(str3);
运行结果 重载形式
public String(char value[], int offset, int count)
char[] arr3 = {'h','e','l','l','o'};
String str4 = new String(arr3, 1, 3);
System.out.println(str4);
ell
2. 取得字符串中指定位置的字符
public char charAt(int index)
String str5 = "hello";
char ch = str5.charAt(1);
System.out.println(ch);
e
3. 将字符串转换为字符数组
public char[] toCharArray()
String str6 = "hello";
char[] arr5 = str6.toCharArray();
System.out.println(Arrays.toString(arr5));
[h, e, l, l, o]
字节与字符串
1. 将byte数组变为字符串
public String(byte bytes[])
重载形式
public String(byte bytes[], int offset, int length)
byte[] array = {97,98,99,100};
String string = new String(array);
System.out.println(string);
abcd
2. 将字符串转换为byte数组
方法原型
public byte[] getBytes(String charsetName)
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException
实例
String str7 = "abcde";
byte[] bytes = str7.getBytes();
System.out.println(Arrays.toString(bytes));
[97, 98, 99, 100, 101]
3. char[ ]和byte[ ]区分
byte[ ] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合 针对二进制数据来操作
char[ ] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候
字符串替换
1. 替换原字符串中的指定字符
public String replace(char oldChar, char newChar)
String str1 = "Hello";
String str = str1.replace('l', 'b');
System.out.println(str);
重载
public String replace(CharSequence target, CharSequence replacement)
其他替换
public String replaceFirst(String regex, String replacement)
public String replaceAll(String regex, String replacement)
字符串截取
原型
public String substring(int beginIndex)
实例:
String str = "hello";
str.substring(1);
ello
重载形式
public String substring(int beginIndex, int endIndex)
字符串查找
1. 判断源串中是否包含子串
原型
public boolean contains(CharSequence s)
实例:
String str3 = "hello";
boolean flag = str3.contains("el");
boolean flag = str3.contains("el");
true
2.模式匹配indexOf
Java底层的indexOf是用BF算法实现的
原型
public int indexOf(String str)
重载
public int indexOf(String str, int fromIndex)
示例
String str4 = "aaabcaaaabcdeecd";
System.out.println(str4.indexOf("abcd"));
8
lastIndexOf方法
原型
public int lastIndexOf(String str)
从后向前查找子字符串的位置
String str4 = "aaabcaaaabcdeecd";
System.out.println(str4.lastIndexOf("aaa"));
6
重载
public int lastIndexOf(String str, int fromIndex)
3. 判断是否以指定字符串开头
public boolean startsWith(String prefix)
public boolean startsWith(String prefix, int toffset)
实例
String str5 = "aaabcaaaabcdeecd";
System.out.println(str5.startsWith("aaa"));
System.out.println(str5.startsWith("aaa", 1));
System.out.println(str5.startsWith("aab", 1));
true
false
true
4. 判断是否以指定字符串结尾
原型
public boolean endsWith(String suffix)
实例:
String str5 = "aaabcaaaabcdeecd";
System.out.println(str5.endsWith("cd"));
System.out.println(str5.endsWith("acd"));
true
false
字符串拆分
public String[] split(String regex)
public String[] split(String regex, int limit)
String str6 = "Welcome to java";
String[] s = str6.split(" ");
System.out.println(Arrays.toString(s));
[Welcome, to, java]
注意:
以下符号要在后面加\\ 才能达到目的
. $ | ( ) [ { ^ ? * +
其他字符串操作
1. 去掉字符串两端空格
public String trim()
实例:
String strr = " hel lo ";
System.out.println(strr.trim());
hel lo
2. 字符串转大写
public String toUpperCase()
实例:
String strr1 = "Welcome To Java";
System.out.println(strr1.toUpperCase());
WELCOME TO JAVA
3. 字符串转小写
public String toLowerCase()
实例:
String strr1 = "Welcome To Java";
System.out.println(strr1.toLowerCase());
welcome to java
4. 字符串求长度
public int length()
5. 判断是否为空字符串
public boolean isEmpty()
StringBuffer 和 StringBuilder
使用
在前面对String类的对象通过+ 来拼接,其实是会产生临时变量的,如果多次拼接,就会产生大量临时对象,每次都在创建对象,然后改变引用的指向
通过StringBuffer和StringBuilder可以很方便的修改原对象并且不会产生临时变量
如下:
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("hello");
stringBuilder.append("world");
System.out.println(stringBuilder);
helloworld
这样就不会产生临时对象,并且是直接针对原对象修改
其实String的底层拼接就是被优化成了StringBuilder的append方法
如下代码:
String string = "a";
for (int i = 0; i < 10; i ++) {
string += "b";
}
System.out.println(string);
abbbbbbbbbb
反汇编:
String的内容无法修改,而StringBuffer的内容是可以修改的,因此在频繁修改字符串的情况下我们就可以考虑使用StringBuilder或StringBuffer
两者的区别
看看他们的append底层实现 比较明显的区别就是StringBuffer的append方法前面有synchronized修饰,说明它是线程安全的
String 和 StringBuilder适用于单线程情况
StringBuffer与StringBuilder大部分功能是相似的
String的内容不可修改,StringBuffer与StringBuilder的内容可以修改
StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
|