创建String对象

关于String和内存的重要内容

摘自[]Kathy Sierra,[] Bert Bates所著《Sun Certified Programmer & Developer for Java 2(Exam 310-035 & 310-027)》一书中,关于String和内存的重要内容

 

所有程序设计语言的关键目标之一都是有效地使用内存。随着应用程序的发展,String处理占用一个程序的大量内存非常常见,在程序中大量的String常量内常常有大量的冗余,为了使Java更有效地使用内存,JVM留出一块特殊的内存区域,它被称为“String常量池。当编译器遇到String常量时,它检查该池内是否已经存在相同的String常量。如果找到相同的常量,则把对新常量的引用指向现有的String,不创建任何新的String常量对象(现有的String只是具有一个额外的引用)。现在我们能够看出为什么使String对象不可改变是一个好想法。如果几个引用变量引用相同的String,假若其中任何一个能够修改该String的值,那么它就会变得非常糟糕。

你可能会说:这一切都好,但是,如果某个人重写String类功能会怎么样,这会导致String常量池出问题吗?这是String类被标识为final的主要原因之一。任何人都不能重写任何一个String方法的操作,因此,事实上可以放心所有的String对象将是不变的。

创建String各种方法之间的细微差别:

String s1 = "hello"; //creates one String object and one reference vaiable

在这情况下,"hello"将进入String常量池中,s1将引用它。(一个对象,一个引用)

String s2 = new String("hello"); //create two objects, and one refrence variable

在这种情况,因为使用了new 关键字,所以将在常规内存——堆中(不是池内)创建一个新的String对象,并且s2将引用它。此外,将把"hello"放置在String常量池中。(二个对象,一个引用)

 

常量池(constant pool

摘自《Java虚拟机规范》:

 

常量池是每个类或每个接口的Java class文件中的constant_pool表的运行期表示。它包含几种常量,范围从编译期已知的数值文字到必须在运行期解析的方法或变量引用。常量池的功能类似于传统程序设计语言的符号表,尽管它比通常的符号表包含更宽的数据范围。

每个常量池都从Java虚拟机的方法区分配。类或者接口的常量池在该类或者接口的Java class文件被Java虚拟机成功的装载时创建。

以下异常情况与类或接口的常量池的创建相关:

  • 在装载 class 文件时,如果常量池的创建需要比 Java 虚拟机中的方法区中可获得的更多的存储空间,则 Java 虚拟机抛出 OutOfMemoryError 。

String java.lang.String.intern()

当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用;如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用。 

 

public String intern()

Returns a canonical representation for the string object.

A pool of strings, initially empty, is maintained privately by the class String.

When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned.

It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.

All literal strings and string-valued constant expressions are interned. String literals are defined in §3.10.5 of the Java Language Specification

Returns:

a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.

返回String对象的标准表示(canonical representation),即字符串的内容,

String类维护了一个私有的字符串(strings)池(初始时是空的)。

调用String对象的intern()方法时,如果字符串池中已经包含了一个与当前String对象相等的字符串(是否相等由equals(Object)方法决定),则返回池中的字符串。否则,String对象会被添加到字符串池中,返回一个对当前对象的引用。

对任意两个字符串st,当且仅当s.equals(t)true时,s.intern() == t.intern()才为true

 

         String s1 = new String("hello");

         String s2 = new String("hello");

         String s3 = "hello";

         System.out.println(s2 == s1);//false

         System.out.println(s3 == s1);//false

         String s4 = s1.intern();//s1.intern()返回的是常量池中的“hello”引用

         System.out.println(s2 == s4);//false

         System.out.println(s3 == s4);//true

         String s5 = s2.intern();

         System.out.println(s5 == s4);//true

String.intern()后,字符串保存在String类的常量池中,而常量池在方法区中。方法区也可以被垃圾收集。因为程序中的内由类加载器动态加载,所有类可能变成没有被引用(unreferenced)的状态。当类变成这种状态时,他就可 能被垃圾收集掉。但是因为String类是永远不会被垃圾收集的,所以String的常量池里的内容就永远不会被回收了,也不要随便使用String.intern()方法。

String s1 = new String() String s2 = nullString s3=new String(“”)

String s1 = new String() 声明了一个String类型的变量s1,这个变量是一个引用,它指向一个对象,但是此对象的内容为空。
String s2 = null
仅仅是声明了一个String类型的变量s,但是这个s并不指向任何一个对象。

String s3=new String(“”)String s1 = new String()相同:

System.out.println(s1.equals(s2));//true
System.out.println(s1.hashCode()==s2.hashCode());//true

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值