Можно ли создать экземпляр анонимного класса в конструкторе внешнего класса?
У меня есть следующий код:
public class Outer {
public Interface Anony {
public void callback();
}
public Outer() {
OtherClass.foo(new Anony() {
@Override
public void callback() {
....
}
});
}
}
Но мой друг сказал мне, что в нем есть какая-то проблема. Я создал экземпляр анонимного класса в конструкторе Outer, поэтому экземпляр анонимного класса неявно ссылается на экземпляр класса Outer, т.е. Outer.this. Но в данный момент экземпляр Outer еще не был полностью создан. Таким образом, экземпляр анонимного класса ссылается на объект с неполными состояниями, поэтому проблема.
Он прав? Спасибо.
Ответы
Ответ 1
Вы, друг, прав, но это зависит от использования курса.
Проблема заключается не в создании внутреннего класса внутри конструктора. Проблема будет возникать, если внутренний класс обращается к внешнему классу.
Это связано с тем, что любой объект не сможет предоставить обычных грантополучателей внутри конструктора. Все переменные, необходимые для операций с объектами, возможно, не были инициализированы и т.д.
Однако, если внутренний класс помещен в конец конструктора, я не вижу, чтобы эта проблема возникала, но имейте в виду, что это опасный гамбит, потому что кто-то может изменить код, а затем это время с отладчиком..
Ответ 2
Вы можете это сделать, но не должны.
Это пример анти-шаблона, известный по-разному, как "разрешение this
справиться с конструктором" - передача ссылки на объект, который создается другим классом изнутри конструктора. Причина, по которой вы не должны этого делать, заключается в том, что в многопоточной среде класс, которому была передана эта ссылка, может видеть новый объект в частично построенном и, следовательно, несогласованном состоянии. Это может привести к странным и труднодоступным ошибкам. Эта статья статьи от IBM является одним из многих ее описаний.
Что неясно, как это происходит здесь: Анонимные классы - это, фактически, внутренние классы, поэтому они содержат ссылку на содержащий класс (т.е. this
). Класс-получатель OtherClass
может видеть и даже действовать, this
до завершения построения.
Ответ 3
Я построил мозговой пример.. всех возможных возможностей, о которых я мог думать:
class OtherClass
{
public static void foo (final Anony x)
{
x.callback ();
}
}
public class Outer
{
public interface Anony
{
void callback ();
}
public class Inner implements Anony
{
public void callback ()
{
System.out.println ("Inner.callback");
}
}
public class InnerDerived implements Anony
{
public void callback ()
{
System.out.println ("InnerDerived.callback");
}
}
public static class StaticInner implements Anony
{
public void callback ()
{
System.out.println ("StaticInner.callback");
}
}
public Outer ()
{
OtherClass.foo (new Anony ()
{
public void callback ()
{
System.out.println ("Anony.callback");
}
});
OtherClass.foo (new Inner ());
OtherClass.foo (new Inner ()
{
@Override
public void callback ()
{
System.out.println ("Anony.Inner.callback");
}
});
OtherClass.foo (new InnerDerived ());
OtherClass.foo (new InnerDerived ()
{
@Override
public void callback ()
{
System.out.println ("Anony.InnerDerived.callback");
}
});
OtherClass.foo (new StaticInner ());
OtherClass.foo (new StaticInner ()
{
@Override
public void callback ()
{
System.out.println ("Anony.StaticInner.callback");
}
});
}
}
Ожидаемый результат должен быть:
Anony.callback
Inner.callback
Anony.Inner.callback
InnerDerived.callback
Anony.InnerDerived.callback
StaticInner.callback
Anony.StaticInner.callback