【问题标题】:Inheritance concept in Java [duplicate]Java中的继承概念[重复]
【发布时间】:2015-05-12 07:34:20
【问题描述】:

这是一个相当基本的问题。但是我不能很好地理解继承的概念。

假设我有两个类,A 和 B,它们都有一个 test() 方法,分别返回 12,并且 B 继承了 A 类。在 main 方法中,我将实例声明为这样;

A a1 = new B();

并调用方法a1.test(),它将返回2。这就是多态性的概念。但是当我在子类中有一个方法test2() 时,我不能使用与上面相同的实例声明来调用该方法。为什么会这样?

【问题讨论】:

    标签: java inheritance


    【解决方案1】:

    我无法使用与上述相同的实例声明来调用该方法。为什么会这样?

    因为变量的类型是A,而类A没有方法test2()。 Java 编译器只查看变量的类型来检查您是否可以调用方法,而不查看实际的对象(在本例中为 B)。

    如果您为类使用更具体和更有意义的名称,而不是像AB 这样的抽象名称,这一切都更容易理解。让我们将它们称为 AnimalBear

    class Animal {
    }
    
    class Bear extends Animal {
        public void growl() { ... }
    }
    
    class Cat extends Animal {
        public void meow() { ... }
    }
    
    Animal a1 = new Bear();
    Animal a2 = new Cat();
    
    // Doesn't work, because not every Animal is a Bear, and not all
    // animals can growl.
    a1.growl();
    
    // You wouldn't expect this to work, because a2 is a Cat.
    a2.growl();
    

    【讨论】:

      【解决方案2】:

      因为变量类型是A,而A类没有方法test2():

      您可以使用:

      A a1 = new B(); // upcasting 
      B b1 = (B)a1; // Downcasting a1 to type B
      b1.test2(); // now you can call test2 function
      

      【讨论】:

        【解决方案3】:

        因为条件的左侧决定了可以调用哪个方法右侧决定了哪些方法可以调用称为。所以在这种情况下,A 类没有 test2() 方法。

        【讨论】:

          【解决方案4】:

          假设 A = "TV" 和 B = "HD_TV"。

          你可以说

          TV tv = new HD_TV() // HD TV
          

          TV tv = new TV() // ordinary TV
          

          因为 HD_TV 就是电视。

          你可以说:

          tv.show(movie) 
          

          它会显示电视上的内容,但使用高清电视可以获得更好的画面。

          你不能说:

          tv.showHD(hdMovie) // Compiler error !!!
          

          因为将tv 声明为TV,您是在说它可能不是高清电视。尽管您可以看到在这种情况下确实如此,但编译器仍然尊重您声明它只是一台电视并且您只能使用电视支持的方法。

          【讨论】:

            【解决方案5】:

            那是因为你将实例a1声明为A。因为B继承了A,所以你可以调用A中声明的所有函数,如果在B中重载它们可能会有不同的含义,但你没有可以访问仅限 B 的东西。

            如果您熟悉的话,您可以将第一个 A 视为某种头文件。它声明了 A 包含的内容,而不查看函数是如何实现的或 A 中所有内容的默认 var 是什么。直接的结果是,您只能访问声明为字面上在 A 中的所有内容。

            【讨论】:

              【解决方案6】:

              左侧——在本例中为A——是声明的类型,它不知道任何特定于子类的信息。右侧 - 在这种情况下为“B” - 是实际类型,它提供了行为。

              因此,这将起作用,因为声明的类型 B 知道 B 类中可用的方法。

              B b1 = new B();
              b1.test2();
              

              如果有可能拥有a1.test2(),那就意味着每个班级都必须知道它拥有的每个孩子——包括其他图书馆中的孩子,当项目组装时!

              【讨论】:

                【解决方案7】:

                当 B 继承 A 类并使用 B 的对象创建 A 的引用时,如 A a1 = new B();

                在编译时,java 编译器在类 A 中查找方法可用性。

                所以它允许调用方法test(),但不允许调用test2()。 由于test() 方法在A 类中可用,但test2()A 类中不可用。

                您可以键入像((B)a1).test2() 这样创建的对象。 这将起作用。

                【讨论】:

                  【解决方案8】:

                  这里 a1 对象属于 A 类型。a1 指向 B 类型的对象。 a1 是 A 类型对 B 类型对象的引用。

                  因为 a1 是 A 类型,它只知道已经在其类定义中声明的 test()。如果您想访问在 B 类中声明的 test2,您需要将 a1 对象类型转换回 B

                  喜欢 B b1 = (B)a1

                  b1.test2() 将可以访问。

                  【讨论】:

                    【解决方案9】:

                    发生这种情况是因为您声明了 A 变量并使用了 B 类,它是 A。编译器知道它是 A,但稍后在代码中不知道它是 B。以现实生活中的物体为例更容易。

                    例如你有:

                    class Pet() { 
                     method feed();
                    }
                    

                    还有一个

                    class Dog() extends Pet {
                     method feed();
                     method bark()
                    }
                    

                    如果你有其他类的代码:

                    如果你有代码:

                    Pet dogPet=new Dog();
                    

                    您知道这是一条狗,因为您创建了实例并且可以使用: ((Dog)dogPet).bark(); 或者只是将变量声明为狗而不是宠物。

                    但是如果你在另一个类中有一个方法:

                    void someMethod(Pet aPet){
                      // Here you don't know if the Pet is a dog or not. So you know only that it       
                      //can be fed but you don't know if it barks. Even if a Dog is supplied to the method
                    }
                    

                    【讨论】:

                      【解决方案10】:

                      a1 = new B() 中,创建的对象的实际类型是 B,但您将其作为超类型引用,因此您可以调用接受 A(多态性)的方法。

                      所以如果一个方法在子类中被覆盖,a1.test() 正在执行子类的test()

                      为了执行test2(),你必须这样做:((B) a1).test2();

                      【讨论】:

                        【解决方案11】:

                        有一个概念叫做向上转换和向下转换。向上转换是转换为超类型,而向下转换是转换为子类型。超强制转换总是被允许的,但是子强制转换涉及到类型检查并且会抛出 ClassCastException。,参见示例代码:

                        class A{
                        public int test(){
                         return 1;
                        }
                        }
                        
                        class B extends A{
                        
                        public int test(){
                         return 2;
                        }
                        
                        public int test2(){
                            return 3;
                        }
                        }
                        

                        A a1 = new B();
                        a1.test2();//not possible
                        

                        这里不能调用B类的方法。

                        【讨论】:

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