目录
一、字符串的构造方法
public static void main(String[] args) {
//方法一:使用常量串构造
String str1 = "abcdef";
//方法二:直接newString对象
String str2 = new String("hehe");
//方法三:使用字符数组进行构造
char[] chars = {'a','b','c'};
String str3 = new String(chars);
System.out.println(str3);
}
注意:1. String是引用类型,内部并不存储字符串本身。
public static void main(String[] args) {
String str1 = "Hello";
String str2 = str1;
System.out.println(str1);
System.out.println(str2);
str1 = "world";
System.out.println("================");
System.out.println(str1);
System.out.println(str2);
}
为什么会出现这样的结果呢?
由于 String 是引用类型
我们发现, “修改” str1 之后, str2 也没发生变化, 还是 hello?
事实上, str1 = “world” 这样的代码并不算 “修改” 字符串, 而是让 str1 这个引用指向了一个新的 String 对象.
public static void func(String s,char[] array){
s = "Haha";
array[0] = 'p';
}
public static void main3(String[] args) {
String str = "abcdef";
char[] chars = {'a','b','c'};
func(str,chars);
System.out.println(str);
System.out.println(Arrays.toString(chars));
}
注:并不是传引用就能改变实参的值!!!!
二、String对象的比较
1.==比较是否引用同一个对象。
public static void main(String[] args) {
String str1 = "hello";//存放到字符串常量池里面
String str2 = new String("hello");
System.out.println(str1 == str2);
}
要想弄清楚这个为什么是false?
就需要提前了解一个知识!
Class文件常量池
运行时常量池:当程序把编译好的字节码文件,加载到JVM当中后,会生成一个运行时常量池[方法区],实际上是Class文件常量池.
字符串常量池:主要存放字符串常量->字符串常量池,本质上是一个哈希表.StringTable
对于引用类型变量,==比较两个引用变量引用的是否为同一个对象 。
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);
}
public static void main(String[] args) {
String str1 = "hello";
String str2 = "he" + "llo";//此时 都是常量,编译的时候就是hello
System.out.println(str1 == str2);
}
所以这个结果依然为true
public static void main(String[] args) {
String str1 = "hello";
String str2 = "he" + "llo";//此时 都是常量,编译的时候就是hello
String str3 = "he";
String str4 = str3 + "hllo";//此时str3是一个变量,编译的时候不知道是什么
System.out.println(str1 == str4);
}
public static void main(String[] args) {
String str1 = "11";
String str2 = new String("1") + new String("1");
System.out.println(str1 == str2);
}
public static void main(String[] args) {
String str2 = new String("1")+new String("1");
str2.intern();//手动入池
String str1 = "11";
System.out.println(str1 == str2);
}
2. boolean equals(Object anObject) 方法:按照字典序比较。
public static void main(String[] args) {
String str1 = "11";
String str2 = new String("1")+new String("1");
str2.intern();//手动入池->当字符串常量池,没有的时候,就会入池
System.out.println(str1 == str2);
System.out.println(str1.equals(str2));
}
public static void main(String[] args) {
String str1 = null;
String str2 = "11";
System.out.println(str2.equals(str1));
}
public static void main(String[] args) {
//数组的整体赋值 只有1次机会 就是在定义的时候
final int []array = {1,2,3,4,5};
//array = {4,5,6,7};
String str1 =null;//str1这个引用 不指向任何对象
String str2 = "";//str2这个引用 指向的字符串是空的
System.out.println(str2.length());
}
3. int compareTo(String s) 方法
与equals不同的是,equals返回的是boolean类型,而compareTo返回的是int类型。
- 先按照字典次序大小比较,如果出现不等的字符,直接返回这两个字符的大小差值。
- 如果前k个字符相等(k为两个字符长度最小值),返回值两个字符串长度差值。
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("abc");
String s4 = new String("abcdef");
System.out.println(s1.compareTo(s2)); // 不同输出字符差值-1
System.out.println(s1.compareTo(s3)); // 相同输出 0
System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3
4.int compareToIgnoreCase(String str) 方法:与compareTo方式相同,但是忽略大小写比较
public static void main(String[] args) {
String s1 = new String("abc");
String s2 = new String("ac");
String s3 = new String("ABc");
String s4 = new String("abcdef");
System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1
System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0
System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3
}
三、字符串不可变
public static void main(String[] args) {
String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);
}
形如 += 这样的操作, 表面上好像是修改了字符串, 其实不是. 内存变化如下:
+= 之后 str 打印的结果却是变了, 但是不是 String 对象本身发生改变, 而是 str 引用到了其他的对象.
回顾引用
引用相当于一个指针, 里面存的内容是一个地址. 我们要区分清楚当前修改到底是修改了地址对应内存的内容发
生改变了, 还是引用中存的地址改变了.
那么如果实在需要修改字符串, 例如, 现有字符串 str = “Hello” , 想改成 str = “hello” , 该怎么办?
- 常见办法: 借助原字符串, 创建新的字符串
public static void main(String[] args) {
String str = "Hello";
str = "h" + str.substring(1);
System.out.println(str);
}
- 特殊办法(选学): 使用 “反射” 这样的操作可以破坏封装, 访问一个类内部的 private 成员.
为什么 String 要不可变?(不可变对象的好处是什么?) (选学)
- 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑何时深拷贝字符串的问题了.
- 不可变对象是线程安全的.
- 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中.