【问题标题】:The difference between "C c = new C()" and "A c = new C()" when C is a subclass of A in JavaJava中C是A的子类时“C c = new C()”和“A c = new C()”的区别
【发布时间】:2013-02-17 04:12:54
【问题描述】:

假设我们有 A 类作为父类,C 类扩展它。

class A
{
    void m()
    {
        System.out.println("A.m");
    }
}

class C extends A
{
    @Override
    void m()
    {
        System.out.println("C.m");
    }
}

当我们使用引用A aC c来指向同一个对象类型时,例如A a = new C();C c = new C();有什么区别?

从这个问题:Java inheritance vs. C# inheritance,看起来ac指向C的对象类型,使用它们似乎没有区别。

我测试了这段代码,它们都打印出C.m

class inherit {

    void x(A a)
    {
        a.m();
    }

    public static void main(String[] args) {
        System.out.println("hello");
        A a = new C();
        C c = new C();
        a.m();
        c.m();

        new inherit().x(a);
        new inherit().x(c);

    }
}

【问题讨论】:

  • 如果C 定义了A 中未定义的方法,您将无法通过A 引用调用它们。此外,如果方法需要 C 参数,则不能将 A 传递给它。在这两种情况下,您都必须将 A 转换为 C
  • 不同之处在于,如果 C 有一个 A 没有的方法,它就不能通过 A a 访问。另一方面,如果您有多个 A 的子类型,并且希望在某个集合中对它们都一视同仁,那么将它们转换为 A 更有意义。

标签: java inheritance


【解决方案1】:

这取决于对象的用途。

如果你真正需要的是一个有A的接口的对象(即A的类型),强烈建议使用A a = new C();。这样可以清楚地表明您需要A 接口,而不是C 实现。稍后当您改变主意时,您可以安全地将其更改为A a = new Another_Subtype_Of_A();,而不会破坏其他代码。

A 是一个接口时尤其如此(在您的情况下,A 是一个类)。例如,如果你只想要一个列表,List list = new ArrayList(); 显然比ArrayList list = new ArrayList(); 好。这就是所谓的“编程到接口,而不是实现”。

如果您正在创建一个特别需要C 接口的对象(尤其是那些在A 中不存在的接口),您最好选择C c = new C();。如果你改为写A a = new C(),迟早你还是得把对象转换成C(因为A没有你想要的所有接口),那何必呢?

【讨论】:

    【解决方案2】:

    这与变量的运行时类型无关。你可能只知道在编译时你有一个Vehicle 对象,并且基于用户输入,它可能是GarbageTruckSportsCar

    GarbageTruck t;
    ...
    t = new SportsCar();  //can't do this!
    
    // so we do this:
    Vehicle t;
    if(user.isFast()) {
       t = new SportsCar();
    } else {
       t = new GarbageTruck();
    }
    

    【讨论】:

      【解决方案3】:

      Java 是关于接口和实现的。

      接口只是一组公共字段(方法和属性),描述用户如何与实现接口的类进行交互。

      实现是实际上使这些方法和属性做某事的代码。实现可以是implementsinterface 的类,也可以是其他实现的子类。

      当您实例化一个类时,您正在编写如下代码:

      Interface a = new Implementation();
      

      很多时候,我们将接口和实现包装在一起...换句话说,当我们定义一个class 时,无论我们是否显式实现一个接口,我们都会用每个@ 定义一个接口987654325@我们写的方法。

      因此,接口会影响我们可以调用的方法,但实现会影响我们调用它们时发生的情况。

      【讨论】:

        【解决方案4】:

        首先A 是父类,C 是子类,当您执行A a = new A() 然后A 的对象由A 句柄创建并持有。当您执行C c = new C() 时,C 的对象正在创建并且C 句柄持有它。但是当您执行A a = new C() 时,C 的对象被创建并且Ahandle 持有它。这意味着C 的所有属性现在都已使用。尽管A 的句柄被C 的属性(实例)使用。这就是我们的多态性。现在它将使用 C 而不是 A 的所有重载方法

        用法举例
        当您创建一个为子类创建方法的大型项目时,差异就出现了
        假设你有 hello 方法
        public void hello(C c) { }

        将来你有另一个类 B 扩展 A.. 在这种情况下你不能使用 hello 因为它的参数是 C.. 并且想象你有很多类作为 A 的子类需要使用这种方法(那么您将创建多少这样的方法)。多态是救命稻草
        您以 A 作为参数创建 hello
        public void hello (A x) { }
        现在您可以对A..的所有孩子使用相同的方法
        A c = new C()
        A b = new B()

        现在都可以使用hello 这就是多态的美妙之处

        【讨论】:

          猜你喜欢
          • 2011-12-08
          • 2018-03-20
          • 2019-07-26
          • 1970-01-01
          • 2018-06-04
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-27
          相关资源
          最近更新 更多