immutable
模式的对象,不变模式的主要作用是当一个对象需要被多线程共享并频繁访问时,可以保证数据的一致性String类型不是基本数据类型,String底层实现为char类型的数组
// 部分源码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
String实例化有两种方式:
char
类型的数组public static void main(String[] args) {
char[] arr = {'你', '好'};
String str1 = new String(arr);
String str2 = new String("Hello World");
String str3 = "Hello World";
}
直接赋值和通过构造函数创建的主要区别在于储存的区域不同,直接赋值的储存在字符串常量池中
public static void main(String[] args) {
String str1 = "Hello";
String str2 = "Hello";
System.out.println(str1 == str2); // true
}
通过构造函数创建的储存在堆内存中
public static void main(String[] args) {
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1 == str2); // false
}
String的equals方法:String的equals方法重写了Object类equals的方法,将String类型转换为char类型的数组,然后依次比较数组的每一位。
// equals源码
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
String不可变性:String的值一旦修改就会是一个新的对象,不是再原来的对象了
public static void main(String[] args) {
String str1 = "abc";
String str2 = str1;
str1 += "def";
System.out.println(str1 == str2); // false
}
String的intern()方法
当调用某个字符串对象的intern()方法时,会先去字符串常量池中寻找,如果已经存在一个值相等的字符串对象的话,则直接返回该对象的引用;如果不存在,则在字符串常量池中创建该对象,并返回。
public static void main(String[] args) {
String str1 = "Hello World";
String str2 = new String("Hello World");
System.out.println(str1 == str2); // false
String str3 = str2.intern();
System.out.println(str1 == str3); // true
}
String 常用方法
1、字符串截取
public String substring(int beginIndex)
:从beginIndex
开始截取,直到字符串结尾public String substring(int beginIndex,int endIndex)
:从beginIndex
开始截取,直到endIndex
结束,不包含endIndex
注意:截取之后原字符串不变
public static void main(String[] args) {
String str1 = "HelloWorld";
String substr1 = str1.substring(4);
String substr2 = str1.substring(4, 7);
System.out.println(str1); // HelloWorld
System.out.println(substr1); // oWorld
System.out.println(substr2); // oWo
}
2、字符串分割
public String[] split(String regex)
:将字符串按照regex
分割成数组,同时支持正则表达式public static void main(String[] args) {
String str = "python java;golang,javascript";
String[] arr = str.split("[,|;| ]");
System.out.println(Arrays.toString(arr)); // [python, java, golang, javascript]
}
要弄懂String类型,要先明白常量和变量的区别。常量是在编译时期就知道值是多少的;而变量是在运行时期才能确定值的
public static void main(String[] args) {
String str1 = "helloWorld";
String str2 = "hello" + "World";
System.out.println(str1 == str2); // true
}
字符串hello
和字符串World
都是常量,拼接之后的值还是保存在字符串常量池中的,所以地址相同
public static void main(String[] args) {
String str1 = "helloWorld";
String str2 = "hello";
str2 += "World";
System.out.println(str1 == str2); // false
}
看似和上一题差不多,但实际上上一题的str2
是有两个常量相加得到的,所以str2
储存的是常量池中地址;而这一道题的str2
是一个变量,变量储存在堆之中,同样一个变量加一个常量还是储存在堆中的,所以地址是不同的
public static void main(String[] args) {
String str1 = "helloWorld";
String str2 = "hello";
String str3 = str2 + "World";
System.out.println(str1 == str3); // false
}
同理,str1
在常量池中,str3
在堆中,所以他们的引用一定不相等
public static void main(String[] args) {
String str1 = "helloWorld";
final String str2 = "hello";
String str3 = str2 + "World";
System.out.println(str1 == str3); // true
}
这里str2
加上final
关键字之后称为常量,保存在常量池中,在加上常量World
之后返回的值还是常量,所以str1
和str3
是相等的
public static void main(String[] args) {
String str1 = "helloWorld";
final String str2 = new String("hello");
String str3 = str2 + "World";
System.out.println(str1 == str3); // false
}
这里虽然加上了final
但是通过构造函数创建的对象本身就是储存在堆中的
public static void main(String[] args) {
String str1 = "helloWorld";
String str2 = "hello";
String str3 = "World";
String str4 = str2 + str3;
System.out.println(str1 == str4); // false
System.out.println(str1 == str4.intern()); // true
}
参考资料:https://blog.csdn.net/qq_34490018/article/details/82110578