2015-12-15 6 views
13

У меня есть следующий статический фабричный метод, который создает представление списка из-за целочисленный массив:Где конечный параметр хранится в экземпляре анонимного класса?

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.

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

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

Буду признателен, если кто-нибудь может предоставить некоторые идеи или некоторые ссылки, чтобы найти дополнительную информацию.

ответ

7

Вы можете использовать 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) реализации.

+0

Спасибо, что упомянул javac -d. -XD-printflat, что более чем полезно в этом случае! –

3

Он хранится внутри анонимного класса 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 
+1

'fields [0]' не всегда будут работать. Из [javadoc «Class # getDeclaredFields() -method'] (http://docs.oracle.com/javase/7/docs/api/java/lang/Class.html#getDeclaredFields()):« _The элементы в возвращенном массиве не сортируются и не находятся в каком-либо конкретном порядке. »+1« тем не менее, так как вы ответили на вопрос OP. –

+0

@KevinCruijssen Спасибо за ваш голос и комментарий. Это просто пример для конкретного случая, когда явно не объявлены поля. – Andremoniy

+0

@Andremoniy Благодарим вас за упоминание отражения и концепции синтетического поля. –

2

Это связано с вопросом: Why are only final variables accessible in anonymous class?

Jon Skeet уже предоставляют succinct answer по вышеуказанному вопросу:

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

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

+0

Спасибо за ссылку на ответ Джона Скита, который очень связан с моим вопросом и помог мне понять тему. –