回顾一下上次的图:
如果我们这样写,你会不会感觉很奇怪:
Animal anim = new Animal();
那么有哪一种动物叫做animal?
那么实例变量会是啥?
有些类不应该被初始化!
那要如何处理这个问题呢?我们一定是要有Animal这个类来继承和产生多态。但是要限制只有它的子类才能够被初始化。我们要的是cat、dog对象,而不是Animal对象。
幸好,有个方法可以防止类被初始化。换句话说,就是让这个类不会被“new”出来。通过标记类为抽象类的,编译器就知道不管在哪里,这个类就是不能创建任何类型的实例。
你还是可以用这种抽象的类型作为引用类型。这也就是当初为何要有抽象类型的目的。
看如下代码:
抽象类除了被继承过之外,是没有用途,没有值的。
抽象和具体
不是抽象的类就被为称为具体类。在Animal的继承树下,如果我们创建出Animal是属于抽象类,那么dog、cat属于具体类。
查阅Java API你就会发现其中很多的抽象类,特别是GUI的函数库中更多。GUI的组件类是按钮、滚动条等与GUI有关的父类。你只会对组件下的具体子类作初始化动作。
抽象的方法
除了类以外,你还可以将方法标记成abstract的。抽象的类代表此类必须要被extend过,抽象的方法代表此方法一定要被覆盖过。你或许会认为抽象类中的某些行为在没有特定的运行时不会有任何的意义。也就是说,没有任何通过的实现是可以行。
抽象的方法没有实体!
因为你已经知道编写出抽象方法的程序代码没有意义,所以不会含有方法。
如果你声明出一个抽象的方法,就必须将类也标记为抽象的。你不能在非抽象类中拥有抽象的方法。
就算只有一个抽象的方法,此类也必须标记为抽象的。
那么:
- 为什么要有抽象的方法?我认为抽象类的重点就在于可以被子类继承的共同程序代码。
将可继承的方法体(也就是有内容的方法)放在父类中是一个好主意。但有时候就是没有办法作出给任何子类都有意义的共同程序代码。抽象方法的意义就是算是无法实现出方法的内容,但还是可以定义出一组子类型共同的协议。 - 这样的好处是?
就是多态!记住,你想达成的目标是要使用父类型作为方法的参数、返回类型或数组的类型。通过这个机制,你可以加入新的子类到程序中,却又不必重写或者修改处理这些类的程序。想象一下如果不是使用Animal作为Vet的方法参数程序会写成什么样子·····你必须为每一种动物写出不同的方法!因此多态的好处就在于所有子类都会有那些抽象的方法。
你必须实现所有抽象的方法
实现抽象的方法就如同覆盖过方法一样
抽象的方法没有内容,它只是为了标记出多态而存在。这表示在继承树结构下的第一个具体类必须要实现出所有的抽象方法。
然而你还是可以通过抽象机制将实现的负担转给下层。例如说将Animal与Canine都标记为abstract,则Canine就无需实现出Animal的抽象方法。但具体的类来说,例如说Dog,就要实现出Aninmal和Canine的抽象方法。
记得抽象类可以带有抽象和非抽象方法,因此Canine也可以实现Animal的抽象方法,让Dog不必实现这个部分。如果Canine
没有对Animal的抽象类表示出意见,就表示Dog的自己实现出Animal的抽象方法。
当我们谈到“你必须实现所有抽象的方法”时,表示你必须写出内容。你必须以相同的方法鉴明(名称和参数)和相容的返回类型创建出非抽象的方法。Java很注重你的具体子类有没有实现这个方法。