Динамично инстанциране на вътрешен клас, вложен в абстрактен клас

Разбирам, че за да създадете вътрешен клас (т.е. нестатичен), имате нужда от екземпляр на обхващащия клас. Това прави нещата малко по-сложни, ако обхващащият клас е абстрактен (не питайте). Помислете за следното.

abstract class Outer {
   class Inner {}
}

Създаването на екземпляр Inner все още е много изпълнимо статично с, например, анонимен клас, като този.

Inner instance = new Outer() {}.new Inner();

Но тогава как да постигнем същото нещо динамично с Constructor.newInstance? (Забележете, че казах динамично; приемете, че не знаете името на външния клас.) Ще трябва да предадете екземпляр на обхващащия клас за първия аргумент, съгласно JLS 15.9.3 и ако има начин да създадете нещо в движение за да удовлетворя абстрактен параметър, не съм наясно с него (бонус точки за всякакви идеи там).

Накратко, накрая случайно минах през null, ето така.

Constructor<Inner> constructor = Inner.class.getDeclaredConstructor(Outer.class);
Object argument = null;
Inner instance = constructor.newInstance(argument);

Представете си изненадата ми, когато това проработи. Въпросът ми е защо това проработи? И това винаги ли ще работи?


person gdejohn    schedule 10.12.2010    source източник
comment
Не питай - Опитвам се да не питам...   -  person Bert F    schedule 10.12.2010
comment
@BertF Ха. Ако трябва да знаете, аз пиша метод, който се опитва да инстанцира даден клас на базата на най-доброто усилие и искам да се справя с всички възможни случаи. Един такъв възможен случай е вътрешен клас, вложен в абстрактен клас.   -  person gdejohn    schedule 10.12.2010
comment
Има пълен смисъл - благодаря!   -  person Bert F    schedule 10.12.2010


Отговори (1)


Работи, защото конструкторът просто задава полето Outer.this. Вероятно трябва да провери дали не е нула (така че се проваля бързо), но е по-бързо, ако не го направи.

Не бих разчитал, че винаги работи, има всяка възможност различните JVM, дори различните актуализации да работят по различен начин.

въз основа на предишния ви пример, това трябва да работи.

Inner instance = constructor.newInstance(new Outer(){});
person Peter Lawrey    schedule 10.12.2010
comment
И така, ако беше извикан метод в Inner, който се опита да дереферира Outer.this, това ще доведе ли до NullPointerException или какво? - person gdejohn; 10.12.2010
comment

Това, което кара текущата ви обвивка да стартира bash е, че текущата ви обвивка (bash?) няма представа какво да прави с file.js. Ето защо боговете на unix изобретиха shebang за:

The character sequence consisting of the characters number sign and exclamation point (#!), when it occurs as the first two characters in the first line of a text file. In this case, the program loader in Unix-like operating systems parses the rest of the first line as an interpreter directive and invokes the program specified after the character sequence with any command line options specified as parameters.

Така че във вашия случай бих се опитал да сложа

 #!/usr/bin/env node

в горната част на скрипта. Можете да видите, че се прилага например в обвивката „inode“ (интерактивен node.js), което може да е друга опция за задействане на вашите скриптове.

https://github.com/bancek/node-interactive-shell/blob/master/inode.js

- person Peter Lawrey; 10.12.2010
comment
Добре. Ще тествам това, след като се наспя. Вероятно ще приема отговора ви утре, след като го разгледам. Благодаря. Що се отнася до предаването на new Outer( ) { }, това работи само ако знаете за Outer. Искам да мога да правя това при произволен Class обект от външния свят. - person gdejohn; 10.12.2010
comment
И така, разгледах и събрах някои полезни подробности. Не разбрах преди, че вътрешните класове завършват напълно отделени от техните обграждащи класове след компилация, като единствената връзка е поле за екземпляр, отнасящо се до обграждащия екземпляр, който трябва да бъде предаден на конструкторите на вътрешния клас. Сега, когато разбирам това, това има много повече смисъл. Благодаря отново за отговора. - person gdejohn; 11.12.2010
comment
BTW: Ако е възможно, по-добре е да направите вътрешни класове, вложен клас, като ги направите статични, това подобрява производителността и намалява ненужните зависимости между външния клас и класовете вътре в тях. - person Peter Lawrey; 11.12.2010
comment
Всъщност не мога да си представя, че някога искам да вмъкна нестатичен вътрешен клас в абстрактен клас. Това е само един възможен случай, с който искам да се справя за метод, който пиша, който взема даден Class обект (напр. Outer.Inner.class) и се опитва да инстанцира класа, който представлява. И за протокола, тъй като коментирах отговора ви, можете да ме маркирате с @, за да сте сигурни, че ще бъда уведомен за отговорите ви, но ако не го направите, нямам представа, че сте коментирали. - person gdejohn; 11.12.2010
comment
@Charlatan, не знаех, че го прави. Просто използвам символа на пощенската кутия до името си в горната част. Показва всички коментари и т.н., свързани с неща, които съм публикувал. - person Peter Lawrey; 11.12.2010
comment
Да, обикновено просто гледам горе вдясно, за да видя дали имам нови известия. - person gdejohn; 12.12.2010
comment
@Charlatan, това спря да работи за мен преди около месец, работи само иконата за имейл... - person Peter Lawrey; 12.12.2010