【问题标题】:Why should I reference the base class when I can access all the methods just as well by referencing the subclass?当我可以通过引用子类来访问所有方法时,为什么还要引用基类?
【发布时间】:2011-01-08 15:08:43
【问题描述】:

我正在学习 Java 概念。 我对java继承概念有疑问。 在继承中,我们可以将子类实例分配给基类引用 并且我们只能访问基类函数。 我们可以将继承层次结构中的任何子类实例分配给基类引用。对于分配给特定基类引用的实例类型,我们只能访问基类函数,我没有发现任何区别。

谁能给我一个实际的概念 为什么我们必须将子类实例分配给基类引用? 有什么必要这样做? 相反,我们可以从仅知道子类引用的子类引用中访问那些基类函数。

通过考虑特定的基类和层次结构中的许多子类来解释。

【问题讨论】:

    标签: java oop inheritance polymorphism


    【解决方案1】:

    您可能想要这样做的原因是为了创建更强大的设计。以 Java 中的集合框架为例。你有一个 List 接口,然后你有两个实现,ArrayList 和 LinkedList。

    您可以编写程序以专门使用 LinkedList 或专门使用 ArrayList。但是,您的程序随后取决于这些特定的实现。

    如果您将程序编写为依赖于超类型 List,那么您的程序可以适用于任一 List 实现。假设您想编写一个对 List 执行某些操作的方法,并且您编写了以下代码:

      public void doSomething(ArrayList a){}
    

    这个方法只能用 ArrayList 调用,不能用 LinkedList 调用。假设您想对 LinkedList 做同样的事情?然后你复制你的代码吗?没有。

      public void doSomething(List l){}
    

    将能够接受任一类型的列表。

    这背后的原理是程序到接口而不是实现。即List定义了所有列表的功能。

    有很多这种用法的例子。

    【讨论】:

      【解决方案2】:

      继承和多态是面向对象编程的基石,它们有几个不同的用途,简而言之:

      • 代码重用通过扩展具有特定功能的基类,
      • 界面设计通过提供一组抽象的功能,其中不同的实现是针对不同的需求量身定制的,并且
      • 封装通过隐藏在某些情况下不需要的特定功能

      等等。

      最后一点还强调了为什么人们可能会使用一组受限的功能,即使在实际实现提供的功能不止这些的情况下也是如此。以Collection 接口为例。通过使用这个接口,我们专注于isEmptycontainssize 等方法,而不是实际的实现。

      【讨论】:

        【解决方案3】:

        您所描述的是多态性的本质。这是一个来自希腊语的词,意思是“多种形式”。

        如果我给你一个像这样的简单层次结构,你可以看到测试代码如何从每个对象中获得不同的计算实现,而不用关心它正在处理什么样的 Shape:

        public interface Shape
        {
            double calculateArea();
        }
        
        class Circle implements Shape
        {
            private double radius;
        
            Circle(double r) { this.radius = r; }
        
            public double calculateArea() { return Math.PI*radius*radius; }
        }
        
        class Square implements Shape
        {
            private double side;
        
            Square(double s) { this.side = s; }
        
            public double calculateArea() { return side*side; }
        }
        
        // This would be a separate JUnit or TestNG annotated test.
        public class ShapeTest
        {
            @Test
            public void testCalculateArea()
            {
                Map<Shape, Double> expected = new HashMap<Shape, Double>()
                {{
                    put(new Circle(1.0), Math.PI);
                    put(new Square(1.0), 1.0);            
                }};
        
        
                for (Shape shape : expected.keySet())
                {
                    Assert.assertEquals(expected.get(shape), shape.calculateArea());
                }       
            }
        }
        

        【讨论】:

          【解决方案4】:

          Polymorphism.

          我是一个给你List&lt;String&gt;的方法。关于我实际上给你的东西,你只需要知道它是一个列表,并且具有列表的行为和语义,即你可以把东西放进去,它会保持它们的顺序,你可以迭代它.

          你不需要知道我是如何存储东西的,我是如何让它们被访问的,等等。这并不重要。对于您所关心的,它可能是LinkedList&lt;String&gt;ArrayList&lt;String&gt; 或全新的东西。可以这么说,我已经挑选了一些东西,你可以愉快地使用它。

          您是绝对正确的,当您使用继承来扩展类并添加新行为时,您需要引用子类才能访问它。这两种方法有些互补,但用例不同。

          【讨论】:

            【解决方案5】:

            假设 Vehiclebase 类,而 CarPlane子类时间>。假设 Vehicle 有一个方法 move()。

            汽车通过上路覆盖了这一点。飞机通过飞行覆盖了这一点。

            为什么 move() 应该是 Vehicle 基类的一部分?

            因为任何车辆都可以移动()。但是我们不能在 Vehicle 中实现 move() ,因为所有车辆的移动方式不同,即没有共同的行为。我们仍然希望在基类中使用它,以便我们可以具有多态行为,即我们可以编写如下代码。如您所见,只有一种名为 runVehicle(...) 的方法可以在任何 Vehicle 类上工作。

            void runVehicle(Vehicle v)
            {
              v.move();
            }
            
            Car c=new Car();
            runVehicle(c);
            
            Plane p=new Plane();
            runPlane(p);
            

            【讨论】:

              【解决方案6】:

              没有真正的需要这样做,除非 API 需要它。例如,如果在特定的 API 或代码库中有一个

              void ReallyUsefulFunction(BaseClass instance)
              

              如果您想使用,您可以从 BaseClass 派生一个类并在 SubClass 中实现其方法。然后您现在可以将子类传递给函数。

              不过,从技术上讲,您可以实现自己的

              void MyReallyUsefulFunction(MyClass instance)
              

              模仿相同的功能。但就像 MYYM 所解释的那样,代码重用等的好处可能是巨大的,这就是你想要利用多态性的时候。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2010-12-26
                • 2021-01-25
                • 2013-03-01
                • 1970-01-01
                相关资源
                最近更新 更多