Java中的常量字符串池

时间:2020-01-09 10:34:53  来源:igfitidea点击:

使用字符串文字(用双引号引起来的值)创建String对象时,该String对象是在内存的一部分(在Java中称为常量字符串池)中创建的。在本教程中,我们将学习什么是Java中的字符串池以及在创建字符串时如何优化内存。

有关为使Java中的String更节省空间而添加的另一个功能,请检查此文章Java 9中的Compact Strings。

Java常量字符串池

用Java创建字符串的方法有两种:

  • 使用字符串文字
  • 使用新关键字

例如,当我们使用字符串文字创建字符串时

String str = “hello”

在Java中称为字符串池的存储区中创建此字符串的内存。此字符串池是堆内存的一部分。
现在的问题是,为什么需要此字符串池,以及它如何优化内存使用? String是Java中的特殊类,也是最常用的类之一。这就是为什么使用常量字符串池的概念来最大程度地减少内存使用的原因。

每当创建任何String文字时,如果返回相同的引用,JVM就会在String池中扫描具有相同值的任何String。因此,不会为同一字符串分配新的内存,而是使用现有的内存。

让我们看一个例子。如果按以下方式创建两个字符串,则:

String str1 = “Hello”;
String str2 = “Hello”;

然后两个对象都引用相同的内存。

我们也可以使用Java程序进行验证。在示例中,使用字符串文字创建了两个字符串,然后使用等号" =="运算符比较了它们的引用。

public class StringLiteral {
	public static void main(String[] args) {
		String str1 = "Hello";
		String str2 = "Hello";
		// checking if memory reference is same
		if(str1 == str2){
			System.out.println("str1 and str2 are pointing to same memory reference");
		}else{
			System.out.println("str1 and str2 are not pointing to same memory reference");
		}
	}
}

输出:

str1 and str2 are pointing to same memory reference

仅通过String在Java中是不可变的,才可以通过String池有效地使用内存。

使用new运算符创建String

使用new运算符创建String实例时,新实例的内存将在堆上而不是在String池中创建。

例如,如果创建三个字符串,如下所示:

String str1 = “Hello”;
String str2 = “Hello”;
String str3 = new String(“Hello”);

str1和str2在常量字符串池中共享相同的引用,其中str3引用堆上的内存位置。
我们也可以使用Java程序进行验证。在示例中,创建了三个字符串,两个使用字符串文字,一个使用new运算符。使用相等的" =="运算符比较它们的引用。

public class StringLiteral  {
	public static void main(String[] args) {
		String str1 = new String("Hello");
		String str2 = "Hello";
		String str3 = "Hello";
		// instance and literal
		if(str1 == str2) {
			System.out.println("str1 and str2 are pointing to same memory reference");
		}else{
			System.out.println("str1 and str2 are not pointing to same memory reference");
		}
		// instance and literal
		if(str1 == str3) {
			System.out.println("str1 and str3 are pointing to same memory reference");
		}else{
			System.out.println("str1 and str3 are not pointing to same memory reference");
		}
		// literal and literal
		if(str2 == str3) {
			System.out.println("str2 and str3 are pointing to same memory reference");
		}else{
			System.out.println("str2 and str3 are not pointing to same memory reference");
		}
	}
}

输出:

str1 and str2 are not pointing to same memory reference
str1 and str3 are not pointing to same memory reference
str2 and str3 are pointing to same memory reference

如果使用new运算符创建了两个具有相同值的实例,那么将为这两个对象分配不同的内存。

public class StringLiteral  {
	public static void main(String[] args) {
		String str1 = new String("Hello");
		String str2 = new String("Hello");
		if(str1 == str2) {
			System.out.println("str1 and str2 are pointing to same memory reference");
		}else{
			System.out.println("str1 and str2 are not pointing to same memory reference");
		}
	}
}

输出:

str1 and str2 are not pointing to same memory reference

Java字符串实习

共享内存的过程在Java中称为Interning。在Java中,使用String.intern方法对字符串文字进行"内联",以共享唯一的实例。对于字符串文字,此过程是隐式的。

明确使用实习方法

我们也可以通过显式使用intern方法来实习字符串。这样,我们甚至可以将字符串池用于使用new运算符创建的字符串。

调用intern方法时,如果池已经包含等于equals(Object)方法确定的此String对象的字符串,则返回池中的字符串。否则,将此String对象添加到池中,并返回对此String对象的引用。

public class StringLiteral  {
  public static void main(String[] args) {
    String str1 = "Hello";
    String str2 = new String("Hello");
    // created using intern
    String str3 = new String("Hello").intern();
    // str3 = str2.intern(); can be created this way too
    if(str1 == str2) {
      System.out.println("str1 and str2 are pointing to same memory reference");
    }else{
      System.out.println("str1 and str2 are not pointing to same memory reference");
    }
    
    if(str1 == str3) {
      System.out.println("str1 and str3 are pointing to same memory reference");
    }else{
      System.out.println("str1 and str3 are not pointing to same memory reference");
    }
    
    if(str2 == str3) {
      System.out.println("str2 and str3 are pointing to same memory reference");
    }else{
      System.out.println("str2 and str3 are not pointing to same memory reference");
    }
  }
}

输出:

str1 and str2 are not pointing to same memory reference
str1 and str3 are pointing to same memory reference
str2 and str3 are not pointing to same memory reference

如我们所见,String str3是使用intern方法创建的,因此它将使用String池。由于池中已经存在一个具有相同值的String,因此str3使用相同的引用,这就是为什么str1和str3具有相同的引用。