Вызов метода, который существует в дочерних классах, но не существует в родительском классе

public class Parent {
    ....
}

public class Child1 extends Parent {
    ....
    public void foo() {
        ....
    }
}

public class Child2 extends Parent {
    ....
    public void foo() {
        ....
    }
}

Здесь метод foo() существует только в дочерних классах и НЕ МОЖЕТ быть добавлен в родительский класс (даже абстрактный метод). В этой ситуации, когда я хочу вызвать метод foo() для obj, который является ссылкой на класс Parent, мне нужно использовать intanceof с несколькими if..else, которых я хочу избежать.

Parent obj = ...// Object of one of the child classes
obj.foo();

EDIT: Мне нужно использовать тип obj только как Parent. В противном случае я не смогу вызывать методы объекта obj, который существует в родительском классе.


Мое решение. Подход, о котором я думаю, состоит в том, чтобы определить интерфейс, скажем, FooInterface с помощью метода foo(), и позволить всем дочерним классам реализовать его, тогда я мог бы просто ввести obj в этот интерфейс и вызвать foo( ) такой метод:

if(obj instanceof FooInterface){
    ((FooInterface)obj).foo();
}

Есть ли лучший подход? Или какое-то улучшение этого?


person Learner    schedule 06.05.2014    source источник
comment
Всякий раз, когда метод является общим для дочернего элемента, он должен быть помещен в родительский. Почему вы не помещаете этот метод в абстрактный класс??   -  person Shoaib Chikate    schedule 06.05.2014
comment
Я НЕ МОГУ изменить Parent класс, так как не управляю им.   -  person Learner    schedule 06.05.2014
comment
Затем используйте интерфейс, указанный в решении, приведенном ниже в ответах.   -  person Shoaib Chikate    schedule 06.05.2014
comment
Можете ли вы ввести промежуточный класс между родителем и дочерним элементом?   -  person vikingsteve    schedule 06.05.2014


Ответы (5)


Вы не можете сделать это со ссылкой на родительский объект, пока в самом родительском классе/интерфейсе не будет объявлен метод.

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

Здесь contract означает abstract methods.


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

FooInterface sc =new Child1();
sc.foo();

...

interface FooInterface{
    void foo();
}

public class Parent {

}

public class Child1 extends Parent implements FooInterface{

    public void foo() {

    }
}

public class Child2 extends Parent implements FooInterface{

    public void foo() {

    }
}
person Braj    schedule 06.05.2014
comment
С этим решением я не смогу вызывать методы sc, которые существуют в родительском классе. Я отредактировал свой вопрос, чтобы упомянуть об этом. Спасибо. - person Learner; 06.05.2014
comment
Вы сделали Child1 орудия FooInterface такими же для Child2? - person Braj; 06.05.2014
comment
Это то, что я упомянул в своем решении, разница только в том, что в моем решении ссылка имеет тип Parent, и поэтому мне нужно использовать instanceof один раз, чтобы увидеть, относится ли она к типу FooInterface. - person Learner; 06.05.2014
comment
так что вы не хотите менять свой дизайн, тогда это невозможно, как я сказал вам, родительский класс/интерфейс не имеет никаких знаний о дочернем классе. как родительский класс/интерфейс узнает, что дочерний класс создал х методов? - person Braj; 06.05.2014
comment
Как насчет моего решения, которое я упомянул в вопросе? это решает мою проблему. Но хороший подход - это то, что я хочу знать? - person Learner; 06.05.2014

Подход, который я, наконец, использую, заключается в том, чтобы определить интерфейс, скажем, FooInterface с методом foo(), и позволить всем дочерним классам реализовать его, тогда я мог бы просто ввести obj в этот интерфейс и вызвать метод foo() следующим образом:

Parent obj = ...// Object of one of the child classes
.....
if(obj instanceof FooInterface){
    ((FooInterface)obj).foo();
}
person Learner    schedule 19.05.2014

Полиморфизм применяется к ссылке на объект, а не к типу. Когда вы звоните

FooInterface obj = ...// Object of one of the child classes
obj.foo(); 

вызывается метод дочернего класса foo().

person Roman C    schedule 06.05.2014
comment
Посмотрите еще раз на вопрос ОП. Parent не имеет никакого foo() метода. - person Braj; 06.05.2014
comment
Как вы можете вызвать метод по ссылке интерфейса, если интерфейс не объявил этот метод? Посмотрите на мой пост. - person Braj; 06.05.2014
comment
@Braj Теперь вы должны снова прочитать вопрос ОП, интерфейс определяет метод foo. - person Roman C; 06.05.2014
comment
Прочитайте эту строку, а не часть решения Здесь метод foo() существует только в дочерних классах и НЕ МОЖЕТ быть добавлен в родительский класс (даже абстрактный метод) - person Braj; 06.05.2014
comment
@Roman C, интерфейс является частью моего решения, и я спрашиваю, хорошо ли мое решение или есть лучший способ сделать это. - person Learner; 06.05.2014
comment
@Braj читайте больше, что отмечает ОП: The approach that I am thinking is to define an interface say FooInterface with foo() - person Roman C; 06.05.2014
comment
@Braj Что за проверка кода? Вы не java-программист? Или что-то не так с форматом ответа? Или ты просто шутишь? - person Roman C; 06.05.2014
comment
@RomanC ваш ответ лучше всего подходит для этого условия. +1 за этот подход. - person Braj; 06.05.2014
comment
@Learner Еще один комментарий для вас: при разработке ваших классов учитывайте кодирование интерфейсов, а не классов. - person Roman C; 06.05.2014
comment
@RomanC, с этим решением я не смогу вызывать методы для obj, которые существуют в классе Parent. Да, я понимаю преимущество кода для интерфейса, но это устаревший код, и я НЕ МОГУ изменить класс Parent. - person Learner; 06.05.2014
comment
@Learner, если вам нужен родительский класс, приведите его напрямую или используйте метод в интерфейсе, который возвращает родительский тип. Почему в вопросе, который вы хотите использовать родитель, нет этого? Видите, у вас есть еще один неполный ответ от %Braj. - person Roman C; 06.05.2014

Если вы хотите только приведение типов, то нет необходимости добавлять интерфейс. Вы можете привести его к нужному классу и вызвать метод. Пример

public class HelloWorld {
    public static void main(String args[]) throws FileNotFoundException {
        SuperClass sc =new Child1();
        if(sc instanceof Child1)//Do same for Child2
        ((Child1)sc).foo();
    }
}

class SuperClass {

}

class Child1 extends SuperClass{
    public void foo(){
        System.out.println("From child1");
    }
}

class Child2 extends SuperClass{
    public void foo(){
        System.out.println("From child2");
    }
}

Выход: от ребенка1

person Aniket Thakur    schedule 06.05.2014
comment
Ну, это то, что я считаю не очень хорошим подходом и, следовательно, не хочу его использовать. Если есть несколько дочерних классов, это было бы некрасиво. не так ли? - person Learner; 06.05.2014

Вы можете реализовать AbstractChild, наследующий от Parent, а затем расширить этот класс вместо Parent:

public class Parent {
    ....
}

public abstract class AbstractChild extends Parent{

    public abstract void foo();

}



public class Child1 extends AbstractChild {
    ....
    public void foo() {
        ....
    }
}

public class Child2 extends AbstractChild {
    ....
    public void foo() {
        ....
    }
}

Поэтому вам нужно только проверить, является ли ваш экземпляр instanceof AbstractChild.

person davioooh    schedule 06.05.2014