您的位置:首页 > 编程语言 > Java开发

第八章:接口与抽象类-深入多态

2018-02-06 14:29 190 查看
该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动!

第八章:接口与抽象类-深入多态

继承只是个开始:

    要使用多态,我们还需要接口(OC里叫协议,是不是瞬间就理解了);
    我们需要超越简单的继承并前进到通过设计和编写接口规格才能达成的适应性和扩展性;

接口是一种100%存抽象的类,抽象类就是无法初始化的类;
接口是多态和Java的重点;

父类中的接口定义的是继承体系中的共同协议;
任何子类类型都能够传递给取用父类类型的方法来执行;

示例:
Animal anim = new Animal();这个就会很奇怪;哪有一种叫做Animal的动物;
我们要说明的是“有些类不应该被初始化”;
    Animal这个类需要被继承和产生多态,同时还要限制他的子类才能被初始化;

标记抽象类:

    防止类被初始化(就是不能被new出来);
    通过标记为抽象类,这个类就不能创建任何类型的实例;
    
这种抽象的类型可以作为引用类型——这也是当初为何要有抽象类型的目的;

设计抽象类——在类声明前使用关键词abstract;
    abstract class Animal{}
    abstract class Dog extends Animal{}

可以使用抽象类来声明引用类型给多态使用;
抽象类畜类被继承过之外,是没有用途、没有值、没有目的的;

不是抽象的类被称为具体类;

abstract:

    除了作用在类上,还可以将方法标记为abstract;
    抽象的类代表此类必须要被extend过,抽象的方法代表此方法一定要被覆盖过;
    抽象的方法则没有实体;
        public abstract void eat();

如果声明了一个抽象的方法,则必须将类也标记为抽象的;不能在非抽象类中拥有抽象方法;

抽象方法的意义:

    将可继承方法体放在父类中是个好主意,但有时无法做出任何子类都有意义的共同程序代码;
    抽象方法的意义在于,就算无法实现出方法的内容,但还是可以定义出一组子类型共同的协议;

这样做的好处就是——多态:
    我们要达成的目标就是:要使用父类型作为方法参数、返回值类型或数组的类型;

实现抽象方法就如同覆盖过方法一样:
    抽象的方法没有内容,他只是为了标记出多态而存在;
    这表示继承树下的第一个具体类必须要实现出所有的抽象方法;
    一个抽象类可以继承自另一个抽象类;
    覆盖时需要以相同的方法签名(名称和参数)和相容的返回类型创建出非抽象的方法;

万用类——通过对象这个类型来操纵所有类型的对象?

在Java中所有的类都是从Object这个类继承出来的:

    Object是所有类的源头,是所有类的父类;
    没有直接继承过其他类的类都会是隐含的继承对象,最终都是继承自Object的;

终极对象的行为:
1)equals()
2)getClass()
3)hashCode()
4)toString()    

Object类不是正式的抽象类,因为他为所有子类继承的方法都提供了实现,它没有必须被覆盖过的方法;
可以覆盖Object的方法(final修饰的除外);
Object可以被创建,对应的是一个轻量化的对象,常用在线程同步上(后续会介绍);

Object的两个目的:

1)作为多态让方法可以应付多种类型的机制;
2)提供Java在执行期间对任何对象都有需要的方法的实现(让所有类都继承到);

Java是类型检查很强的语言,编译器会根据你调用的是否是该对象确实可以响应的方法(你只能从确实有该方法的类去调用);

使用Object类型作为引用的一些问题:
1)任何从ArrayList<Object>取出的东西都会被当做Object类型的引用而不管它原来是什么;
2)把所有东西都以多态来当做Object会让对象看起来失去了真正的本质(但不是永久性的);

由于编译器是根据引用类型来判断有哪些method可以调用,而非根据Object确实的类型;所以需要将对象转换回原来的类型;

多态意味着多种形式:
    如果引用是个遥控器,则当在继承树往下走时,会发现遥控器的按钮越来越多;

转换回原来的类型:

    Object o = list.get(index);
    Dog d = (Dog)o;
    不能确定o是Dog,可以使用instanceof这个运算符来检查;若类型转换错了,则会在执行期遇到ClassCastException异常并终止;
    if(0 instanceof Dog){
        Dog d = (Dog)o
    }    

只能在引用变量的类确实有该方法才能调用它;把类的公有方法当做是合约的内容,合约是你对其他程序的承诺协议;
    
合约包括继承树中之前继承链上的所有父类的方法;

接口:

    以宠物行为举例,在Animal的继承树中,我们希望小猫小狗可以执行宠物的行为,但狮子老虎不行;
    我们需要一种方法:
    1)一种可以让宠物行为只应用在宠物身上的方法;
    2)一种确保所有宠物的类都有相同的方法定义的方法;
    3)一种可以运用到多态的方法;

感觉我们需要两个父类,让Dog即继承Animal又继承宠物Pet;——但Java不支持多重继承,因为它会引入经典的菱形问题(致命方块);

接口是我们的救星!

接口(interface):

    此接口可以用来解决多重继承的问题却又不会产生致命方块的问题;
    方法是:把全部的方法设为抽象的;
    Java的接口就好像100%的纯抽象类;

接口的定义:使用interface代替class;
    public interface Pet{}

接口的实现:使用implements关键字;
    public class Dog extnds Animal implements Pet {}
        

设计和实现Pet接口:

    就是添加一堆public和abstract的方法;(这两个修饰是可选的)
    注意这些方法没有实现,以“;”结尾;
    接口实现的时候必须在类中实现定义的方法(这是合约的规定);

接口的存在是为了实现多态,接口有无比的适用性;
    可以使用接口取代具体的子类或抽象的父类作为参数或返回值类型;
    可以传入任何实现该接口的东西;
    
不同的继承树可以实现相同的接口;
同一个类可以实现多个接口;(… implements Pets,Pet2,…)

允许不同继承树的类实现共同的接口对Java API来说十分重要:
    将对象的状态保存到文件,实现Serializable这个接口;
    让对象的方法以单独的线程来执行,实现Runnable;

extends只能有一个,implement可以有好多个;

要如何判断应该是设计类、子类、抽象类或接口呢?

1)如果新的类无法对其他的类通过IS-A测试时,就设计不继承其他类的类;
2)只有在需要某类的特殊化版本时,以覆盖或增加新的方法来继承现有的类;
3)当你需要定义一群子类的模板,又不想让程序员初始化此模板时,可以设计出抽象类给他们用;
4)如果想要定义出类可以扮演的角色,使用接口;

调用父类的方法:

    super关键字能够在子类中调用父类的方法;

要点:

1.如果不想让某个类被初始化,就以abstract关键字把它标记为抽象的;
2.抽象的类可以带有抽象和非抽象的方法;
3.带有抽象方法的类,必是抽象类;
4.抽象的方法没有内容,声明以分好结尾;
5.抽象的方法必须在具体的类中运行;
6.Java所有的类都是Object(java.lang.Object)直接或间接的子类;
7.方法可以声明Object的参数或返回类型;
8.不管实际上所引用的对象是什么类型,只有在引用变量的类型就是带有某方法的类型时才能调用该方法;
9.Object引用变量在没有类型转换的情况下不能赋值给其他的类型,若堆上的对象类型与要转换的类型不兼容,则此转换会产生异常;
10.Java不允许多重继承;
11.接口像100%抽象类,以interface这个关键词取代class来声明接口;
12.实现接口使用implements这个关键词;
13.class可以实现多个接口;
14.实现某接口的类必须实现它所有的方法,因为这些方法都是public和abstract的;
15.要从子类调用父类的方法可以用super这个关键字来引用;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Java基础