Java_字符串池以及字符串类

Posted 小企鹅推雪球!

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java_字符串池以及字符串类相关的知识,希望对你有一定的参考价值。

Java_字符串池的概念

  1. JVM为了提升性能和减少内存开销,避免字符串的重复创建,其维护了一块特殊的内存空间,即字符串池(String Pool),字符串池由String类维护
  2. 在Java中存在两种船舰字符串对象得到方式:
  3. 第一种:采用字面量的方式赋值: String str = "ASD"
  4. 第二种:采用new关键字新建一个字符串对象:String str = new Sring("ASD")
  5. 以上两种创建方式存在性能和内存占用方面存在差别
package com.company;
// 字符串池的样例
public class Java_16 {
    public static void main(String[] args) {
//      采用字面值的方式赋值
        String str1 = "ASD";
        String str2 = "ASD";
        System.out.println(str1 == str2); // 输出 true
//        采用new关键字的方式赋值
        String str3 = new String("ASD");
        String str4 = new String("ASD");
        System.out.println(str3 == str4); // 输出 false
    }
}

Java_采用字面值方式创建字符串

  1. 采用字面值方式创建一个字符串,JVM首先会区字符串池中查找是否存在"ASD"这个对象,
  2. 如果不存在"ASD"对象,则会新建一个"ASD"对象,然后将池中的"ASD"对象的引用地址返回给字符串常量str,这样,str会指向"ASD"对象,
  3. 如果存在"ASD"对象,则不创建任何对象,直接将池中的"ASD"对象的值返回给"str"

Java_采用new关键字创建字符串

  1. 采用new关键字新建一个字符串对象时,JVM首先在字符串池中查找有没有"aaa"这个字符串对象,
  2. 如果有,则不在池中再去创建"ASD"这个对象了,直接在堆中创建一个"ASD"字符串对象,然后将堆中的这个"ASD"对象的地址返回赋给引用str3,这样,str3就指向了堆中创建的这个"ASD"字符串对象;
  3. 如果没有,则首先在字符串池中创建一个"ASD"字符串对象,然后再在堆中创建一个"ASD"字符串对象,然后将堆中这个"ASD"字符串对象的地址返回赋给str3引用,这样,str3指向了堆中创建的这个"ASD"字符串对象。
  4. 采用new关键字创建对象时,每次new出来的都是一个新的对象,也即是说引用str3和str4指向的是两个不同的对象,

Java_字符串池的前提条件

  1. String对象是不可变的。因为这样可以保证多个引用可以同事指向字符串池中的同一个对象。
  2. 如果字符串是可变的,那么一个引用操作改变了对象的值,对其他引用会有影响,这样显然是不合理的。

Java_字符串池的优缺点

  1. 字符串池的优点就是避免了相同内容的字符串的创建,节省了内存,省去了创建相同字符串的时间,同时提升了性能
  2. 字符串池的缺点就是牺牲了JVM在常量池中遍历对象所需要的时间,不过其时间成本相比而言比较低。

Java_intern方法

  1. 一个初始为空的字符串池,由String类单独维护,当调用intern方法时
  2. 如果池已经包含一个等于此String对象的字符串(用equals(oject)方法确定),则返回池中的字符串。
  3. 如果池中不存在一个等于此String对象的字符串:将此String对象添加到池中,并返回此String对象的引用。 对于任意两个字符串s和t,当且仅当s.equals(t)为true时,s.instan() == t.instan才为true。
  4. 所有字面值字符串和字符串赋值常量表达式都使用 intern方法进行操作。
package com.company;
// intern 方法
public class Java_17 {

    public static void main(String[] args) {
        String Str1 = new String("ASD");
        String Str2 = new String("ASD");

        System.out.print("相等:" );
        System.out.println(Str1.intern());

        System.out.print("相等:" );
        System.out.println(Str2.intern());
    }
}

Java_字符串注意事项

  1. 每一个字符串常量都指向字符串池中或者堆内存中的一个字符串实例;
  2. 字符串对象值是固定的,一旦创建就不能再修改;
  3. 字符串常量或者常量表达式中的字符串都被使用方法String.intern()在字符串池中保留了唯一的实例
  4. 同一个包下同一个类中的字符串常量的引用指向同一个字符串对象;
  5. 同一个包下不同的类中的字符串常量的引用指向同一个字符串对象;
  6. 不同的包下不同的类中的字符串常量的引用仍然指向同一个字符串对象;
  7. 由常量表达式计算出的字符串是在编译时进行计算,然后被当作常量;
  8. 在运行时通过连接计算出的字符串是新创建的,因此是不同的;
  9. 通过计算生成的字符串显示调用intern方法后产生的结果与原来存在的同样内容的字符串常量是一样的。

Java_String类

String的特性:

1.String类:代表字符串。Java 程序中的所有字符串字面值(如"abc" )都作为此类的实例实现
2. String是一个final类,代表不可变的字符序列
3. 字符串是常量,用双引号表示,字符串的值在创建之后不能更改
4. String对象的字符内容是存储在一个字符数组value[]中的。

String对象的创建:

String str = "hello";
//本质上this.value = new char[0];
String  s1 = new String();
 
//this.value = original.value;
String  s2 = new String(String original); 

//this.value = Arrays.copyOf(value, value.length);
String  s3 = new String(char[] a); 
String  s4 = new String(char[] a,int startIndex,int count);

字符串常量存储在字符串常量池,目的是共享
字符串非常量对象存储在堆中

String str1  = “abc”;String str2 = new String(“abc”);的区别

两个字符串拼接的情况:

  1. 常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
  2. 两个字符串只要其中有一个是变量,结果就在堆中
  3. 如果拼接的结果调用intern()方法,返回值就在常量池中

Java_字符串使用陷阱

  1. String s1 = "a";在字符串常量池中创建了一个字面量为"a"的字符串。
  2. String s1 = "a";s1 = s1 + "b";实际上原来的“a”字符串对象已经丢弃了,现在在堆空间中产生了一个字符串s1+"b"(也就是"ab")。如果多次执行这些改变串内容的操作,会导致大量副本字符串对象存留在内存中,降低效率。如果这样的操作放到循环中,会极大影响程序的性能
  3. String s2 = "ab":直接在字符串常量池中创建一个字面量为"ab"的字符串。
  4. String s3 = "a" + "b";s3指向字符串常量池中已经创建的"ab"的字符串。
  5. String s4 = s1.intern();堆空间的s1对象在调用intern()之后,会将常量池中已经存在的"ab"字符串赋值给s4

Java_string类常用方法

1.返回值int 类型 length():返回字符串的长度:return value.length
2. 返回值 char 类型 charAt(int index):返回某索引处的字符return value[index]
3. 返回值 boolean 类型`` isEmpty():判断是否是空字符串:return value.length == 0
4.返回值 String 类型 toLowerCase():使用默认语言环境,将String 中的所有字符转换为小写
4. 返回值String类型 toUpperCase():使用默认语言环境,将String 中的所有字符转换为大写
5. 返回值String类型 trim():返回字符串的副本,忽略前导空白和尾部空白
6. 返回值boolean类型 equals(Object obj):比较字符串的内容是否相同
7. 返回值boolean 类型`` equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
8. 返回值 String 类型 concat(String str):将指定字符串连接到此字符串的结尾。等价于用“+
9. 返回值int 类型``compareTo(String anotherString):比较两个字符串的大小
10. 返回值String 类型 substring(int beginIndex) :返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。
11. 返回值 String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。
12. 返回值类型 boolean contains(CharSequence s):当且仅当此字符串包含指定的char 值序列时,返回true
13. 返回值类型 int indexOf(String str):返回指定子字符串在此字符串中第一次出现处的索引
14. 返回值类型int indexOf(String str, int fromIndex):返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始搜索
15. 返回值类型 int lastIndexOf(String str):返回指定子字符串在此字符串中最右边出现处的索引
16. 返回值类型 int lastIndexOf(String str, int fromIndex):返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
注意:indexOf和lastIndexOf方法如果未找到都是返回-1
17. 返回值类型 String replace(char oldChar, char newChar):返回一个新的字符串,它是通过用newChar 替换此字符串中出现的所有oldChar 得到的。
18. 返回值类型String replace(CharSequence target, CharSequence replacement):使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。

Java_StringBuffer类

  1. java.lang.StringBuffer代表可变的字符序列,JDK1.0中声明,可以对字符串内容进行增删,此时不会产生新的对象。
  2. StringBuffer类不同于String,其对象必须使用构造器生成,

StringBuffer类的三个构造器

  1. StringBuffer():初始容量为16的字符串缓冲区
  2. StringBuffer(int size):构造指定容量的字符串缓冲区
  3. StringBuffer(String str):将内容初始化为指定字符串内容
String s = new String("我喜欢学习"); // 定义 s 的值以后,就不能被修改了
StringBuffer buffer = new StringBuffer("我喜欢学习");  // 还能被修改
buffer.append("数学"); // 此时 buffer 的变为 "我喜欢学习数学"

Java_StrigBuffer类常用方法

  1. StringBuffer append(xxx):提供了的append()方法,用于进行字符串拼接
  2. StringBuffer delete(int start,int end):删除指定位置的内容
  3. StringBuffer replace(int start, int end, String str):把[start,end)位置替换为str
  4. StringBuffer insert(int offset, xxx):在指定位置插入xxx
  5. StringBuffer reverse() :把当前字符序列逆转

注意:当append和insert时,如果原来value数组长度不够,可扩容

Java_StringBuilder类

  1. StringBuilder 和StringBuffer非常类似,均代表可变的字符序列,而且提供相关功能的方法也一样

String,StringBuffer,StringBuilder之间的区别:

  1. String:是不可变的字符序列
  2. StringBuffer:可变字符序列,效率低,线程安全
  3. StringBuilder:可变字符序列,效率高,线程不安全
  4. 作为参数传递的话,方法内部String不会改变其值,StringBuffer和StringBuilder会改变其值

以上是关于Java_字符串池以及字符串类的主要内容,如果未能解决你的问题,请参考以下文章

基础Java 8 中的常量池字符串池包装类对象池

JAVA String介绍常量池及StringStringBuilder和StringBuffer得区别. 以及8种基本类型的包装类和常量池得简单介绍

对于JVM中方法区,永久代,元空间以及字符串常量池的迁移和string.intern方法

Java中关于String类以及字符串拼接的问题

java常量池共享是啥意思?每个类都有自己的一个常量池吗?

java 常量池