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 = "techArcher";
String two = "techArcher";
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 "techArcher". Both of the local variables, one andtwo, 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 ("techArcher"), 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 = "techArcher";
String two = new String("techArcher");
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, "techArcher", 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.
// 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 "techArcher". Both of the local variables, one andtwo, 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 ("techArcher"), 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 = "techArcher";
String two = new String("techArcher");
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, "techArcher", 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.


No comments:
Post a Comment