`
leonzhx
  • 浏览: 797351 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Strings, Literally

阅读更多

The SCJP Tip Line
Strings, Literally
by Corey McGlone


This month, I'm going to tackle String literals and how they're handled in Java. If you read last month's SCJP Tip Line article, you'll find that this article is a nice follow up all about Strings. If you didn't read it, no big deal - I plan to cover enough information here to get you up to speed. String literals are a little "special" in Java in the way that they are treated. For the most part, the information contained in this post is not on the SCJP exam, but I see it on mock exams all the time and it comes up in the SCJP Forum quite often. Besides, it's just darned interesting stuff.

Let's start off by asking a simple question. What is a String Literal? A String literal is a sequence of characters between quotation marks, such as "string" or "literal". You've probably used String literals hundreds of times in your own applications. You might not, however, have realized just how special String literals are in Java.

Strings are Immutable

So what makes String literals so special? Well, first of all, it's very important to remember that String objects are immutable. That means that, once created, a String object cannot be changed (short of using something like reflection to get at private data). Immutable, you say? Unchangable? What about this code?

Source Code
public class ImmutableStrings { public static void main(String[] args) { String start = "Hello"; String end = start.concat(" World!"); System.out.println(end); } } // Output Hello World!


Well look at that, the String changed...or did it? In that code, no String object was ever changed. We start by assigning "Hello" to our variable, start. That causes a new String object to be created on the heap and a reference to that object is stored in start. Next, we invoke the method concat(String) on that object. Well, here's the trick, if we look at the API Spec for String, you'll see this in the description of the concat(String) method:

Concatenates the specified string to the end of this string.
If the length of the argument string is 0, then this String object is returned. Otherwise, a new String object is created, representing a character sequence that is the concatenation of the character sequence represented by this String object and the character sequence represented by the argument string.

Examples:

    "cares".concat("s") returns "caress"
    "to".concat("get").concat("her") returns "together"

Parameters:
    str - the String that is concatenated to the end of this String.
Returns:
    a string that represents the concatenation of this object's characters followed by the string argument's characters.

Notice the part I've highlighted in bold. When you concatenate one String to another, it doesn't actually change the String object, it simply creates a new one that contains the contents of both of the original Strings, one after the other. That's exactly what we did above. The String object referenced by the local variable start never changed. In fact, if you added the statement System.out.println(start); after you invoked the concat method, you would see that start still referenced a String object that contained just "Hello". And just in case you were wondering, the '+' operator does the exact same thing as the concat() method.

Strings really are immutable.

 

Storage of Strings - The String Literal Pool

If you've done any preparation for the SCJP exam (and quite possibly even if you haven't), you've probably heard of the "String Literal Pool." What is the String Literal Pool? Most often, I hear people say that it is a collection of String objects. Although that's close, it's not exactly correct. Really, it's a collection of references to String objects. Strings, even though they are immutable, are still objects like any other in Java. Objects are created on the heap and Strings are no exception. So, Strings that are part of the "String Literal Pool" still live on the heap, but they have references to them from the String Literal Pool.

Yeah, so that doesn't really explain what the pool is, or what it's for, does it? Well, because String objects are immutable, it's safe for multiple references to "share" the same String object. Take a look at this example:

Source Code
public class ImmutableStrings { public static void main(String[] args) { String one = "someString"; String two = "someString"; System.out.println(one.equals(two)); System.out.println(one == two); } } // Output true true


In such a case, there is really no need to make two instances of an identical String object. If a String object could be changed, as a StringBuffer can be changed, we would be forced to create two separate objects. But, as we know that String objects cannot change, we can safely share a String object among the two String references, one and two. This is done through the String literal pool. Here's how it is accomplished:

When a .java file is compiled into a .class file, any String literals are noted in a special way, just as all constants are. When a class is loaded (note that loading happens prior to initialization), the JVM goes through the code for the class and looks for String literals. When it finds one, it checks to see if an equivalent String is already referenced from the heap. If not, it creates a String instance on the heap and stores a reference to that object in the constant table. Once a reference is made to that String object, any references to that String literal throughout your program are simply replaced with the reference to the object referenced from the String Literal Pool.

So, in the example shown above, there would be only one entry in the String Literal Pool, which would refer to a String object that contained the word "someString". Both of the local variables, one and two, would be assigned a reference to that single String object. You can see that this is true by looking at the output of the above program. While the equals() method checks to see if the String objects contain the same data ("someString"), the == operator, when used on objects, checks for referential equality - that means that it will return true if and only if the two reference variables refer to the exact same object. In such a case, the references are equal. From the above output, you can see that the local variables, one and two, not only refer to Strings that contain the same data, they refer to the same object.

Graphically, our objects and references would look something like this:



 


Note, however, that this is a special behavior for String Literals. Constructing Strings using the "new" keyword implies a different sort of behavior. Let's look at an example:

Source Code
public class ImmutableStrings { public static void main(String[] args) { String one = "someString"; String two = new String("someString"); System.out.println(one.equals(two)); System.out.println(one == two); } } // Output true false


In this case, we actually end up with a slightly different behavior because of the keyword "new." In such a case, references to the two String literals are still put into the constant table (the String Literal Pool), but, when you come to the keyword "new," the JVM is obliged to create a new String object at run-time, rather than using the one from the constant table.

In such a case, although the two String references refer to String objects that contain the same data, "someString", they do not refer to the same object. That can be seen from the output of the program. While the equals() method returns true, the == operator, which checks for referential equality, returns false, indicating that the two variables refer to distinct String objects.

Once again, if you'd like to see this graphically, it would look something like this. Note that the String object referenced from the String Literal Pool is created when the class is loaded while the other String object is created at runtime, when the "new String..." line is executed.



 


If you'd like to get both of these local variables to refer to the same object, you can use the intern() method defined in String. Invoking two.intern() will look for a String object referenced from the String Literal Pool that has the same value as the one you invoked the intern method upon. If one is found, a reference to that String is returned and can be assigned to your local variable. If you did so, you'd have a picture that looks just like the one above, with both local variables, one and two, referring to the same String object, which is also referenced from the String Literal Pool. At that point, the second String object, which was created at run-time, would be eligible for garbage collection.

Garbage Collection

What makes an object eligible for garbage collection? If you're preparing for the SCJP exam (or even if you're not), the answer to that question should roll right off your tongue. An object is eligible for garbage collection when it is no longer referenced from an active part of the application. Anyone see what is special about garbage collection for String literals? Let's look at an example and see if you can see where this is going.

Source Code
public class ImmutableStrings { public static void main(String[] args) { String one = "someString"; String two = new String("someString"); one = two = null; } }


Just before the main method ends, how many objects are available for garbage collection? 0? 1? 2?

The answer is 1. Unlike most objects, String literals always have a reference to them from the String Literal Pool. That means that they always have a reference to them and are, therefore, not eligible for garbage collection. This is the same example as I used above so you can see what our picture looked liked originally there. Once we assign our variables, one and two, to null, we end up with a picture that looks like this:



 


As you can see, even though neither of our local variables, one or two, refer to our String object, there is still a reference to it from the String Literal Pool. Therefore, the object is not eligible for garbage collection. The object is always reachable through use of the intern() method, as referred to earlier.

Conclusion

Like I said at the outset of this article, virtually none of this information is included on the SCJP exam. However, I constantly see this question coming up in the SCJP forum and on various mock exams. These are a few of the highlights you can keep in mind when it comes to String literals:

  • Equivalent String Literals (even those stored in separate classes in separate packages) will refer to the same String object.
  • In general, String Literals are not eligible for garbage collection. Ever.
  • Strings created at run-time will always be distinct from those created from String Literals.
  • You can reuse String Literals with run-time Strings by utilizing the intern() method.
  • The best way to check for String equality is to use the equals() method.

Be sure to check out these resources, as well:

API Spec for String
JLS, §3.10.5 String Literals

Tune in to the SCJP TipLine for more updates.

 

This article originates from http://www.javaranch.com/journal/200409/Journal200409.jsp#a1

  • 大小: 29.7 KB
  • 大小: 35.6 KB
  • 大小: 26.3 KB
分享到:
评论

相关推荐

    Strings字符串分析工具

    《Strings字符串分析工具详解》 在计算机领域,字符串分析是一个重要的技术手段,尤其在病毒分析、逆向工程和软件调试中扮演着不可或缺的角色。Strings工具就是这样一个强大的实用程序,它能够从二进制文件中提取出...

    两个Strings.xml的比较

    1、此程序用来比较2个Strings.xml中name的不同项,并打印出来; 2、使用前,请先将两个String.xml重命名为:strings_en.xml(英文或其他语言)和strings_zh.xml(中文); 3、此程序是通过strings_zh.xml去检索...

    strings.exe

    "Strings.exe"是一款在Windows操作系统环境下广泛使用的实用程序,它主要功能是用于从二进制文件(如可执行文件、库或数据文件)中提取连续的ASCII或Unicode字符序列,即字符串。这个工具对于系统管理员、软件开发者...

    ns_strings_zh.xml

    ns_strings_zh.xml

    Android 自动化生成多语言strings文件

    在Android应用开发中,为了支持多种语言环境,开发者通常需要创建多个`strings.xml`文件,分别对应不同的语言,如英语、简体中文、繁体中文等。这些文件存储在项目的`res/values`目录下,用于定义应用中的文本资源。...

    Format Strings

    `Standard Date and Time Format Strings_files`、`Standard Numeric Format Strings_files`、`Custom Date and Time Format Strings_files`和`Custom Numeric Format Strings_files`这些文件夹可能包含支持上述网页...

    ns_strings_zh_storyline.xml

    ns_strings_zh_storyline.xml

    strings 字符串分析工具

    通过静态分析来最大程度上的获取PE文件的信息,从而帮助我们了解其行为动态和作用方式,

    android strings

    在Android开发中,"strings"是一个非常关键的概念,它涉及到应用程序中的文本管理和国际化。本文将深入探讨`strings.xml`文件及其在Android应用开发中的作用,同时也会提及与之相关的`colors.xml`文件。 首先,`...

    c++ Strings

    ### C++ Strings: A Comprehensive Overview #### Introduction One of the key shortcomings often highlighted in the C programming language is its lack of a built-in string type. Instead, strings in C ...

    POJ3096-Surprising Strings

    北京大学的在线编程平台POJ上有一道题目名为“Surprising Strings”(POJ 3096),这是一道考察算法思维和编程能力的题目。在本篇解题报告中,我们将深入探讨该问题的背景、问题分析、解决方案以及实现代码,同时也...

    strings.xml文件读取html标签示例

    在Android开发中,`strings.xml` 文件是存储应用中各种字符串资源的重要地方,它使得文本内容的管理和国际化变得更为方便。本示例将探讨如何从`strings.xml` 文件中读取包含HTML标签的字符串,并在Android应用中正确...

    strings_zh.xml

    strings_zh.xml

    4sSpringBoard.strings原生

    本文档包准确,iPhone越狱后修改滑动解锁损坏SpringBoard.strings文件修复,此文件适用于ios7.1.2原生

    android的strings.xml示例代码

    在Android开发中,`strings.xml`文件是管理应用中所有文本资源的核心文件。它使得开发者可以集中处理字符串,便于国际化和本地化,同时也方便代码维护。在这个`StringDemo`示例中,我们将深入探讨如何使用`strings....

    pku acm 2406 Power Strings代码

    pku acm 2406 Power Strings代码 kmp算法。解题报告:http://blog.csdn.net/china8848

    Computing Patterns in Strings [djvu]

    William Smyth-Computing Patterns in Strings -Addison Wesley.djvu 0积分

    Ruby-Rubustrings检查Localizablestrings文件的格式和一致性

    在进行国际化处理时,一个重要的环节是确保Localizable.strings文件的格式正确且内容一致。Localizable.strings文件用于存储应用程序中的多语言文本,使得程序可以适应不同的地区和语言设置。`Rubustrings`是一个...

    android多语言strings.xml,arrays.xml转xls与xls转xml脚本程序

    `strings.xml`和`arrays.xml`文件是Android资源文件中的核心组件,用于存储应用程序中的文本和数组数据。这些文件通常包含不同语言的字符串资源,以便在不同地区展示相应的本地化内容。 本话题涉及一个脚本程序,它...

    action strings

    ACTIONSTRINGS是一款用于影视和游戏音乐制作中的弦乐音源库,它由EastWest公司开发。这款软件包含了大量的乐句和主题,可以让使用者通过简单的操作来创造出复杂的弦乐片段。 首先,ACTIONSTRINGS提供了154个乐句和...

Global site tag (gtag.js) - Google Analytics