【问题标题】:Java: Casting to an Interface and InheritanceJava:转换为接口和继承
【发布时间】:2014-07-07 15:46:08
【问题描述】:

我一直在尝试了解 Java 中的强制转换以及它如何影响引用。我想出了这个特殊的例子:

public interface A1{
      public void foo();
};

public class A2{
      public void bar();
      public static void main( String[] args )
      {
         A2 a = new B();
         A1 c = (A1)a;
         c.foo();
      }
};

public class B extends A2 implements A1{
      public void foo(){ System.out.println("This is B"); }
}

它打印“This is B”,但我不知道为什么。这就是我目前的理解:a 是对 A2 类型对象的引用,但在运行时,它指向具有 B 属性的堆对象,但 a 仅“看到”A2 的属性.但是类型已经在编译期间确定了,所以转换尝试将 A2 转换为 A1,但它不能这样做。显然我错了,但我不知道为什么。任何帮助将不胜感激。

【问题讨论】:

  • 动态类型与静态类型 - 肯定出现过几次。
  • 类型确实是A1,但是当foo()被调用时,调用对象的foo()B中的实现
  • 方法调用总是使用创建对象的实际类型(“运行时类型”)。您无法更改使用强制转换调用的方法。 但是,数据成员遵循不同的规则。 如果您有一个定义成员字段 m 的类 A,以及定义其自己的单独成员字段 m 的子类 B非常不好的做法),如果您有一个运行时类型为B 的对象,您可以通过将对象转换为(A) 来访问A 中定义的m。跨度>

标签: java inheritance polymorphism


【解决方案1】:

从概念上讲,铸造有两个组成部分,

  1. 在运行时,JVM 确保对象属于该类型,并且 如果不是,则会出现 ClassCastException 错误
  2. 在编译时,它告诉编译器允许使用 那堂课。请注意,如果对象在运行时结果不是该类型,那么它将在运行时出错。

强制转换不做的是在运行时更改实际对象的类型。

在您的示例中,您调用了 new B();这意味着在将 B 的引用转换为 A1 之后,该对象仍然是 B 的实例。假设 foo() 在 A1 上声明,并且 B 扩展了 foo,那么编译器很高兴(它通过了上面的 2)。在运行时,JVM 会扫描 B 以查找 foo 的方法,它会在 A1 之前检查 B,因为该对象是作为 B 类型创建的。自从调用 new 后它没有更改其类型。

【讨论】:

    【解决方案2】:

    强制转换检查总是在运行时进行(请参阅下一段中的警告),您的引用指向 B 类型的对象,因此当您到达强制转换位时,VM 将看到对 B 对象的引用,这可以安全地施放。请注意,强制转换实际上并不会改变对象,它只是确保其余代码调用原始对象中可用的方法。

    需要注意的是,如果可以在编译时看到强制转换绝对不可能,那么你确实会遇到编译错误。

    String foo = "x";
    Integer i = (Integer)foo; //throws a compile time error because `String` is final and `Integer` isn't its supertype.
    

    但是:

    Object foo = "x";
    Integer i = (Integer)foo; //this will only throw a runtime exception because from the compiler's point of view, `foo` may or may not be an integer.
    

    【讨论】:

      【解决方案3】:

      保存引用的变量的类型与方法实现解析的内容无关。在 Java 中,所有方法都是隐式虚拟的,这意味着每次都会通过对象的实际类型(而不是引用变量的类型)来查找它们。由于c 实际上指向B 的一个实例,所以调用的是B.foo()

      请注意,这并不一定适用于所有语言 - 例如,在 C# 中,方法只有在您明确声明它们时才是虚拟的,因此它的默认行为将符合您的想法。然而,Java 始终是虚拟的。

      【讨论】:

        【解决方案4】:

        引用仅在编译期间或静态方法或行为的情况下出现。

        当你创建一个对象时,方法或行为将取决于你创建了谁的对象,而不是你使用了谁的引用。这称为多态。

        例如,让我们以现实生活中的实体为例 ---

        你租房子的时候,是找中介帮你找房子,这是你的参考。但是房子的归属人,房东才是你要的实际对象。所以出租给你的是房东而不是经纪人。

        【讨论】:

          猜你喜欢
          • 2011-01-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多