在java中向上转换

时间:2009-05-03 15:58:28

标签: java casting

在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类型,因为CB都来自A。我希望f()接收b作为B类型,而不是C类型。

无论如何迫使这种向上推进?

9 个答案:

答案 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 BA

f内,f只看到其参数的A部分a如果f调用公共A函数,则CC中重写,调用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;
}