好吧所以我通过谷歌搜索文档,但是我没有找到任何真正描述我想要回答的内容,所以我在这里问你们。
所以我得到了继承,以及它是如何工作的。我遇到问题的有时候我看到一个对象最初定义为一种类型,并设置为不同的类型,我不明白究竟发生了什么。这是一个例子:
说我有一个类动物,并且分类猫和狗延伸动物。猫,动物和狗都有方法说(),对于猫打印“喵”和狗打印“woof”和动物“不能说话”。
好吧,所以最后这是我的问题。如果制作一只猫(c)然后运行Animal a = c,究竟会发生什么?如果我运行a.speak()会发生什么?哪种说法叫做?当我改变类型时到底发生了什么?我有没有真正的理由使用它?
就抽象方法而言,我的问题是拥有它们究竟是什么意思?在示例中,我已经看到它们已被放入超类中,其下的类定义了确切的行为。通过在超类中放置一个抽象方法,需要在其下面的所有类来实现它吗?
感谢您的帮助!
答案 0 :(得分:3)
如果制作一只猫会发生什么 (c)然后运行Animal a = c;?什么 如果我运行a.speak();会发生?哪一个 说方法叫?到底是什么 当我改变类型时发生了 那?我会有任何真正的理由吗? 用这个?
始终是真实类的方法,例如在这种情况下,是cat的speak()
方法。
就抽象方法而言,我的 问题究竟是什么意思 有他们吗?
他们确保,例如,每只动物都有一种方法walk()
,你可以召唤每只动物。保修说“每个Animal
对象都有这种方法,你不必关心它。”
在我的例子中 看到他们已被列入超级班 并且它们下面的类定义了 确切的行为。通过提出一个摘要 超类中的方法就是一个 要求其下的所有课程 实现它?
实现它或者是抽象的,是的。
答案 1 :(得分:2)
Cat c = new Cat(); 动物a = c; a.speak()将打印出来。
关于抽象类:
当抽象类被子类化时, 子类通常提供 所有的实现 父类中的抽象方法。 但是,如果没有,则为子类 也必须宣布为抽象。
JLS第5.2节解释了Cat
可分配给Animal
的原因。 (请注意,Animal
不能隐式分配给Cat
,因为Cat
是“更具体”的类型; Cat
是Animal
和{{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,因此您不需要在所有实现类中编写它。