Effects of Java’s Synthetic Accessor Methods in Android

Image Credit: MemeMaker

Does the following Java code compile?

// Outer.java 
public class Outer {
private static void doSomething() {
}

private class Nested {
private void execute() {
Outer.doSomething();
}
}
}

Yes. Of course. Java does support nested class and the nested class can access the private members of the outer class. But, does Java has true nesting classes? Let’s explore more.

$ javac Outer.java
$ ls 
Outer$Nested.class
Outer.class
Outer.java

The compiler compiles the Outer.java class into two separate classes: Outer.class and Outer$Nested.class. So that is not true class nesting.

Now the obvious question arises, “If Java does not support true nesting then how one class can access the private member of another class?”. The all mighty Java solves this problem under the hood by creating a synthetic access method.

Let’s look into the Outer class,

$ javap -p -c Outer 
public class Outer { 
public Outer();
Code: <removed>
    private static void doSomething(); 
Code: <removed>
    static void access$000(); 
Code:
0: invokestatic #1 // Method doSomething:
3: return
}

Look closely in the above snippet. The compiler has created a package-scoped static method named “access$…” on behalf of us. That method just forwards the method invocation to the actual private method. That’s one waste and literally unused method created for us.

Anonymous class is also a nested class, but with no name. So it is very likely that these synthetic methods are created when we use the click listeners in our app.

Let’s say, we access a few private fields inside the click listener,

private String a; 
private String b;
private String c;
button.setOnClickListener(new OnClickListener() { 
@Override
public void onClick(View view) {
// click action
a = “a”;
b = “b”
c = “c”;
}
}

Now three unwanted synthetic methods are created.

Even if the same private field is accessed from the nested class as ‘x’ different actions, ‘x’ synthetic methods are created.

private int count = 0; 
button.setOnClickListener(new OnClickListener() { 
@Override
public void onClick(View view) {
// click action
count++;
count — ;
++count;
— count;
}
}

This code block creates four synthetic methods.

Drawbacks of Synthetic methods in Android:

A few bunch of extra methods might seem trivial. But it quickly adds up to a few thousands of unwanted methods as we have these nested/ anonymous classes everywhere in our code, and in other libraries we use.

1.Dex method reference limit
We all know that every Android app has 65,536 methods limit (without multidex). So it is not wise to waste few thousand methods as unwanted synthetic methods.

2.Performance: 
Direct field access is about 7 times faster than invoking a getter method . Unknowingly we might be using these synthetic methods to access the fields where the direct filed access would have been much faster.

How to fix: 
Hunt all the private members that are accessed from nested class and edit to package scope. ​​:P

There is an Intellij inspection that shows a warning for this private member access. To enable it in Android Studio, go to: Preferences > Editor > Inspections > Java > J2ME issues > Private member access between outer and inner classes

Do not ignore the warning. Fixing this as and when it’s encountered is a better approach than editing the entire application.

Reference: 
https://www.youtube.com/watch?v=WALV33rWye4