Java проблема наследования. Вызов метода подкласса внутри массива суперкласса не компилируется - PullRequest
0 голосов
/ 23 марта 2020

У меня есть класс BaseClass, и у него есть два подкласса C и D. Мне нужно поместить объекты типа C и D в массив BaseClass. Назначение работает. Но если я вызову метод print (), определенный в C и D в массиве, он не скомпилируется. Я что-то упустил, но поиск в Интернете или здесь не ответил на мой вопрос.

В моей книге сказано, что цепочка наследования будет искать print () в C. Если print () найден в C, используйте его. Если не найдено в C go до родительского класса. Как исправить?

Согласно описанию Java наследование позволяет подклассу наследовать данные и методы от суперкласса. Кроме того, в наследовании говорится, что когда метод вызывается для объекта JVM, он сначала ищет метод в классе объекта. Если метод там, он будет использовать этот метод. Однако это следующее не будет компилироваться. Цель состоит в том, чтобы иметь массив суперкласса и назначать ему объекты подклассов.

Ниже приведена программа.

//This is an example program.
public class Tester
{
    static public void main(String[] args)
    {
        BaseClass[] myarr = new BaseClass[10];
        myarr[0] = new C();
        myarr[1] = new D();

        myarr[0].print();  //error

        for (int i =0 ; i < 10; i++)
        {
            if(myarr[i] != null)  myarr[i].print(); //will not compile. Why?
        }
    }
}

Это код суперкласса.

public class BaseClass
{
    public BaseClass()
    {
    }

    //it wants print(), why?
}


Далее у меня есть два подкласса C и D.

//subclass
public class C extends BaseClass
{
    public C()
    {
    }

    public void print()
    {
        System.out.println(“hello C”);
    }
}

И подкласс D.

//subclass
public class D extends BaseClass
{
    public D()
    {
    }

    public void print()
    {
        System.out.println(“hello D”);
    }
}

Ответы [ 2 ]

1 голос
/ 23 марта 2020

Это не работает, потому что при создании массива типа BaseClass компилятор ничего не знает о методе print(). Они просто представлены в ваших 2 подклассах.

Представьте, что у вас есть другой подкласс под названием E (также расширяющий базовый класс), который не имеет функции print(). Теперь назначьте объект E одному из мест в myarr. Пока здесь все будет работать нормально. Теперь, когда вы попытаетесь вызвать метод print(), компилятор не будет знать, что делать. Вот почему компилятор не может найти print () и не хочет «интерпретировать» ваш код.

Теперь для решения этой проблемы есть 2 возможности. Если вам нужен print() -метод в каждом подклассе, вы можете просто создать один абстрактный метод:

public abstract class BaseClass {
    public BaseClass() {
        // Some Constructor Work
    }
    // This tells the compiler there is a print()-method in every subclass because it must be overridden
    public abstract void print();
}

Теперь в ваших подклассах (я просто делаю один для подтверждения концепции:)):

public class SubClass extends BaseClass {
    public SubClass() {
        // Do Constructor Work if necessary
    }
    // I would highly suggest you also use this annotation because it helps you 
    // identifying overridden methods (but it is not obligatory to use)
    @Override
    public void print() {
        System.out.println("Hello from SubClass");
    }
}

Теперь у вас в главном:

public static void main(String[] args) {
    // Init Array
    BaseClass[] myarr = new BaseClass[4];
    myarr[0] = new SubClass();
    myarr[1] = new OtherSubClass();
    // and so on... I think you get the gist

    // Now execute print()
    myarr[0].print(); // This works perfectly now.
}

Теперь возможность 2, которая в зависимости от вашего варианта использования может быть единственной работающей (хотя я настоятельно рекомендую использовать метод, показанный ранее, поскольку здесь вы должны быть На 100% уверен, что ClassType вашего объекта) намного небезопаснее, и вы должны знать, что вы делаете, или вы получаете ошибки (и никто не любит ошибки правильно? :)): Используйте Casting.

public static void main(String[] args) { // Note I will be using "your" classes here again
    // Array Init...
    BaseClass[] myarr = new BaseClass[10];
    // Assign blabla
    myarr[0] = new C();
    myarr[1] = new D();

    ((C) myarr[0]).print(); // Casting to C-Type which has a print()
}

Это будет в основном, сообщаем компилятору (и JVM): «Эй, не волнует, какой тип у этого объекта. Просто предположим, что это будет C -Тип!» Я думаю, вы начинаете понимать, в чем может быть проблема. Если компилятор хочет прочитать C -Тип, но вместо этого получает D-тип или E-тип, он не знает, что делать -> Ошибка.

Надеюсь, я мог бы помочь вам:)

РЕДАКТИРОВАТЬ:

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

1 голос
/ 23 марта 2020

Во время компиляции компилятор проверит, что BaseClass имеет метод print (), так как тип stati c любого элемента в myarr - BaseClass. Во время выполнения программа сможет динамически разрешать тип каждого объекта либо на C, либо на D. Только тогда она будет искать классы C или D для соответствующих методов печати. Чтобы это исправить, вы можете добавить метод печати по умолчанию в BaseClass.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...