Вопрос-ответ

Can we instantiate an abstract class?

Можем ли мы создать экземпляр абстрактного класса?

Во время одного из моих интервью меня спросили: "Можем ли мы создать экземпляр абстрактного класса?"

Мой ответ был "Нет. мы не можем". Но интервьюер сказал мне: "Неправильно, мы можем".

Я немного поспорил по этому поводу. Затем он сказал мне попробовать это самому дома.

abstract class my {
public void mymethod() {
System.out.print("Abstract");
}
}

class poly {
public static void main(String a[]) {
my m = new my() {};
m.mymethod();
}
}

Здесь я создаю экземпляр своего класса и вызываю метод абстрактного класса. Кто-нибудь, пожалуйста, может мне это объяснить? Я действительно был неправ во время собеседования?

Переведено автоматически
Ответ 1

Здесь я создаю экземпляр своего класса


Нет, вы не создаете здесь экземпляр своего абстрактного класса. Скорее вы создаете экземпляр анонимного подкласса вашего абстрактного класса. И затем вы вызываете метод в своей ссылке на абстрактный класс, указывающий на объект подкласса.

Такое поведение четко описано в JLS - разделе # 15.9.1: -


Если выражение для создания экземпляра класса заканчивается телом класса, то создаваемый класс является анонимным классом. Тогда:



  • Если T обозначает класс, то объявляется анонимный прямой подкласс класса, названного через T . Это ошибка времени компиляции, если класс, обозначаемый через T, является конечным классом.

  • Если T обозначает интерфейс, то объявляется анонимный прямой подкласс Object, который реализует интерфейс, названный через T .

  • В любом случае телом подкласса является ClassBody, заданное в выражении создания экземпляра класса.

  • Создаваемый класс является анонимным подклассом.


Курсив мой.

Кроме того, в JLS - разделе # 12.5 вы можете прочитать о процессе создания объекта. Я процитирую одно утверждение из этого здесь: -


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


Непосредственно перед тем, как ссылка на вновь созданный объект будет возвращена в качестве результата, указанный конструктор обрабатывается для инициализации нового объекта с помощью следующей процедуры:


Вы можете прочитать о полной процедуре по ссылке, которую я предоставил.


Чтобы практически увидеть, что создаваемый класс является анонимным подклассом, вам просто нужно скомпилировать оба ваших класса. Предположим, вы поместили эти классы в два разных файла:

My.java:

abstract class My {
public void myMethod() {
System.out.print("Abstract");
}
}

Poly.java:

class Poly extends My {
public static void main(String a[]) {
My m = new My() {};
m.myMethod();
}
}

Теперь скомпилируйте оба ваших исходных файла:

javac My.java Poly.java

Теперь в каталоге, где вы скомпилировали исходный код, вы увидите следующие файлы классов:

My.class
Poly$1.class // Class file corresponding to anonymous subclass
Poly.class

Посмотрите на этот класс - Poly$1.class. Это файл класса, созданный компилятором, соответствующий анонимному подклассу, который вы создали, используя приведенный ниже код:

new My() {};

Итак, ясно, что создается экземпляр другого класса. Просто этому классу присваивается имя только после компиляции компилятором.

В общем, все анонимные подклассы в вашем классе будут названы таким образом:

Poly$1.class, Poly$2.class, Poly$3.class, ... so on

Эти числа обозначают порядок, в котором эти анонимные классы появляются во вложенном классе.

Ответ 2

В приведенном выше примере создается анонимный внутренний класс, который является подклассом my абстрактного класса. Строго говоря, это не эквивалентно созданию экземпляра самого абстрактного класса. OTOH, каждый экземпляр подкласса является экземпляром всех его суперклассов и интерфейсов, поэтому большинство абстрактных классов действительно создаются путем создания экземпляра одного из их конкретных подклассов.

Если интервьюер просто сказал "неправильно!" без объяснения причин и привел этот пример в качестве уникального контрпримера, я думаю, он не знает, о чем говорит.

Ответ 3

= my() {}; означает, что существует анонимная реализация, а не простое создание экземпляра объекта, которое должно было быть : = my(). Вы никогда не сможете создать экземпляр абстрактного класса.

Ответ 4

Просто наблюдения, которые вы могли бы сделать:


  1. Почему poly расширяется my? Это бесполезно...

  2. Каков результат компиляции? Три файла: my.class, poly.class и poly$1.class

  3. Если мы можем создать экземпляр такого абстрактного класса, мы можем создать экземпляр интерфейса тоже ... странно...


Можем ли мы создать экземпляр абстрактного класса?

Нет, мы не можем. Что мы можем сделать, это создать анонимный класс (это третий файл) и создать его экземпляр.


Как насчет создания экземпляра суперкласса?

Экземпляр абстрактного суперкласса создается не нами, а java.

РЕДАКТИРОВАТЬ: Попросите его протестировать это

public static final void main(final String[] args) {
final my m1 = new my() {
};
final my m2 = new my() {
};
System.out.println(m1 == m2);

System.out.println(m1.getClass().toString());
System.out.println(m2.getClass().toString());

}

вывод:

false
class my$1
class my$2
java oop class