这系列博文主要是将自己之前学习的一些java基础内容进行归纳与总结。
常用方法
int length() // 获取长度
char charAt(int index) // 获取对应角标的字符
int indexOf(String str) // 获取对应角标
String substring(int beginIndex, int endIndex) // 截取区间返回 包含开头不包含结尾
String[] split(String regex, int limit) // 根据正则表达式分隔字符,limit应用次数
String trim() // 忽略前后空白
String replace(char oldChar, char newChar) // 替换
char[] toCharArray() // 分解成字符数组
String intern() // 判断常量池是否存在该字符串,如果存在则返回,否则在常量池记录首次出现的引用(jdk1.7后)
Sting对equals方法的重写
// Object的equals方法 直接通过==比较内存地址
public boolean equals(Object obj) {
return (this == obj);
}
// String对equals方法进行了重写 先比较内存地址如果不相等再比较字符串值是否相同
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
.... // 逐个char进行比较
}
}
String的比较
String s1 = new String("aaa");
String s2 = "aaa";
System.out.println(s1 == s2); // false
s1 = new String("bbb").intern();
s2 = "bbb";
System.out.println(s1 == s2); // true
s1 = "ccc";
s2 = "ccc";
System.out.println(s1 == s2); // true
s1 = new String("ddd").intern();
s2 = new String("ddd").intern();
System.out.println(s1 == s2); // true
s1 = "ab" + "cd";
s2 = "abcd";
System.out.println(s1 == s2); // true
String temp = "hh";
s1 = "a" + temp;
// 如果调用s1.intern 则最终返回true
s2 = "ahh";
System.out.println(s1 == s2); // false
temp = "hh".intern();
s1 = "a" + temp;
s2 = "ahh";
System.out.println(s1 == s2); // false
temp = "hh".intern();
s1 = ("a" + temp).intern();
s2 = "ahh";
System.out.println(s1 == s2); // true
s1 = new String("1"); // 同时会生成堆中的String对象 以及常量池中的"1",但是此时s1是指向堆内存的String对象
s1.intern(); // 返回的是常量池中的已经存在"1"的引用
s2 = "1"; // 还是指向常量池中已存在的"1"
System.out.println(s1 == s2); // false
// 先调用intern
String s3 = new String("1") + new String("1"); // 此时生成了四个对象 常量池中的"1" + 2个堆中的"1" + s3指向的堆中的对象(注此时常量池不会生成"11")
s3.intern(); // jdk1.7之后,常量池不仅仅可以存储对象,还可以存储对象的引用,会直接将s3的地址存储在常量池
String s4 = "11"; // jdk1.7之后,常量池中的地址其实就是s3的地址
System.out.println(s3 == s4); // jdk1.7之前false, jdk1.7之后true
// 后调用intern
s3 = new String("2") + new String("2");
s4 = "22"; // 常量池中不存在22,所以会新开辟一个存储22对象的常量池地址
s3.intern(); // 常量池22的地址和s3的地址不同,若 s3 = s3.intern() 则为true
System.out.println(s3 == s4); // false
String在内存中的对象创建
- 字符串相加如果没有任何变量参与,则编译器对String做了优化,会直接拼接转化为一个字符串
- 若有变量参与则是通过new StringBuild().append()相加
- new String(“E”) + new String(“F”) 一共创建了五个变量
String s1 = "A" + "B" + "C"; // 直接在常量池中创建 "ABC"
// 字节码:
Code:
0: ldc #2 // String ABC
2: astore_1
3: return
String s2 = s1 + "D"; // 在堆中new StringBuilder,通过append相加
// 字节码:
Code:
0: ldc #2 // String ABC
2: astore_1
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: aload_1
11: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
14: ldc #6 // String D
16: invokevirtual #5 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: invokevirtual #7 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
22: astore_2
23: return
String s3 = new String("E") + new String("F"); // 创建了五个对象, 常量池中的"E"、"F",堆中的"E"、"F",s3指向堆中的对象
// 字节码:
Code:
0: new #2 // class java/lang/StringBuilder
3: dup
4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V
7: new #4 // class java/lang/String
10: dup
11: ldc #5 // String E
13: invokespecial #6 // Method java/lang/String."<init>":(Ljava/lang/String;)V
16: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: new #4 // class java/lang/String
22: dup
23: ldc #8 // String F
25: invokespecial #6 // Method java/lang/String."<init>":(Ljava/lang/String;)V
28: invokevirtual #7 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
31: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
34: astore_1
35: return
IDEA中在控制台打印执行的字节码
在Setting中配置External Tools
参数说明
Name: Show Byte Code (随意)
Program: C:\Program Files\Java\jdk1.8.0_144\bin\javap.exe (jdk bin目录下的javap.exe)
Arguments: -c $FileClass$ (照填)
Working directory: $OutputPath$ (照填)
然后右键执行即可