About Joonas Javanainen

Joonas is a passionate software developer from Finland. He has worked on a multitude of problem domains, and focuses professionally on functional programming and JVM-based technologies.

Java pitfalls: Field access in inner classes

This is not a “pitfall” per se, but an implementation detail worth knowing. Let’s say I have a inner class with a field. Such a field is visible to the enclosing class, but which one of the following ways is the fastest way to access it? Note! I’m only looking here at the generated bytecode, and not considering any JIT optimizations, so this “performance analysis” is very naïve

public class Test {

  public void testAlternatives() {
    // Alternative 1
    System.out.println(new Inner().field);
    // Alternative 2
    System.out.println(new Inner().getField());
    // Alternative 3
    System.out.println(new Inner2().field);
    // Alternative 4
    System.out.println(new Inner2().getField());
  }

  class Inner {
    private int field;

    public int getField() {
      return field;
    }
  }

  class Inner2 {
    int field;

    public int getField() {
      return field;
    }
  }

}

An intuitive answer is that alternatives 1 and 3 are equally fast because the field is always visible to the enclosing class, and both use field access which is overall slightly faster than method access used in alternatives 2 and 4. However, there’s an implementation detail that causes this to be untrue. The JVM itself does not have a concept called “inner classes”. The whole concept is implemented by the Java compiler and in the bytecode level everything consists of normal classes.

The issue here is that if the inner class has a private field, and the compiler will eventually compile the inner class as a normal class. A private field in a normal class cannot be accessed by other classes, so the enclosing Test class cannot “see” the field without some tricks. Here’s the above code “desugared” to what the compiler actually compiles to bytecode:

public class Test {
  public void testAlternatives() {
    // Alternative 1
    System.out.println(Test$Inner.access$000(new Test$Inner(this)));
    // Alternative 2
    System.out.println(new Test$Inner(this).getField());
    // Alternative 3
    System.out.println(new Test$Inner2(this).field);
    // Alternative 4
    System.out.println(new Test$Inner2(this).getField());
  }
}

class Test$Inner {
  final Test this$0;

  private int field;

  Test$Inner(Test test) {
    this$0 = test;
  }

  public int getField() {
    return field;
  }

  static int access$000(Test$Inner inner) {
    return inner.field;
  }

}

class Test$Inner2 {
  final Test this$0;

  int field;

  Test$Inner2(Test test) {
    this$0 = test;
  }

  public int getField() {
    return field;
  }

}

As you can see, a package-level static accessor method called access$000 is generated in order to grant access to the private field. Now it’s easier to see that alternative 3 will most likely be the fastest one, because it is the only one that uses direct field access. Using package access in fields is a micro-optimization, but this whole thing is definitely a detail that should be known by Java developers. In performance-critical parts of code it might actually matter, and the Android performance guide actually mentions this implementation detail.

This implementation detail may also cause slight confusion when field access is attempted on a null reference of the inner class. Consider the following code:

public class NullTest {
  class Inner {
    private int field;
  }

  public void test() {
    Inner inner = null;
    System.out.println(inner.field);
  }

  public static void main(String[] args) {
    new NullTest().test();
  }
}

The variable “inner” is null, so a NullPointerException is obviously thrown. However, what is not apparent from the original code is that the exception is thrown inside the compiler-generated static accessor method!

$ java NullTest
Exception in thread 'main' java.lang.NullPointerException
 at NullTest$Inner.access$000(NullTest.java:2)
 at NullTest.test(NullTest.java:8)
 at NullTest.main(NullTest.java:12)

The stack trace contains the intuitive exception source (line 8), but the real source will confuse developers who don’t know about compiler-generated accessor methods.

Reference: Java pitfalls: Field access in inner classes from our JCG partner Joonas Javanainen at the Jawsy Solutions technical blog blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

JPA Mini Book

Learn how to leverage the power of JPA in order to create robust and flexible Java applications. With this Mini Book, you will get introduced to JPA and smoothly transition to more advanced concepts.

JVM Troubleshooting Guide

The Java virtual machine is really the foundation of any Java EE platform. Learn how to master it with this advanced guide!

Given email address is already subscribed, thank you!
Oops. Something went wrong. Please try again later.
Please provide a valid email address.
Thank you, your sign-up request was successful! Please check your e-mail inbox.
Please complete the CAPTCHA.
Please fill in the required fields.

Leave a Reply


eight − = 4



Java Code Geeks and all content copyright © 2010-2014, Exelixis Media Ltd | Terms of Use | Privacy Policy | Contact
All trademarks and registered trademarks appearing on Java Code Geeks are the property of their respective owners.
Java is a trademark or registered trademark of Oracle Corporation in the United States and other countries.
Java Code Geeks is not connected to Oracle Corporation and is not sponsored by Oracle Corporation.
Do you want to know how to develop your skillset and become a ...
Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you two of our best selling eBooks for FREE!

Get ready to Rock!
You can download the complementary eBooks using the links below:
Close