Java: вопрос наследования новичков - PullRequest
3 голосов
/ 03 октября 2008

Предположим, у меня есть базовый класс B и производный класс D. Я хочу, чтобы в моем базовом классе был метод foo (), который возвращает новый объект любого типа, которым является экземпляр. Так, например, если я вызываю B.foo (), он возвращает объект типа B, а если я вызываю D.foo (), он возвращает объект типа D; Между тем, реализация находится исключительно в базовом классе B.

Возможно ли это?

Ответы [ 8 ]

3 голосов
/ 03 октября 2008

Не. Сделайте метод "foo" абстрактным.

abstract class B {
    public abstract B foo();
}

Или получить абстрактную фабрику через конструктор базового класса:

abstract class B {
    private final BFactory factory;
    protected B(BFactory factory) {
        this.factory = factory;
    }
    public B foo() {
        return factory.create();
    }
}
interface BFactory {
    B create();
}

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

3 голосов
/ 03 октября 2008

Пока у каждого класса есть конструктор по умолчанию:

    public B instance() throws Exception {
        return getClass().newInstance();
    }
1 голос
/ 03 октября 2008

Как говорят другие ответы, вы можете использовать getClass (). NewInstance (), если в каждом подклассе есть конструктор без аргументов (обязательно перехватывайте InstantiationException и IllegalAccessException).

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

, например

Thing foo() {
    Thing th = getNewInstance();
    // do some stuff with th
    return th;
}

Thing getNewInstance() {
    return getClass().newInstance();
}

Тогда getNewInstance () можно переопределить, только если вам это действительно нужно, для подклассов, у которых нет конструктора по умолчанию.

Thing getNewInstance() {
    return new BigThing(10, ThingSize.METRES);
}
1 голос
/ 03 октября 2008

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

В вашем вопросе вы используете статические (классовые) методы B.foo (), D.foo (), это невозможно сделать с помощью наследования, потому что статические методы не имеют динамической природы, они не принимают участия в поисковой системе. Таким образом, у вас недостаточно информации о типе.

Если вы используете функцию-член foo (), вы можете иметь следующую конструкцию:

public class B {
    public B foo()
    throws IllegalAccessException, InstantiationException {
        return this.getClass().newInstance();
    }
}

public class D  extends B{    
}

public class Test {
    public static final void main(String[] args)
    {
        try {
            System.out.println((new B()).foo());
            System.out.println((new D()).foo());
        } catch (IllegalAccessException e) {
            e.printStackTrace();  
        } catch (InstantiationException e) {
            e.printStackTrace();  
        }
    }
}
1 голос
/ 03 октября 2008

Ну, я мог бы быть выключен, но я бы предположил, что, поскольку «this» всегда относится к текущему объекту, вы можете сделать что-то вроде

public B foo() {
    return this.getClass().newInstance();
}

или что-то в этом роде? Если вы создаете экземпляр D и затем вызываете d.foo (), вы должны получить экземпляр D, возвращенный как B. Вы можете вернуть его как простой объект, но я думаю, что вы должны быть настолько конкретны, насколько это возможно, в этом случае, я думаю.

1 голос
/ 03 октября 2008

Я думаю, что это возможно сделать с помощью рефлексии, т. Е. В вашем суперклассе у вас есть:

public ClassName getFoo() throws InstantiationException, IllegalAccessException
{
    return getClass().newInstance();
}

Где ClassName - это имя вашего базового класса.

Вам придется разыграть его там, где вы хотите его использовать, хотя ... Я не уверен, что это действительно отличное решение!

Редактировать: Методы типа newInstance () обычно являются статическими, и, конечно же, вы не будете иметь представления о том, какой тип вашего подкласса имеет статический метод.

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

0 голосов
/ 03 октября 2008

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

public class B <X extends B>{

public X foo() throws InstantiationException, IllegalAccessException{
    return (X)this.getClass().newInstance();
}
}        
public class C extends B<C>{        

}

Позвольте мне предложить вам этот совет. Классы CS, как правило, преподаются в том, что профессора влюблены в наследство, но не выяснили состав. Я думаю, что вы можете искать это композиция. Поэтому вместо вызова getNextThing для самой Thing, возможно, вам следует подумать о том, чтобы заставить Thing реализовать Iterable

Это означает, что вам просто нужно написать Итератор , который может инкапсулировать логику получения следующей вещи, поскольку она, похоже, не вписывается в вашу модель наследования. Еще одним преимуществом этого является то, что вы получаете некоторые хорошие синтаксические устройства из этого (улучшено для понимания цикла).

0 голосов
/ 03 октября 2008

@ Rik

Ну, настоящая проблема в том, что у меня есть абстрактный базовый класс Thing. И у Thing есть метод getNextThing (), который возвращает новый экземпляр Thing.

Затем у меня есть несколько подклассов, таких как BigThing, LittleThing, SomethingThing, и я не хочу переписывать метод getNextThing () для каждого из них. Это кажется расточительным, так как все они делают одно и то же ... вещь.

Я ошибаюсь в своем подходе?

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