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

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

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

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

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

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

15 ответов


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

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

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

если выражение создания экземпляра класса завершается в теле класса, то экземпляр класса является анонимным классом. Затем:

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

выделено мной.

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

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

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

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


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

мой.java:

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

Поли.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.class  // Class file corresponding to anonymous subclass
Poly.class

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

new My() {};

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

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

Poly.class, Poly.class, Poly.class, ... so on

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


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

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


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


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

  1. почему poly выходит my? Это бесполезно...
  2. каков результат компиляции? Три файла:my.class, poly.class и poly.class
  3. если мы можем создать экземпляр абстрактного класса, как это, мы можем создать экземпляр интерфейса тоже... странный...


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

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


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

абстрактный класс не инстанцируется,нас но java.

EDIT: попросите его проверить это

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
class my

вы можете просто ответы, всего в одной строке

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

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

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

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

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


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

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

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


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

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

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

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

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


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

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

из JLS, Глава 8. Классы:

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

из JSE 6 Java doc для Занятия.newInstance ():

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

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

Другой Угол Зрения На Это-Teamplay & Social Intelligence:

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

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

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


это хорошо установленный факт, что abstract class can не быть инстанцированным, как все ответили.

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

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

мой.класс!--9-->

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

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

class poly extends my 
{
} 

ploly.Кэсс

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();
    }
}

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


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

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

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


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


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

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

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

  1. создать пустой класс
  2. наследовать от абстрактного класса
  3. создать экземпляр класса dervied

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


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

   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;
    }
}

затем, наконец, фабрика выглядит примерно так:

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 вызовет методы на него и получит логику, реализованную в конкретном спуске (и частично в абстрактном class methods), не зная, что такое конкретная реализация, которую он получил. Это также известно как инверсия управления и внедрение зависимостей.


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

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

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. Здесь мы создали ссылочную переменную типа Figure и Figure Ссылочная переменная класса используется для ссылки на объекты класса Rectangle и Triangle.