Подтвердить что ты не робот

Где конечный параметр хранится в экземпляре анонимного класса?

У меня есть следующий статический метод factory, который создает представление списка из массива int:

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);

}

В "Эффективной Java" Джошуа Блох упомянул об этом

в качестве адаптера, который позволяет рассматривать массив int как список экземпляров Integer.

Однако я помню, что Adapter использует композицию, и экземпляр реализации анонимного списка должен использовать int [] как поле участника.

Где именно хранится входной параметр int [], если он не является полем члена реализации анонимного списка?

Я был бы признателен, если бы кто-нибудь мог предоставить некоторые идеи или некоторые ссылки для поиска дополнительной информации.

4b9b3361

Ответ 1

Вы можете использовать javac -d . -XD-printflat ListFactory.java, чтобы узнать, как компилятор понимает внутренний класс. На самом деле в вашем примере есть два класса Java. ListFactory (обратите внимание, как numbers передается конструктору ListFactory$1):

public class ListFactory {

    public ListFactory() {
        super();
    }

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

и представление анонимной реализации 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);
    }
}

Методы и поля, помеченные как синтетические, генерируются компилятором и недоступны для вас как программист, но используются во время выполнения для доступа к массиву int. И действительно есть поле val$numbers, которое содержит окончательную ссылку на массив int.

Кстати, вы также можете заметить, что бокс от int до Integer в Integer get(int index) и что для соответствия с необработанным (не общим) интерфейсом List создается дополнительный Object get(int index) метод, который делегирует реализация типа Integer get(int index).

Ответ 2

Он хранится внутри анонимного класса AbstractList как синтетическое поле. Вы можете просмотреть его с помощью утилиты javap:

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);
}

Кроме того, вы можете обнаружить это через отражение:

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

Вывод:

val$numbers
true

Ответ 3

Это связано с вопросом: Почему только конечные переменные доступны в анонимном классе?

Джон Скит уже предоставляет краткий ответ для вопроса выше:

Когда вы создаете экземпляр анонимного внутреннего класса, любые переменные, которые используются в этом классе, имеют свои значения, скопированные с помощью автогенерированного конструктора. Это позволяет избежать компилятора, чтобы автогенерировать различные дополнительные типы для хранения логического состояния "локальных переменных".

Итак, в этом случае номера int [] автоматически копируются в анонимный класс, который простирается от AbstractList как синтетическое поле.