2009-05-03 4 views
2

In Java, nehme ich drei Klassen haben, erstreckt sich C von B, die von A.Upcasting in java

class X { 
    interface A {} 
    interface B extends A {} 
    interface C extends B {} 
    void f(A a) {} 

    void test() { 
     C c = new C() 
     B b = (B) c; 

     f(b); 
    } 
} 

Wenn ich in test(), wie oben gezeigt, so etwas wie dies erstreckt:

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

f(b); 

f() akzeptiert b als Typ C seit C und B beide von A erstrecken. Ich wollte f() erhalten b als Typ B und nicht Typ C.

Gibt es trotzdem, um diese Upcasting zu erzwingen?

Antwort

9

f() wird immer erhalten etwas als A typisiert (trotz der Abdeckungen ist es eigentlich ein B oder C, und kann entsprechend herabgestuft werden).

Sie können eine zusätzliche f()

f(B b); 

so definieren und ggf.

f(C c); 

und die richtige wird abhängig von der Klasse des Arguments aufgerufen werden. d.h. der Compiler bestimmt abhängig vom Typ des Arguments, welche Funktion aufgerufen wird. Dies unterscheidet sich von einem dynamischen Dispatch (oder Polymorphismus), der zur Laufzeit auftreten würde.

Beachten Sie, dass Ihre Besetzung in der Frage überflüssig ist. Sie können schreiben:

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

f(b); 

seit C von B erstreckt, C ein B. ist

1

I fb als Typ B und Typ C. nicht

erhalten wollte A C ist ein B ist ein A.

Innerhalb von f, f nur den A Teil seines Parameters sieht a Wenn f eine öffentliche A Funktion aufruft, die in C außer Kraft gesetzt wird, die C Übersteuerung aufgerufen.

So funktionieren virtuelle Funktionen. Die Idee ist, das Objekt, auf das Bezug genommen wird, ist wirklich ein C, so sollte es C Verhalten zeigen. Wenn Sie B Verhalten möchten, übergeben Sie eine B Instanz, keine C Instanz.

Wenn ‚C‘ und „B‘ das gleiche Verhalten haben sollten, nicht ovveride nicht, dass das Verhalten in C.

Warum Sie das tun wollen?

+0

Dies ist genau das, was ich versuche zu verstehen. Ich möchte, dass der Parameter B-Verhalten aufweist. Ich denke, ich muss eine neue B-Instanz von C erstellen, bevor ich sie an f übergebe. Vielen Dank. – simao

+0

Wenn Sie möchten, dass f auf einem B operiert, warum erstellen Sie nicht einfach ein B? Wo kommt C rein? – tpdi

1

Ihre Frage nicht sinnvoll. Was meinst du mit "f akzeptiert b als Typ C"?

f akzeptiert b als Typ A, da die Methodensignatur "A" sagt. Wenn Sie Methoden auf b aufrufen, werden sie in C aufgerufen, wenn C sie überschreibt. Aber das ist Standardverhalten in Java (alle Methoden sind wie virtuelle Methoden in C++), und es gibt keine Möglichkeit, sie zu ändern.

Vielleicht können Sie Ihr tatsächliches Problem beschreiben, dann können wir vielleicht helfen.

+0

Ich möchte f Methoden auf den Parameter abhängig von seinem Typ aufrufen, wenn der Parameter ein C ist, möchte ich C.deliverTo() aufrufen, aber wenn der Parameter ein B ist, möchte ich B.DeliverTo() aufrufen. Vielen Dank. – simao

2

Sie scheinen über den Unterschied zwischen dem Kompilierzeittyp und dem Laufzeittyp verwirrt zu sein.

Sie erstellen ein Objekt (mit den Referenzen c und b) vom Typ C, und bleibt ein C, weil es unmöglich ist, den Laufzeittyp und damit das Verhalten eines Objekts zu ändern; Durch Casting können Sie lediglich den Typ der Kompilierungszeit ändern, was sich auf die Behandlung des Compilers auswirkt.

Können Sie weitere Informationen zu dem konkreten Problem geben, das Sie lösen möchten? Höchstwahrscheinlich gibt es einen Weg, um Ihr Ziel zu erreichen, indem Sie das Design ändern.

+0

Ja, es gibt eine andere Möglichkeit zu tun, was ich will, ich kann eine neue Instanz von B von einem C erstellen, aber ich wollte verstehen, warum ich das nicht so machen konnte, wie ich es zuerst versuchte :) Danke. – simao

0

Die Tatsache, dass Sie jede Unterklasse von A als Parameter von f (A a) übergeben können, ist OO in Java inhärent, es gibt keine Möglichkeit, dass Sie das umgehen können. Wenn C A erweitert, können Sie immer verwenden, wo ein A erwartet wird.

0

können Sie Reflexion überprüfen verwenden, wenn die Parameter der Klasse A:

public void f(A a) { 
    if (a.getClass() == A.class) { 
    // ok, go on 
    } 
    else { 
    System.err.println("The parameter is not of class A!"); 
    } 
} 

weiß nicht, ob das, was Sie wollen, aber es kann hilfreich sein.

0

Ihr Problem kann gelöst werden, indem Sie den Unterschied zwischen REFERENCE-Typ und INSTANCE-Typ verstehen. Wenn Sie Ihr C-Objekt als B-Objekt darstellen, ändern Sie nur den Referenztyp - die tatsächliche Instanz des Objekts ist immer noch ein C-Objekt. Dies sollte ziemlich offensichtlich sein, wenn Sie Ihr Objekt im Debug-Modus betrachten. Das Ändern des Referenztyps hat nur Einfluss darauf, wie der Compiler den Code handhabt/wahrnimmt - das Laufzeitverhalten sollte nicht beeinflusst werden. Jeder Methodenaufruf für ein C-Objekt ruft immer die C-Methode auf (unabhängig davon, ob das Objekt an etwas anderes übergeben wurde oder nicht). Wenn Sie eine Methode aus B überschreiben und die B-Version der Methode aufrufen möchten, müssen Sie eine B-Instanz erstellen.

0

Die Tatsache, dass Ihr Code einen Verweis auf ein A hat, bedeutet nicht, dass das Objekt auch ein A ist. Wenn es ein a C ist, bleibt es ein C. Der Verweis in Ihrer Quelle beschränkt nur die verfügbaren Methoden in Ihrer Quelle. Casting ist nur notwendig, weil manchmal eine Methode auf einem anderen Typ benötigt wird und wir den Compiler austricksen müssen, damit wir anfangen können, Methoden auf den Kasten zu verwenden, um zu tippen. Natürlich kann der Cast zur Laufzeit fehlschlagen, wenn der Versuch uns ungültig macht.

0
In upcasting and downcasting the object first upcast then downcastenter 
class A 
{ 
} 
class B extends A 
{ 
} 
Class M 
{ 
    psvm(String ar[]) 
{ 

    A a1= new B(); 
    B b2=(B)a1; 
} 
Verwandte Themen