【问题标题】:When instantiating a (sub)Class, is there any difference in what "type" you declare the object as?实例化(子)类时,您将对象声明为什么“类型”有什么区别吗?
【发布时间】:2013-01-16 15:44:22
【问题描述】:

假设我有一个名为 ParentClass 的类和一个名为 ChildClass 的类

ParentClass 是抽象的,ChildClass 根据 Java 术语扩展了 ParentClass。此外,ParentClass 有一个以int 为参数的构造函数。现在在另一个类中,我想实例化ChildClass。我尝试了以下两种方式:

  1. ChildClass obj1 = new ChildClass(5)
  2. ParentClass obj2 = new ChildClass(5)

Java 允许我使用上述两种方式中的任何一种。我的问题是,实际上有什么区别吗?如果我愿意,可以互换使用这两者吗?

【问题讨论】:

    标签: java inheritance subclass instantiation


    【解决方案1】:

    两者都有效,并且都在内存中创建了相同的对象。但只有第一个允许您使用 ChildClass 其他特定属性或 ParentClass 不知道的方法。

    例子:

    abstract class ParentClass{
       ...
    }
    
    class ChildClass extends ParentClass {
    
       public void SomeChildMethod(){ ... }
       ...
    }
    
    ...
    
    
    ChildClass obj1 = new ChildClass(5);
    ParentClass obj2 = new ChildClass(5);
    
    obj1.SomeChildMethod(); // ok
    obj2.SomeChildMethod(); // compilation error 
    ((ChildClass)obj2).SomeChildMethod(); // ok
    

    因此,仅当您确定永远不需要特定的子方法或属性(如果有)时,才使用第二种实例化方法。

    【讨论】:

      【解决方案2】:
      • 如果他们有相同的方法,只是孩子实现了 抽象方法那么没有任何区别。
      • 如果您添加了其他方法,那么孩子不会 如果您将其声明为父级,则可以访问。

      【讨论】:

        【解决方案3】:

        创建的对象实际上是相同的。

        第一种方法允许您使用ChildClass 中定义的方法,而不是ParentClass 中定义的方法。所以

           obj1.aMethodNotInParentClass();
        

        编译时

           obj2.aMethodNotInParentClass();
        

        没有。

        另外,使用第二种形式可以让您更轻松地将内部类替换为其他实现。如果你想使用AnotherChildClass 而不是ChildClass

              ParentClass obj2 = new AnotherChildClass(5);
        

        是您需要做的所有更改(假设类已正确定义);使用第一种方法可能需要在代码的其他地方进行一些更改。

        根据经验,将变量定义为更通用的类,该类定义(*)您需要的对象的所有方法。所以,如果你使用ChildClass中没有在ParentClass中定义的任何方法,就使用第一种,否则使用第二种。

        (*) 请注意,我提到的是定义,而不是实现。如果您覆盖 ChildClass 中的方法,您将使用该实现,因为创建的对象属于该类。

        【讨论】:

          【解决方案4】:

          在内存中将使用完全相同的对象。但是,您只能使用变量obj2,就好像它包含一个ParentClass 对象一样,而不会理所当然地认为ChildClass 类的所有出色功能。如果ChildClass 声明了一个方法f(),但ParentClass 没有,则调用obj2.f() 将不起作用——尽管内存中的对象可以很好地运行该方法。

          【讨论】:

            【解决方案5】:

            第二种选择只允许使用在 ParentClass 中声明的方法。例如:

            public class ParentClass {
                public void doX() {}
            }
            
            public class ChildClass {
                public void doY() {}
            
                public static void main() {
                    ParentClass p = new ChildClass();
                    ChildClass c = new ChildClass();
                    p.doX(); //works
                    c.doX(); //works
            
                    p.doY(); //not allowed
                    c.doY(); //works
            
            
                    ((ChildClass) p).doY(); //this way you cast the object to ChilClass and can use its methods.
            
                }
            }
            

            【讨论】:

              【解决方案6】:

              是的,有区别。 第一种方法使用动态绑定为您提供一个子实例作为父对象。这只会为您提供父对象在子实例上的功能。 第二种方式会给你一个子对象的实例作为子对象,允许你使用它的所有方法和它的父对象的方法,而不是局限于父类的方法。

              【讨论】:

                猜你喜欢
                • 2016-11-12
                • 1970-01-01
                • 1970-01-01
                • 2019-12-10
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2013-07-12
                • 1970-01-01
                相关资源
                最近更新 更多