【问题标题】:Java Type System: Why do these assignments, method calls and type casts fail?Java 类型系统:为什么这些赋值、方法调用和类型转换会失败?
【发布时间】:2018-11-12 11:45:48
【问题描述】:

假设我定义了以下接口和类:

public interface I { void a(); }

public class A implements I {
    public void a() { System.out.println("A"); }
}

public class B implements I {
    public void a() { System.out.println("B"); }
    public void b() { System.out.println("C"); }
}

然后我运行以下代码:

public class Main {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        I i;
        i = a;
        i.a();    // prints "A"
        i = b;
        i.a();    // prints "B"
        i.b();    // 1st problem: i can't seem to find method b. Why?
        b = i;    // 2nd problem: b can't be assigned to i although i references an object of class B?
        b = (B)i; //              why does this work fine...
        a = (A)i; // 3rd problem: ...but this here doesn't?
    }
}

所以这是我的问题:

第一个问题

为什么不能调用i.b()

i 指向与b 相同的对象,B 类的对象,它确实有一个方法b

那么为什么i.a() 调用了正确的方法(打印出“B”的方法)但i.b() 根本没有解决?

i 被声明为I 类型(接口)这一事实与此有关吗?这是否意味着在 Y extends X 的赋值 X x = new Y() 中,只能调用 x 上已经在 X 中声明的方法,而不仅仅是特定于 Y

第二个问题

虽然i 引用了B 类的对象,但为什么不能将b 分配给ibi 已经引用了同一个对象,不是吗?那么,如果我尝试将b 分配给i,为什么会导致错误 - 其最终结果应该与该分配之前的程序状态相同,除非我错过了重要的事情。

第三题

为什么我现在可以将i 转换为B,虽然我之前无法将b 分配给i,为什么不能将i 转换为A 工作?

我假设我的困惑在某种程度上源于引用变量和它们所引用的对象之间的不明确区别,以及这些变量和对象的类型之间的差异。我只是无法完全解释这些事件——尤其是第一个问题让我很困惑。

【问题讨论】:

    标签: java types casting variable-assignment


    【解决方案1】:

    对于第一个问题: 您可以使用接口引用仅调用它声明的方法

    对于第二个问题: 您可以使用接口引用来调用实现该接口的类中的方法。但是,将接口引用分配给类引用是没有用的,因为接口引用没有任何可以调用的方法。

    第三个问题: 您之前已分配

            i=b 
    

    因此

         b=(B)i 
    

    工作正常。

    然而, a=(A)i 行不通,因为我存储的是 b 而不是 a

    【讨论】:

      【解决方案2】:

      首先,学习Java(和/或OO(面向对象))编程...

      1. 变量i 是对实现接口I 的对象实例的引用。方法b()未在接口I中声明,因此通过i.b()不可见。
        为了能够调用它,i 需要被强制转换,例如:((B) i).b()
      2. 变量b 是对作为B 类实例的对象的引用,并且不能将其分配给本身未声明为B 实例的任何引用。
        再次,需要演员,例如:b = (B) i
      3. B 类不是A 类的子类。它们都实现了接口I,但A 不是B 的父级。

      【讨论】:

      • 什么是“对象实例”?它不只是一个对象吗? IE。一个类的实例?
      【解决方案3】:

      这根本不是问题,而是继承和多态的行为。

      请注意,当你

      I i = new A();
      

      左侧 (I) 将告诉编译器它可以使用该引用调用哪些所有方法。

      右侧 (A) 将告诉运行时应使用该方法调用执行哪个方法

      所以你的情况

      1 个问题

      你不能打电话给b(),因为b()不在接口I

      2 问题

      您正在将接口转换为对象 b,然后调用 b(),这样它就可以正常工作了。

      【讨论】:

        猜你喜欢
        • 2020-04-19
        • 2011-02-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-09-11
        相关资源
        最近更新 更多