了解Java中的继承和抽象类

时间:2010-12-10 23:42:17

标签: java inheritance interface

好吧所以我通过谷歌搜索文档,但是我没有找到任何真正描述我想要回答的内容,所以我在这里问你们。

所以我得到了继承,以及它是如何工作的。我遇到问题的有时候我看到一个对象最初定义为一种类型,并设置为不同的类型,我不明白究竟发生了什么。这是一个例子:

说我有一个类动物,并且分类猫和狗延伸动物。猫,动物和狗都有方法说(),对于猫打印“喵”和狗打印“woof”和动物“不能说话”。

好吧,所以最后这是我的问题。如果制作一只猫(c)然后运行Animal a = c,究竟会发生什么?如果我运行a.speak()会发生什么?哪种说法叫做?当我改变类型时到底发生了什么?我有没有真正的理由使用它?

就抽象方法而言,我的问题是拥有它们究竟是什么意思?在示例中,我已经看到它们已被放入超类中,其下的类定义了确切的行为。通过在超类中放置一个抽象方法,需要在其下面的所有类来实现它吗?

感谢您的帮助!

5 个答案:

答案 0 :(得分:3)

  

如果制作一只猫会发生什么   (c)然后运行Animal a = c;?什么   如果我运行a.speak();会发生?哪一个   说方法叫?到底是什么   当我改变类型时发生了   那?我会有任何真正的理由吗?   用这个?

始终是真实类的方法,例如在这种情况下,是cat的speak()方法。

  

就抽象方法而言,我的   问题究竟是什么意思   有他们吗?

他们确保,例如,每只动物都有一种方法walk(),你可以召唤每只动物。保修说“每个Animal对象都有这种方法,你不必关心它。”

  

在我的例子中   看到他们已被列入超级班   并且它们下面的类定义了   确切的行为。通过提出一个摘要   超类中的方法就是一个   要求其下的所有课程   实现它?

实现它或者是抽象的,是的。

答案 1 :(得分:2)

Cat c = new Cat(); 动物a = c; a.speak()将打印出来。

请检查java polymorphism

关于抽象类:

  

当抽象类被子类化时,   子类通常提供   所有的实现   父类中的抽象方法。   但是,如果没有,则为子类   也必须宣布为抽象。

JLS第5.2节解释了Cat可分配给Animal的原因。 (请注意,Animal不能隐式分配给Cat,因为Cat是“更具体”的类型; CatAnimal和{{1}的子类型是Animal

的超类型
  

将编译时引用类型S(源)的值分配给编译时引用类型T(目标)的变量,如下所示:

     
      
  • 如果S是班级类型:   
        
    • 如果T是类类型,则S必须与T相同,或者S必须是T的子类,否则会发生编译时错误。
    •   
    • 如果T是接口类型,则S必须实现接口T,否则会发生编译时错误。
    •   
    • 如果T是数组类型,则发生编译时错误。
    •   
  •   
  • 如果S是接口类型:   
        
    • 如果T是类类型,那么T必须是Cat,否则会发生编译时错误。
    •   
    • 如果T是接口类型,则T必须是与S相同的接口或S的超接口,否则会发生编译时错误。
    •   
    • 如果T是数组类型,则发生编译时错误。
    •   
  •   
  • 如果S是数组类型SC [],即SC类型的组件数组:
  •   
     

[为简洁省略]

答案 2 :(得分:1)

  

说我有一个类动物,并且分类猫和狗延伸动物。猫,动物和狗都有方法说(),对于猫打印“喵”和狗打印“woof”和动物“不能说话”。

     

好吧,所以最后这是我的问题。如果制作一只猫(c)然后运行Animal a = c;会发生什么?如果我运行a.speak();会怎样?调用哪个speak()方法?当我改变类型时到底发生了什么?我有没有真正的理由使用它?

Java中的对象确切地知道它们被创建的类型;它实际上是一个隐藏字段(可以使用Object.getClass()方法检索)。此外,所有非静态方法解析都从最具体的类的方法定义开始,并向最通用的类​​(Object)开始;因为在Java中只有单一的实现继承,所以这是一个简单的搜索。 Cat知道它是Animal的子类型,它是Object的子类型,而c知道它是Cat,与变量的类型无关。

执行分配时,编译器会检查分配的值的已知类型是否为分配给或其子类型的类型。如果是,则分配有效。如果不是,你需要一个显式的强制转换(在运行时进行正确的类型检查;强制转换不能破坏Java的类型系统,它们只会让它变丑)。它不会改变方法查找仍然是动态完成的事实,并且对象仍然知道它实际是什么类型;所有程序正在做的是忽略一些信息。 如果您了解C ++,那么将Java视为仅具有虚拟方法(和静态方法),并且处理对vtable的查找非常简单,因为继承钻石或其他恶意案例没有问题。

当使用接口的实现时,它几乎是相同的,除了进行更复杂的查找(即,首先查找vtable中的索引然后再继续之前)。但是,拥有一个实现接口的对象意味着必须有一些完全实现接口的类,这一点再次相对简单。请记住,所有非常复杂的东西都是在编译时完成的;在运行时,事情在所有情况下都相对简单。

那么,你会利用这些吗?好吧,你应该(你实际上发现在实际代码中很难避免)。根据接口或超类定义的合同来考虑这是一种好的方式,其中子类型在没有调用者必须知道细节的情况下遵守合同。 Java库非常重要,特别是因为合同类型细节的可见性及其实现可能不同。所有客户端代码都知道对象服从合同,它是给定类型的。

答案 3 :(得分:0)

根据你的背景,C ++或Java的东西会变得非常混乱。

在C ++中,存在虚函数的概念,在运行时查找它以决定函数属于哪个实际类。还有一些非虚函数将根据变量类型调用。

在Java中虽然所有方法都是虚拟的,这意味着Java方法总是在运行时查找,这个过程称为运行时多态

这样的好处是这样的

class Animal{
    public void type(){
        System.out.println("animal");

    }
}

class Dog extends Animal{
    public void type(){
        System.out.println("dog");
    }
}

class Cat extends Animal{
    public void type(){
        System.out.println("cat");
    }
}

public class Driver{
    public static void main(String[] args){
        Animal[] animals = new Animal[3];
        animals[0] = new Animal();
        animals[1] = new Dog();
        animals[2] = new Cat();

        for(Animal animal: animals){
            animal.type();
        }
    }
}

这将输出

animal
dog
cat

答案 4 :(得分:0)

据我了解,您使用接口来解耦代码。您希望针对接口进行编程,而不是实现:What does it mean to "program to an interface"?。您将使用抽象类来实现对所有实现类都很简单的functionlity,因此您不需要在所有实现类中编写它。