字符串常量池
-
字符串常量池是Java中的一个特殊区域,用于存储字符串常量,位于堆内存中。
-
在使用双引号创建字符串常量时,如果该字符串常量不存在,则会添加该字符串到字符串常量池中,并返回对该字符串的引用,如果存在,则直接返回,避免重复的创建。
-
使用new创建字符串时,String s3=new String(“Hello”); JVM首先是在字符串常量池中找"Hello" 字符串,如果没有创建字符串常量,然后放到常量池中,若已存在,则不需要创建;还会在内存(不是字符串常量池中)上创建一个新的String对象,存储"Hello",并将内存上的String对象引用地址返回
-
具有不变性。底层使用final来实现(不可被继承)。如果对字符串有什么操作,比如拼接,是直接新建一个字符串,而不是在原来的字符串修改。字符串常量池中的字符串对象是不可变的,一旦创建就不能被修改。
String str1 = "hello";
String str2 = "hello";
String str3 = new String("hello");
System.out.println(str1 == str2); // true,因为两者指向同一个字符串常量池中的对象
System.out.println(str1 == str3); // false,因为str3是在堆内存中创建的新对象
String str1 = "hello"; //str1指向静态区
String str2 = new String("hello"); //str2指向堆上的对象
String str3 = "hello";
String str4 = new String("hello"); System.out.println(str1.equals(str2));//true System.out.println(str2.equals(str4)); //true System.out.println(str1 == str3); //true
System.out.println(str1 == str2); //false System.out.println(str2 == str4); //false
System.out.println(str2 == "hello"); //false str2 = str1; System.out.println(str2 == "hello");//true
String 有没有 length()方法
数组没有 length()方法 ,有 length 的属性。String 有 length()方法。
String 类的常用方法
方法 | 描述 |
---|---|
length() | 返回字符串的长度。 |
charAt(int index) | 返回指定索引处的字符。 |
isEmpty() | 检查字符串是否为空。 |
indexOf(String str) | 返回指定子字符串在此字符串中第一次出现的索引。 |
lastIndexOf(String str) | 返回指定子字符串在此字符串中最后一次出现的索引。 |
substring(int beginIndex) | 返回一个新的字符串,从指定索引开始直到字符串末尾。 |
substring(int beginIndex, int endIndex) | 返回一个新的字符串,从指定的 beginIndex(包括)开始,到指定的 endIndex(不包括)结束。 |
startsWith(String prefix) | 检查字符串是否以指定的前缀开头。 |
endsWith(String suffix) | 检查字符串是否以指定的后缀结尾。 |
toLowerCase() | 将字符串转换为小写。 |
toUpperCase() | 将字符串转换为大写。 |
trim() | 去除字符串两端的空格。 |
replace(char oldChar, char newChar) | 将字符序列中出现的所有 oldChar 替换为 newChar。 |
replaceAll(String regex, String replacement) | 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。 |
equalsIgnoreCase(String anotherString) | 比较两个字符串,忽略大小写。 |
split(String regex) | 根据给定的正则表达式分割字符串为字符串数组。 |
join(CharSequence delimiter, CharSequence... elements) | 使用指定的分隔符连接字符串数组或可迭代对象的元素。 |
valueOf() | 将其他数据类型转换为字符串。 |
在使用 HashMap 的时候,为何用String做key
HashMap 内部实现是通过 key 的 hashcode 来确定 value 的存储位置,因为字符串是不可变的,所以当创建字符串时,它的 hashcode 被缓存下来,不需要再次计算,所以相比于其他对象更快
String和StringBuffer、StringBuilder的区别
String(不可变性):
-
String
是不可变的,一旦创建就不能被修改。每次对字符串的操作都会产生一个新的字符串对象。 -
不可变性带来的好处是线程安全,因为字符串不可变,所以它们可以被多个线程安全地共享,无需额外的同步开销。
-
不可变性也是字符串常量池的基础,因为相同的字符串常量可以被多个对象共享,节省内存。
-
String类中使用字符数组保存字符串,private final char value[],所以string对象是不可变的。StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,char[] value,这两种对象都是可变的。
-
AbstractStringBuilder是StringBuilder与StringBuffer的公共父类
-
每次对String 类型进行改变的时候,都会生成一个新的String对象,然后将指针指向新的String 对象。StringBuffer每次都会对StringBuffer对象本身进行操作,而不是生成新的对象并改变对象引用。
StringBuffer(线程安全):
-
StringBuffer
是可变的,它可以修改其内部存储的字符序列。 -
StringBuffer
的所有公共方法都是同步的,所以它是线程安全的。这意味着多个线程可以安全地同时修改一个StringBuffer
实例。
StringBuilder(非线程安全):
-
StringBuilder
也是可变的,它与StringBuffer
类似,但不同的是StringBuilder
的所有公共方法都不是同步的,因此它不是线程安全的。 -
StringBuilder
在单线程环境下的性能通常比StringBuffer
更好,因为它不需要同步。因此,如果在单线程环境下使用,通常优先使用StringBuilder
。
如何将字符串反转
使用 StringBuilder 或者 stringBuffer 的 reverse() 方法。
// StringBuffer reverse
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.
append("abcdefg");
System. out. println(stringBuffer. reverse()); // gfedcba
// StringBuilder
reverse StringBuilder stringBuilder = new StringBuilder(); stringBuilder. append("abcdefg");
System. out. println(stringBuilder. reverse()); // gfedcba