在Java中,假设我有3个类,C从B扩展而来自A。
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);
}
}
如果我执行上述test()
所示的此类操作:
C c = new C()
B b = (B) c;
f(b);
f()
接受b
作为C
类型,因为C
和B
都来自A
。我希望f()
接收b
作为B
类型,而不是C
类型。
无论如何迫使这种向上推进?
答案 0 :(得分:9)
f()
将始终接收输入为A的内容(尽管在封面下它实际上是B或C,并且可以适当地向下投射)。
您可以定义一个额外的f()
f(B b);
并在必要时
f(C c);
并根据参数的类调用正确的。即,编译器根据参数的类型确定调用哪个函数。这与运行时发生的动态调度(或多态)不同。
请注意,您在问题中的演员阵容是多余的。你可以写:
C c = new C()
B b = c;
f(b);
由于C从B延伸,因此C 是 B。
答案 1 :(得分:2)
您似乎对编译时类型和运行时类型之间的区别感到困惑。
您正在创建一个C类型的对象(由引用c和b指向),它将保持一个C,因为无法更改对象的运行时类型,从而无法改变行为;通过转换,您只需更改其编译时类型,这会影响编译器处理它的方式。
您能否提供一些有关您要解决的具体问题的更多信息?最有可能通过改变设计来实现目标。
答案 2 :(得分:1)
我希望f接收b作为B类而不是C类。
C
B
是A
。
在f
内,f
只看到其参数的A
部分a
如果f
调用公共A
函数,则C
在C
中重写,调用C
覆盖。
这就是虚拟功能的工作原理。想法是,所提到的对象实际上是C
,因此它应该表现出B
行为。如果您想要B
行为,请传递C
个实例,而不是C
个实例。
如果'C'和'B'应该具有相同的行为,请不要在{{1}}中抛弃该行为。
你为什么要这样做?
答案 3 :(得分:1)
你的问题没有意义。你是什么意思“f接受b作为C型”?
f接受b作为类型A,因为方法签名是“A”。如果在b上调用方法,如果C覆盖它们,它们将在C上调用。但这是Java中的标准行为(所有方法都像C ++中的虚方法),并且没有办法改变它。
也许你可以描述你的实际问题,然后我们也可以提供帮助。
答案 4 :(得分:0)
你可以传递A的任何子类作为f(A a)的参数这一事实是Java中OO所固有的,你无法绕过它。如果C扩展A,您可以始终在期望A的地方使用它。
答案 5 :(得分:0)
您可以使用反射来检查参数是否属于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!");
}
}
不知道这是不是你想要的,但它可能会有所帮助。
答案 6 :(得分:0)
通过了解REFERENCE类型和INSTANCE类型之间的区别,可以解决您的问题。当您将C对象转换为B时,您只更改引用类型 - 对象的实际实例仍然是C对象 - 如果您在调试模式下查看对象,这应该是非常明显的。更改引用类型只会影响编译器处理/感知代码的方式 - 运行时行为不应受到影响。对C对象的任何方法调用都将始终调用C的方法(无论对象是否已被转换为其他对象)。如果您从B重写方法并想要调用B的方法版本,那么您将需要创建一个B实例。
答案 7 :(得分:0)
您的代码引用A的事实并不意味着指向的对象也是A.如果它是C,它仍然是C.源中的引用仅限制源中的可用方法。转换只是必要的,因为有时需要一个不同类型的方法,我们需要欺骗编译器,这样我们就可以开始使用类型上的方法来键入。当然,如果我们无效,那么演员阵容可能会在运行时失败。
答案 8 :(得分: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;
}