String.intern aka “I never knew that…”

Ok, so I’m trying to fill in any gaps in my java knowledge. First thing is going through my fairly comprehensive SCJP 1.5 study book. Mainly common stuff I’ve used enough of but the odd thing is of interest. Today I found the ‘intern’ method on Strings. I’ll explain.

The typical Java developer is aware of the following:

  • Strings are immutable.
  • Strings typically live in a String pool.
  • Strings should be checked for equality using the equals method, not ‘==’.

You can create a String not in the String pool using the the following:

String foo = new String("bar");

What we typically want, though, is String reuse, via the String pool. An interesting method exists around Strings to ensure getting the String instance from the String pool, this method is ‘intern’. Here is the javadoc lifted from the JSE1.7 site:

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 section 3.10.5 of the The Java™ Language Specification.

Here is a class to demonstrate with tests. It uses the System.identityHashCode(Object) method to show which object reference is being looked at.

import junit.framework.Assert;
import org.junit.Test;

public class StringTest {
	final String test = "test";
	@Test
	public void testStrings() {

		final String stackTest = "test";
		final String stackTest2 = new String("test");
		final String stackTest2Interned = stackTest2.intern();

		Assert.assertEquals("test", test);
		Assert.assertTrue("test" == test);
		Assert.assertTrue(stackTest == test);
		Assert.assertFalse(stackTest2 == test);
		Assert.assertTrue(stackTest2Interned == test);

		System.out.println("id of constant = " + System.identityHashCode(test));
		System.out.println("id of stackTest = " + System.identityHashCode(stackTest));
		System.out.println("id of stackTest2 = " + System.identityHashCode(stackTest2));
		System.out.println("id of stackTest2Interned = " + System.identityHashCode(stackTest2Interned));
	}
}

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s