пъзелче
11 отговора
405 прегледа
пъзелче
Даден е следният клас, който вътре в себе си включва свой анонимен наследник. Въпросът е какъв ще бъде изхода от програмата и защо.
public class Twisted {
private final String name;
public Twisted(String name) {
this.name=name;
}
private void printName() {
System.out.println(name);
}
/** ей тука е интересното */
public void doit() {
new Twisted("doit") {
public void f() {
printName();
}
}.f();
}
public static void main(String []ar) {
new Twisted("base").doit();
}
}
при изпълнение на програмата се отпечатва base. Според мен това е защото когато се линква анонимният вътрешен клас неговият printName не е достъпен, f() се връзва към външния printName(). Това обяснение нещо ми се струва криво обаче, вие какво мислите?
public class Twisted {
private final String name;
public Twisted(String name) {
this.name=name;
}
private void printName() {
System.out.println(name);
}
/** ей тука е интересното */
public void doit() {
new Twisted("doit") {
public void f() {
printName();
}
}.f();
}
public static void main(String []ar) {
new Twisted("base").doit();
}
}
при изпълнение на програмата се отпечатва base. Според мен това е защото когато се линква анонимният вътрешен клас неговият printName не е достъпен, f() се връзва към външния printName(). Това обяснение нещо ми се струва криво обаче, вие какво мислите?
Re: пъзелче
Това няма да отпечата "base". Недей литкай хората 
All warfare is based on deception.
Sun Tzu [1:18]
All warfare is based on deception.
Sun Tzu [1:18]
Re: пъзелче
Abe otpechatva si 'base'. Tui kato methoda printName e private , naslednicite mu niamat vidimost kum nego. No inner classovete imat dostup do private methodite na enclose-vashtite gi clasove. Zatova se otpechatva i 'base'.
Po interesnia vupros e kakvo da se napravi za da se otechata 'doIt'.
/** ей тука е интересното */
public void doit()
{
new Twisted("doit")
{
public void f()
{
super.printName();
}
}.f();
}
Niakoi ako iska moje da napishe obiasnenie.
Po interesnia vupros e kakvo da se napravi za da se otechata 'doIt'.
/** ей тука е интересното */
public void doit()
{
new Twisted("doit")
{
public void f()
{
super.printName();
}
}.f();
}
Niakoi ako iska moje da napishe obiasnenie.
Re: пъзелче
Колеги, не ме правете на луд с тоя "base", щото ще ме карате да го copy/paste-на и да го пробвам 
All warfare is based on deception.
Sun Tzu [1:18]
All warfare is based on deception.
Sun Tzu [1:18]
Re: пъзелче
айде де, копи-пействай го! Аз го написах от спомен как изглежда ама сега го пробвах и компилира и тръгва и пише base!
и на тоше солюшъна си пише doit!

и на тоше солюшъна си пише doit!
Re: пъзелче
Ей сега го копирах и компилирах. Ами doit си пише! 
All warfare is based on deception.
Sun Tzu [1:18]
All warfare is based on deception.
Sun Tzu [1:18]
Re: пъзелче
uff, ne che shte mi poviarvash ako ti peistna outputa ama aide:
====================
[zab@localhost zab]$ cat Twisted.java
public class Twisted {
private final String name;
public Twisted(String name) {
this.name=name;
}
private void printName() {
System.out.println(name);
}
/** .. .... . ........... */
public void doit() {
new Twisted("doit") {
public void f() {
printName();
}
}.f();
}
public static void main(String []ar) {
new Twisted("base").doit();
}
}
[zab@localhost zab]$ javac Twisted.java
[zab@localhost zab]$ java Twisted
base
[zab@localhost zab]$
==================
ama aide niakoi independent da potvyrdi
====================
[zab@localhost zab]$ cat Twisted.java
public class Twisted {
private final String name;
public Twisted(String name) {
this.name=name;
}
private void printName() {
System.out.println(name);
}
/** .. .... . ........... */
public void doit() {
new Twisted("doit") {
public void f() {
printName();
}
}.f();
}
public static void main(String []ar) {
new Twisted("base").doit();
}
}
[zab@localhost zab]$ javac Twisted.java
[zab@localhost zab]$ java Twisted
base
[zab@localhost zab]$
==================
ama aide niakoi independent da potvyrdi
Re: пъзелче
Разбира се, че ти вярвам. Не сме малки деца да се лъжем, но примерчето го тествах с 1.3.1 и 1.4.1_02 под XP. Сега като се прибера в къщи, ще пробвам под Debian да видя, но направо ми се изправя косата, щото ако има разлика... 
All warfare is based on deception.
Sun Tzu [1:18]
All warfare is based on deception.
Sun Tzu [1:18]
Re: пъзелче
Naj-dobre e da se pogledne Java Language Specification ili pyk source-a na samia kompilator.
Sigurno smiatat meteda ot vynshnia class za chast ot konteksta na anonymous class-a, zatova i vinagi go namirat pyrvi. Tochno kakto kogato override-vash metod na base class-a - metoda ot novia class vinagi e po podrazbirane, a tozi ot base class-a se vika sys super.printName()
Taka se poluchava Twisted.this.printName() i se optpechatva "base". (Twisted.this.name = "base")
Ponezhe anonymous class-a ima dostyp do tozi metod kogato se opitash da go izvikash prez super (vypreki che e private) rezultatnia call e Twisted$1.this.printName() i tyj kato Twisted$1.this.name = "doit" rezultata e tova koeto ochakvash ot pyrvata programa
Vyprosa kojto triabva da si zadadesh e dali design-a ti e pravilen shtom se nalaga da pravish podobni hack-ove...
Sigurno smiatat meteda ot vynshnia class za chast ot konteksta na anonymous class-a, zatova i vinagi go namirat pyrvi. Tochno kakto kogato override-vash metod na base class-a - metoda ot novia class vinagi e po podrazbirane, a tozi ot base class-a se vika sys super.printName()
Taka se poluchava Twisted.this.printName() i se optpechatva "base". (Twisted.this.name = "base")
Ponezhe anonymous class-a ima dostyp do tozi metod kogato se opitash da go izvikash prez super (vypreki che e private) rezultatnia call e Twisted$1.this.printName() i tyj kato Twisted$1.this.name = "doit" rezultata e tova koeto ochakvash ot pyrvata programa
Vyprosa kojto triabva da si zadadesh e dali design-a ti e pravilen shtom se nalaga da pravish podobni hack-ove...
Re: пъзелче
това силно се съмнявам някой да го употреби в реален дизайн.. освен като параван за този който ти прави code review за да прикриеш някой backdoor друга употреба не виждам.
Re: пъзелче
ууу ... грубичко ...
ето едно обяснение:
Декомпилирам функцията f() до bytecode инструкции (прави се с jad -asm):
public void f()
{
// 0 0:aload_0
// 1 1:getfield #2 <Field Twisted this$0>
// 2 4:invokestatic #3 <Method void Twisted.access$000(Twisted)>
// 3 7:return
}
методът access$000(Twisted t) е изкуствено генериран от компилатора с цел да могат да се викне private метода printName от вътрешен клас (такъв метод се създава за ВСЕКИ викнат от вътрешен клас private метод).
Полето this$0 е също изкуствено генерирано и играе ролята на proxy от вътрешния към външния клас. Ако се вземе през reflection се вижда че стойността му е точно this на "base" (наричам го така условно). Ако са искали да вземат this на "doit" щяха да ползват инструкцията aload_0.
Използвал съм JDK 1.4.2_03 за компилатор и jad 1.5.8e2 за декомпилатор.
Според мен в случая има бъг в компилатора - забравили са частния случай когато вътрешния клас е наследник на външния. Нищо чудно че не винаги се държи така.
Изводите (поне за мен) са два:
1. Да се избягва викането на private методи на външен клас от вътрешни класове - товари се външния клас с изкуствени методи.
2. Да се дава подобна задача е глупост от класа. Не знам кой идиот я е дал, но аз лично не бих желал той после да ми е шеф ...
ето едно обяснение:
Декомпилирам функцията f() до bytecode инструкции (прави се с jad -asm):
public void f()
{
// 0 0:aload_0
// 1 1:getfield #2 <Field Twisted this$0>
// 2 4:invokestatic #3 <Method void Twisted.access$000(Twisted)>
// 3 7:return
}
методът access$000(Twisted t) е изкуствено генериран от компилатора с цел да могат да се викне private метода printName от вътрешен клас (такъв метод се създава за ВСЕКИ викнат от вътрешен клас private метод).
Полето this$0 е също изкуствено генерирано и играе ролята на proxy от вътрешния към външния клас. Ако се вземе през reflection се вижда че стойността му е точно this на "base" (наричам го така условно). Ако са искали да вземат this на "doit" щяха да ползват инструкцията aload_0.
Използвал съм JDK 1.4.2_03 за компилатор и jad 1.5.8e2 за декомпилатор.
Според мен в случая има бъг в компилатора - забравили са частния случай когато вътрешния клас е наследник на външния. Нищо чудно че не винаги се държи така.
Изводите (поне за мен) са два:
1. Да се избягва викането на private методи на външен клас от вътрешни класове - товари се външния клас с изкуствени методи.
2. Да се дава подобна задача е глупост от класа. Не знам кой идиот я е дал, но аз лично не бих желал той после да ми е шеф ...