создать объект абстрактного класса != создать экземпляр абстрактного класса?

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

package MainPackage;

abstract class abstractClass {
    abstract abstractClass a_function();
}

public class Src {
    abstractClass m;
    public abstractClass abstractClassTest() {
        return m.a_function();
    }
    public static void main(String args[]) {
        System.out.println("Hello world!");
    }
}

Здесь я создаю абстрактный класс abstractClass и возвращаю его в функцию abstractClassTest(). И компилируется успешно без ошибок! IMO, прежде чем что-то возвращать, компьютер должен создать объект этого типа. И здесь он должен создать объект abstractClass перед return m.function(), что я не могу понять. я думаю, что мы не можем создать экземпляр абстрактного класса означает, что мы не можем создать объект абстрактного класса или мы не могу создать новый класс (например, abstractClass m = new abstractClass() is illegal). Но из кодов выше кажется, что мы можем создать объект абстрактного класса. как это реализовать? Что делает компьютер для кода abstractClass m, когда видит код? Мы не можем сказать, что Java создала экземпляр абстрактного класса m для кода abstractClass m? и если java не создает экземпляр класса abstractClass, как он может вернуть объект abstractClass в коде abstract abstractClass a_function();?


person Searene    schedule 27.01.2012    source источник
comment
Вы не создаете абстрактный класс, а просто используете его ссылку.   -  person Bhushan    schedule 27.01.2012
comment
Обратите внимание, что ваш код не создает экземпляр какого-либо объекта abstractclass. Если бы вам нужно было создать подкласс abstractclass, вы могли бы создать его экземпляр (abstractClass m = new childClass(...)) и тогда m.a_function будет действительным.   -  person Sam DeHaan    schedule 27.01.2012
comment
Как вы указываете, вы не можете создать новый абстрактный класс. В вашем коде нигде нет new — так в чем может быть проблема?   -  person yshavit    schedule 27.01.2012
comment
Бхушан и Сэм ДеХаан, поскольку вы отвечаете на вопрос, вы должны предоставить это как ответ, а не как комментарий.   -  person Spencer Kormos    schedule 27.01.2012


Ответы (3)


Да, он должен компилироваться без ошибок. Однако при выполнении он выдаст NullPointerException, если вы когда-либо вызывали abstractClassTest, потому что вы никогда не инициализируете переменную m для ссылки на реальный экземпляр. Для этого вам нужно создать конкретный класс, который является подклассом вашего абстрактного.

Например:

public class ConcreteClass extends AbstractClass {
    @Override AbstractClass a_function() {
       return this;
    }
}

public class Src {
    private AbstractClass m = new ConcreteClass();

    public AbstractClass abstractClassTest() {
        return m.a_function();
    }
    public static void main(String args[]) {
        new Src().abstractClassTest();
    }
}

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

person Jon Skeet    schedule 27.01.2012
comment
Если вы попытаетесь инициализировать переменную непосредственно экземпляром абстрактного класса, вы получите ошибку компиляции. - person Spencer Kormos; 27.01.2012
comment
Просто пометка для полноты. :-) - person Spencer Kormos; 27.01.2012

m никогда не назначается, и вы никогда не пытаетесь создать экземпляр нового abstractClass с новым ключевым словом. Если бы ваш код действительно попал в abstractClassTest, вы бы просто получили исключение нулевого указателя. Я думаю, вы можете путать объявление переменной и фактическое присвоение ей значения.

person Stephanie Miller    schedule 27.01.2012

Вы не можете напрямую создать экземпляр абстрактного класса, и ваш код на самом деле этого не делает. То, что у вас есть, является просто ссылкой на какой-то подкласс или другой из вашего абстрактного класса, и когда вы приходите к созданию экземпляра «m», вам нужно будет предоставить фактический конкретный подкласс.

Вы получаете аналогичный образец с интерфейсами. Вполне допустимо написать, например:

List m;
...
m.size();

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

List m;
...
m = new ArrayList();
...
m.size();

Обратите внимание, что при создании экземпляра мы используем ArrayList, а не List (это просто интерфейс).

person Neil Coffey    schedule 27.01.2012