Java; кастинг базового класса к производному классу

Почему я не могу бросить экземпляр базового класса к производному классу?

Например, если у меня есть класс B, который расширяет класс C, почему я не могу сделать этого?

B b=(B)(new C());

или это?

C c=new C();
B b=(B)c;

Хорошо позвольте мне быть более конкретным относительно того, что я пытаюсь сделать. Вот то, что я имею:

public class Base(){
    protected BaseNode n;
    public void foo(BaseNode x){
        n.foo(x);
    }
}


public class BaseNode(){
    public void foo(BaseNode x){...}
}

Теперь я хочу создать новый набор классов, которые расширяют Base и Basenode, как это:

public class Derived extends Base(){
    public void bar(DerivedNode x){
        n.bar(x);//problem is here - n doesn't have bar
    }
}

public class DerivedNode extends BaseNode(){
    public void bar(BaseNode){
        ...
    }
}

Таким образом, по существу я хочу добавить новую функциональность для Базирования и BaseNode путем расширения их обоих и добавления функции к ним обоим. Кроме того, Основа и BaseNode должны смочь использоваться самостоятельно.

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


Хорошо, таким образом, я закончил тем, что понял это, частично благодаря ответу Maruice Perry.

В моем конструкторе для Base, n инстанцирован как a BaseNode. Все, что я должен был сделать, было, повторно инстанцируют n как a DerivedNode в моем производном классе в конструкторе, и это работает отлично.

19
задан Cam 3 April 2010 в 20:06
поделиться

7 ответов

Вам необходимо использовать ключевое слово instanceof , чтобы проверить тип объект, на который ссылается n , введите тип объекта и вызовите метод bar () . Checkout Derived.bar () метод ниже

public class Test{
    public static void main(String[] args){
        DerivedNode dn = new DerivedNode();
        Derived d = new Derived(dn);
        d.bar( dn );
    }
}

class Base{
    protected BaseNode n;
    public Base(BaseNode _n){
        this.n = _n;
    }

    public void foo(BaseNode x){
        n.foo(x);
    }
}


class BaseNode{
    public void foo(BaseNode x){
        System.out.println( "BaseNode foo" );
    }
}

class Derived extends Base{
    public Derived(BaseNode n){
        super(n);
    }

    public void bar(DerivedNode x){
        if( n instanceof DerivedNode ){
            // Type cast to DerivedNode to access bar
            ((DerivedNode)n).bar(x);
        }
        else {
            // Throw exception or what ever
            throw new RuntimeException("Invalid Object Type");
        }
    }
}

class DerivedNode extends BaseNode{
    public void bar(BaseNode b){
        System.out.println( "DerivedNode bar" );
    }
}
6
ответ дан 30 November 2019 в 02:22
поделиться

потому что, если B расширяет C, это означает, что B является C, а не C является B.

переосмыслите то, что вы пытаетесь сделать.

20
ответ дан 30 November 2019 в 02:22
поделиться

Потому что если B расширяет C, то в B могут быть вещи, которые не находятся в C (например, переменные экземпляра, инициализируемые в конструкторе, которые не находятся в новом C())

0
ответ дан 30 November 2019 в 02:22
поделиться

Вы не можете этого сделать, потому что C не обязательно реализует поведение, которое вы создали, когда вы расширили его в B.

Итак, скажем, c имеет метод foo(). Тогда вы знаете, что вы можете вызвать foo() на B, так как B расширяет C, поэтому вы можете соответственно отлить трактовку B, как если бы это был C с (C)(новый B()).

Однако - если у B есть метод bar(), ничто в отношениях подкласса не говорит о том, что вы можете вызвать bar() на C тоже. Таким образом, вы не можете относиться к C так, как если бы это было B, и поэтому вы не можете бросать.

2
ответ дан 30 November 2019 в 02:22
поделиться

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

// Hypothetical code
Object object = new Object();
InputStream stream = (InputStream) object; // No exception allowed?
int firstByte = stream.read();

Откуда конкретно взялась реализация метода read ? Это аннотация в InputStream . Откуда ему взять данные? Просто не подходит для обработки пустого java.lang.Object как InputStream . Гораздо лучше для приведения в действие сгенерировать исключение.

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

19
ответ дан 30 November 2019 в 02:22
поделиться

Вы можете создать конструктор для B который принимает в качестве параметра C. См. этот пост , чтобы узнать, как делать то, что вы пытаетесь сделать.

4
ответ дан 30 November 2019 в 02:22
поделиться

В вашем примере вы можете преобразовать n в DerivedNode, если уверены, что n является экземпляром DerivedNode, или вы можете использовать обобщенные типы:

public class Base<N extends BaseNode> {
    protected N n;
    public void foo(BaseNode x){
        n.foo(x);
    }
}


public class BaseNode {
    public void foo(BaseNode x){...}
}

public class Derived extends Base<DerivedNode> {
    public void bar(DerivedNode x){
        n.bar(x); // no problem here - n DOES have bar
    }
}

public class DerivedNode extends BaseNode {
    public void bar(BaseNode){
        ...
    }
}
2
ответ дан 30 November 2019 в 02:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: