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

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

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

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

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 - Section # 15.9.1: -

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

  • Если T обозначает класс, объявляется анонимный прямой подкласс класса с именем T. Это ошибка времени компиляции, если класс, обозначаемый T, является конечным классом.
  • Если T обозначает интерфейс, то объявляется анонимный прямой подкласс Object, реализующий интерфейс с именем T.
  • В любом случае, тело подкласса - это ClassBody, указанное в выражении создания экземпляра класса.
  • Создаваемый класс является анонимным подклассом.

Акцент на мой.

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

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

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

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


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

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

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

  • Почему poly extends my? Это бесполезно...
  • Каков результат компиляции? Три файла: my.class, poly.class и poly$1.class
  • Если мы можем создать такой абстрактный класс, мы можем создать интерфейс тоже... странно...


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

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


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

Абстрактный суперкласс не создается нами, а 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

Ответ 5

Вы можете просто ответить только в одной строке

Нет, вы никогда не сможете использовать экземпляр Abstract Class

Но, интервьюер все еще не согласен, тогда вы можете сказать ему/ей

все, что вы можете сделать, это создать анонимный класс.

И, согласно анонимному классу, класс объявлен и создается экземпляр в том же месте/строке

Таким образом, возможно, что интервьюер будет заинтересован проверить ваш уровень доверия и насколько вы знаете о ООП.

Ответ 6

Техническая часть была хорошо освещена в других ответах, и в основном она заканчивается:
  "Он ошибается, он не знает, попросите его присоединиться к этому, и все это очистится:)"

Я хотел бы затронуть тот факт (который упоминался в других ответах), что это может быть стресс-вопрос и является важным инструментом для многих интервьюеров узнать больше о вас и как вы реагируете на сложные и необычные ситуации. Предоставляя вам неправильные коды, он, вероятно, хотел посмотреть, не возражаете ли вы. Чтобы узнать, есть ли у вас уверенность противостоять старшим в ситуациях, подобных этому.

P.S: Я не знаю, почему, но у меня есть ощущение, что интервьюер прочитал этот пост.

Ответ 7

Абстрактные классы не могут быть созданы, но они могут быть подклассами. См. эту ссылку

Лучшим примером является

Хотя класс Calender имеет абстрактный метод getInstance(), но когда вы говорите Calendar calc=Calendar.getInstance();

calc ссылается на экземпляр класса класса GregorianCalendar, поскольку "GregorianCalendar расширяет календарь"

Infact анонимный внутренний тип позволяет создать подкласмент без имени абстрактного класса и экземпляр этого.

Ответ 8

Технический ответ

Абстрактные классы не могут быть созданы - это по определению и дизайну.

Из JLS, глава 8. Классы:

Именованный класс может быть объявлен абстрактным (§8.1.1.1) и должен быть объявлен аннотация, если она не полностью выполнена; такой класс не может быть экземпляр, но может быть расширен подклассами.

Из JSE 6 java doc для Classes.newInstance():

InstantationException - если этот класс представляет абстрактный класс, интерфейс, массив класс, примитивный тип или пустота; или если класс не имеет нулевого конструктора; или если создание экземпляра происходит по другой причине.

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

Разный угол на этом - Teamplay и социальный интеллект:

Такое техническое недоразумение часто происходит в реальном мире, когда мы имеем дело со сложными технологиями и законными спецификациями.

"Навыки людей" могут быть более важными, чем "Технические навыки". Если вы конкурентно и агрессивно пытаетесь доказать свою сторону аргумента, то вы можете быть теоретически правы, но вы также можете нанести дополнительный урон в битве/повреждении "лица" /создании врага, чем это стоит. Будьте примирительны и понимаете в разрешении своих разногласий. Кто знает - может быть, вы "оба правы", но отработали немного разные значения для терминов?

Кто знает - хотя вряд ли, возможно, интервьюер сознательно ввел небольшой конфликт/непонимание, чтобы поставить вас в сложную ситуацию и посмотреть, как вы себя ведете себя эмоционально и социально. Будьте любезны и конструктивны с коллегами, следуйте советам старших и следуйте после интервью, чтобы решить любую проблему/непонимание - по электронной почте или по телефону. Показывает, что вы мотивированы и детализированы.

Ответ 9

Хорошо известно, что abstract class может не быть экземпляром, как все отвечали.

Когда программа определяет анонимный класс, компилятор фактически создает новый класс с другим именем (имеет шаблон EnclosedClassName$n, где n - номер анонимного класса)

Итак, если вы декомпилируете этот класс Java, вы найдете код, как показано ниже:

my.class

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

poly $1.class(сгенерированный класс "анонимного класса" )

class poly$1 extends my 
{
} 

ploly.cass

public class poly extends my
{
    public static void main(String[] a)
    {
        my m = new poly.1(); // instance of poly.1 class NOT the abstract my class

        m.mymethod();
    }
}

Ответ 10

Об абстрактных классах

  • Невозможно создать объект абстрактного класса
  • Может создавать переменные (может вести себя как типы данных)
  • Если ребенок не может переопределить хотя бы один абстрактный метод родителя, тогда ребенок также становится абстрактным
  • Абстрактные классы бесполезны без дочерних классов

Цель абстрактного класса - вести себя как база. В иерархии наследования вы увидите абстрактные классы по направлению вверх.

Ответ 11

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

Ответ 12

Расширение класса не означает, что вы создаете экземпляр класса. На самом деле, в вашем случае вы создаете экземпляр подкласса.

Я уверен, что абстрактные классы не позволяют инициировать. Итак, я бы сказал нет: вы не можете создать абстрактный класс. Но вы можете расширить его/наследовать.

Вы не можете напрямую создать абстрактный класс. Но это не означает, что вы не можете косвенно получить экземпляр класса (а не actully экземпляр исходного абстрактного класса). Я имею в виду, что вы не можете создать экземпляр абстрактного класса orginial, но вы можете:

  • Создать пустой класс
  • Наследовать его из абстрактного класса
  • Выполнить действие класса dervied

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

Ответ 13

Вы можете сказать:
мы не можем создать экземпляр абстрактного класса, но мы можем использовать ключевое слово new для создания экземпляра анонимного класса, просто добавив {} в качестве тела реализации в конце абстрактного класса.

Ответ 14

Невозможно создать экземпляр абстрактного класса. То, что вы действительно можете сделать, реализовало некоторые распространенные методы в абстрактном классе и позволило другим реализовать (абстрактно) их абстрактное представление и позволить конкретному descender реализовать их в зависимости от их потребностей. Затем вы можете сделать factory, который возвращает экземпляр этого абстрактного класса (на самом деле его исполнитель). В factory вы затем решаете, какой разработчик выбрать. Это называется шаблоном проектирования factory:

   public abstract class AbstractGridManager {
        private LifecicleAlgorithmIntrface lifecicleAlgorithm;
        // ... more private fields

        //Method implemented in concrete Manager implementors 
        abstract public Grid initGrid();

        //Methods common to all implementors
        public Grid calculateNextLifecicle(Grid grid){
            return this.getLifecicleAlgorithm().calculateNextLifecicle(grid);
        }

        public LifecicleAlgorithmIntrface getLifecicleAlgorithm() {
            return lifecicleAlgorithm;
        }
        public void setLifecicleAlgorithm(LifecicleAlgorithmIntrface lifecicleAlgorithm) {
            this.lifecicleAlgorithm = lifecicleAlgorithm;
        }
        // ... more common logic and getters-setters pairs
    }

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

public class FileInputGridManager extends AbstractGridManager {

private String filePath;

//Method implemented in concrete Manager implementors 
abstract public Grid initGrid();

public class FileInputGridManager extends AbstractGridManager {

    private String filePath;

    //Method implemented in concrete Manager implementors 
    abstract public Grid initGrid();

    public Grid initGrid(String filePath) {
        List<Cell> cells = new ArrayList<>();
        char[] chars;
        File file = new File(filePath); // for example foo.txt
        // ... more logic
        return grid;
    }
}

Затем, наконец, factory выглядит примерно так:

public class GridManagerFactory {
    public static AbstractGridManager getGridManager(LifecicleAlgorithmIntrface lifecicleAlgorithm, String... args){
        AbstractGridManager manager = null;

        // input from the command line
        if(args.length == 2){
            CommandLineGridManager clManager = new CommandLineGridManager();
            clManager.setWidth(Integer.parseInt(args[0]));
            clManager.setHeight(Integer.parseInt(args[1]));
            // possibly more configuration logic
            ...
            manager = clManager;
        } 
        // input from the file
        else if(args.length == 1){
            FileInputGridManager fiManager = new FileInputGridManager();
            fiManager.setFilePath(args[0]);
            // possibly more method calls from abstract class
            ...
            manager = fiManager ;
        }
        //... more possible concrete implementors
        else{
            manager = new CommandLineGridManager();
        }
        manager.setLifecicleAlgorithm(lifecicleAlgorithm);
        return manager;
    }
}

Приемник AbstractGridManager будет вызывать методы на нем и получать логику, реализованную в конкретном descender (и частично в абстрактных методах класса), не зная, какова конкретная реализация, которую он получил. Это также известно как инверсия контроля или инъекции зависимостей.

Ответ 15

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

Вот пример, иллюстрирующий это понятие

abstract class Figure { 

    double dim1; 

    double dim2; 

    Figure(double a, double b) { 

        dim1 = a; 

        dim2 = b; 

    } 

    // area is now an abstract method 

    abstract double area(); 

    }


    class Rectangle extends Figure { 
        Rectangle(double a, double b) { 
        super(a, b); 
    } 
    // override area for rectangle 
    double area() { 
        System.out.println("Inside Area for Rectangle."); 
        return dim1 * dim2; 
    } 
}

class Triangle extends Figure { 
    Triangle(double a, double b) { 
        super(a, b); 
    } 
    // override area for right triangle 
    double area() { 
        System.out.println("Inside Area for Triangle."); 
        return dim1 * dim2 / 2; 
    } 
}

class AbstractAreas { 
    public static void main(String args[]) { 
        // Figure f = new Figure(10, 10); // illegal now 
        Rectangle r = new Rectangle(9, 5); 
        Triangle t = new Triangle(10, 8); 
        Figure figref; // this is OK, no object is created 
        figref = r; 
        System.out.println("Area is " + figref.area()); 
        figref = t; 
        System.out.println("Area is " + figref.area()); 
    } 
}

Здесь мы видим, что мы не можем создать объект типа Figure, но мы можем создать ссылочную переменную типа Figure. Здесь мы создали ссылочную переменную типа Reference и ссылочной переменной класса Class, которая ссылается на объекты класса Rectangle и Triangle.