The Effect of Caching in Wrapper Classes

Caching in Java wrapper classes - Image of wrapped chocolates

Here’s a fact that you may not know. When you auto-box integral primitives (byteshortint and long) to their respective wrapper classes (ByteShortInteger and Long), the wrapper classes cache all values from -128 to +127. These values are later used by the valueOf() methods to give better performance than using a constructor.

Auto-boxing to wrapper classes

Let’s use an example of auto-boxing an int into an Integer.

Integer a = 33;

Behind the scenes when the compiler generates code to auto-box the int, it uses the static Integer.valueOf() method. The valueOf() method first checks the cache. If the value to be auto-boxed falls in the range -128 to +127, then it returns the previously-created cached Integer. Otherwise it creates a new Integer object. This yields better performance for commonly used values.

Example

Let’s look at a code snippet:

Integer a = 33;  // same as Integer a = Integer.valueOf(33);  
Integer b = 33;
Integer c = new Integer (33);
System.out.printf("a == b : %b%n", a==b);
System.out.printf("a == c : %b%n", a==c);
System.out.printf("a.equals(b) : %b%n", a.equals(b));
System.out.printf("a.equals(c) : %b%n", a.equals(c));

Comparing a and b with the == operator returns true, while a == c returns false.

Both a and b refer to the same object in the cache, while c refers to a new Integer object on the heap. Using the equals() method will always return true.

Now let’s change the values of ab and c to the following:

Integer a = 133;
Integer b = 133;
Integer c = new Integer (133);
System.out.printf("a == b : %b%n", a==b);
System.out.printf("a == c : %b%n", a==c);
System.out.printf("a.equals(b) : %b%n", a.equals(b));
System.out.printf("a.equals(c) : %b%n", a.equals(c));

Now a == b returns false because they refer to different objects. This is because their values are outside the range of the cache limits. New Integer objects have been created for each value when auto-boxed.

Changing the Cache Limit

We can change the upper cache limit, but not the lower limit. When starting the JVM, we can use either of two options (the xxx is the value you want for the upper limit):

java -Djava.lang.Integer.IntegerCache.high=xxx MyClass

or

java -XX:AutoBoxCacheMax=xxx MyClass

The -D option will always work, but the -XX: option is non-standard, and may not be supported by the compiler you are using.

Why do you need to know about this caching?

There are practical implications of caching other than just performance. Not knowing about the cache can lead to unexpected behaviour when comparing wrapped integral numbers which may take you a lot of time and effort to track down. And as an added knowledge bonus, it’s also a common question in certification exams.

If you found this useful, please leave a comment.

Leave a Comment

Your email address will not be published. Required fields are marked *

Code like a Java Guru!

Thank You

We're Excited!

Thank you for completing the form. We're excited that you have chosen to contact us about training. We will process the information as soon as we can, and we will do our best to contact you within 1 working day. (Please note that our offices are closed over weekends and public holidays.)

Don't Worry

Our privacy policy ensures your data is safe: Incus Data does not sell or otherwise distribute email addresses. We will not divulge your personal information to anyone unless specifically authorised by you.

If you need any further information, please contact us on tel: (27) 12-666-2020 or email info@incusdata.com

How can we help you?

Let us contact you about your training requirements. Just fill in a few details, and we’ll get right back to you.

Your Java tip is on its way!

Check that incusdata.com is an approved sender, so that your Java tips don’t land up in the spam folder.

Our privacy policy means your data is safe. You can unsubscribe from these tips at any time.