12

I have the following static factory method that creates a list view out of an int array:

public static List<Integer> newInstance(final int[] numbers) {
    return new AbstractList<Integer>() {

        @Override
        public Integer get(int index) {
            return numbers[index];
        }

        @Override
        public int size() {
            return numbers.length;
        }
    };
}


public static void main(String[] args) {
    int[] sequence = {10, 20, 30};
    List<Integer> list = ListFactory.newInstance(sequence);
    System.out.println("List is "+list);

}

In "Effective Java", Joshua Bloch mentioned this

as an Adapter that allows an int array to be viewed as a list of Integer instances.

However, I remember that Adapter uses composition and the instance of the anonymous list implementation should use the int[] as a member field.

Where exactly is the int[] input parameter stored if it's not a member field of the anonymous list implementation?

I would appreciate if anyone could provide some insights or some links to look for more information.

Kewei Shang
  • 949
  • 3
  • 11
  • 27

3 Answers3

7

You can use javac -d . -XD-printflat ListFactory.java to see how the compiler understands the inner class. Actually, there are two Java classes in your example. The ListFactory (note how numbers are passed to the constructor of ListFactory$1):

public class ListFactory {

    public ListFactory() {
        super();
    }

    public static List newInstance(final int[] numbers) {
        return new ListFactory$1(numbers);
    }
}

and the representation of the anonymous implementation of AbstractList:

class ListFactory$1 extends AbstractList {
    /*synthetic*/ final int[] val$numbers;

    ListFactory$1(/*synthetic*/ final int[] val$numbers) {
        this.val$numbers = val$numbers;
        super();
    }

    @Override()
    public Integer get(int index) {
        return Integer.valueOf(val$numbers[index]);
    }

    @Override()
    public int size() {
        return val$numbers.length;
    }

    @Override()
    /*synthetic*/ public Object get(/*synthetic*/ int index) {
        return this.get(index);
    }
}

The methods and fields marked as synthetic are generated by the compiler and not accessible to you as a programmer, but are used during runtime to access the int array. And indeed there is a val$numbers field that holds a final reference to the int array.

By the way you can also notice boxing from int to Integer in Integer get(int index) and that to comply with the raw (non-generic) List interface an extra Object get(int index) method is generated that delegates to the type-safe Integer get(int index) implementation.

Adam Michalik
  • 9,678
  • 13
  • 71
  • 102
3

It is stored inside AbstractList's anonymous class as synthetic field. You can view it using javap utility:

final class q34290420.Test$1 extends java.util.AbstractList<java.lang.Integer> {
  final int[] val$numbers;   // here
  q34290420.Test$1(int[]);
  public java.lang.Integer get(int);
  public int size();
  public java.lang.Object get(int);
}

Furthermore you can discover it via reflection:

    Field[] fields = list.getClass().getDeclaredFields();
    System.out.println(fields[0].getName());
    System.out.println(fields[0].isSynthetic());

Output:

val$numbers
true
Andremoniy
  • 34,031
  • 20
  • 135
  • 241
  • 1
    `fields[0]` won't always work, though. From the [javadoc of the `Class#getDeclaredFields()-method`](http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getDeclaredFields()): "_The elements in the array returned are not sorted and are not in any particular order._" +1 nonetheless, since you've answered OP's question. – Kevin Cruijssen Dec 15 '15 at 14:16
  • @KevinCruijssen Thanks for your vote & comment. This is just an example for this particular case where there is not explicitly declared fields. – Andremoniy Dec 15 '15 at 14:21
  • @Andremoniy Thank you for mentioning the reflection and the concept of synthetic field. – Kewei Shang Dec 16 '15 at 00:01
2

This is related to the question: Why are only final variables accessible in anonymous class?

Jon Skeet already provide succinct answer for the question above :

When you create an instance of an anonymous inner class, any variables which are used within that class have their values copied in via the autogenerated constructor. This avoids the compiler having to autogenerate various extra types to hold the logical state of the "local variables".

So in this case, the int[] numbers are automatically being copied to the anonymous class that extends from AbstractList as a synthetic field.

Community
  • 1
  • 1
Ibrahim Arief
  • 8,742
  • 6
  • 34
  • 54
  • Thanks for the link to Jon Skeet's answer, which is quite related to my question and helped my understanding of the subject. – Kewei Shang Dec 16 '15 at 00:03