OOP语言中,多态是封装、继承以后的第三种基本特征。程序员
封装:经过合并特征和行为来建立新的数据类型,“实现隐藏”经过细节“私有化”把接口和实现分离。安全
继承:以复用接口方式从已有类型用extends关键字建立新类型,并容许向上转型。spa
多态:消除类型之间的耦合关系(分离作什么和怎么作),基于继承的向上转型功能,容许同一种类型同一行为有不一样的表现。设计
8.1再论向上转型对象
8.1.1忘记对象类型继承
无论导出类的存在,编写的代码(方法)只是针对基类类型。不须要为每一个导出类型都写各自的代码,这正是多态所容许的。接口
8.2起色内存
程序运行时接受的是基类类型,可是它如何知道具体类型是哪个从而调用正确的方法呢?咱们须要了解绑定机制。编译器
8.2.1方法调用绑定io
把方法调用同方法主体关联起来称为绑定。
前期绑定:程序执行前绑定(由编译器和链接程序实现),C语言中方法调用都是前期绑定。
后期绑定:又叫动态绑定,运行时绑定,在运行时根据对象的类型绑定对应的方法主体。
Java中默认就是动态绑定,无需手动设置。特殊:static方法和final(private也是final)方法不存在多态性,不是动态绑定。
8.2.2产生正确行为
动态绑定使得多态中的基类对象能够正确执行相应的导出类对象方法。
8.2.3可扩展性
多态使得扩展新类型和扩展基类不会对已有代码(调用基类方法的代码)产生影响。它可让程序员“将改变的事物与不变的事物分离开”。
8.2.4缺陷:不能够覆盖private方法
基类中private方法在子类中能够用相同的方法名和签名,可是它是一个全新的方法,不会按照咱们想要的子类方法来执行。
调用的时候,按照基类方法的访问权限来决定是否能够调用。
子类是否会覆盖父类方法,按照子类是否能够访问到父类该方法来决定是否能够覆盖。
8.2.5缺陷:域与静态方法
多态特性(动态绑定)只是针对方法的。域和静态方法不具备这种特性。
如:父类和子类都有一个域 public String str; 在Super s = new Sub(); s.str 取出的是Super里的而不是Sub里的。 不过通常状况不会存在这种把域设置为public而且想用子类覆盖它的状况。
静态方法也不会有多态性。
8.3构造器和多态
构造器是隐式static方法,不具备多态特性。
8.3.1构造器的调用顺序
为何编译器强制每一个导出类的构造器必须调用基类构造器呢:由于构造器有个特殊的任务,检查对象是否被正确构造。导出类构造器只能访问它本身的成员,不能访问基类的成员(一般是private成员)。只有基类构造器才具备相应的知识和权限对本身的元素进行初始化。而导出类成员的初始化有可能会用到基类成员,所以导出类初始化在基类以后。
8.3.2继承与清理
经过组合和继承方式建立新类时,一般状况都是不须要担忧对象的清理问题。
可是若是的确须要作清理时,必须很是当心谨慎:在使用完以后按照建立逆序清理,即sub.dispose()而后super.dispose()来清理。
更加复杂的状况:不知道何时使用结束,须要本身定义引用计数,而后再清理。
8.3.3构造器内部的多态方法行为
在调用子类构造器的过程当中,会先调用父类构造器,此时子类构造器还没调用完成,子类对象也没有执行初始化,若是在父类构造器里调用多态方法,那么这个方法是能够产生多态行为特征的,可是因为子类构造器没有执行完,所以子类的初始化还没完成,多态方法里对子类成员变量的获取只能拿到默认值0,false,null
对象初始化过程(注意与类的加载过程区分):
1.给导出类对象分配内存空间,并初始化为0,false,null
2.调用父类构造器,并执行多态方法,拿到的是子类0,false,null的域
3.按照声明顺序调用成员变量的初始化
4.调用子类构造器主体
此处虽然逻辑没什么问题,可是行为的确错误了,因此在写构造器的时候,咱们要尽量用简单的方法使对象进入正常状态,若是能够的话避免调用其余方法。
8.4协变返回类型
导出类重写父类方法,方法的返回类型(区分返回值)能够是父类返回类型的某一个导出类。
8.5用继承进行设计
就建立新类型而言,不要只想到继承,应该优先考虑组合,它比继承具备更大的灵活性,能够动态的改变类型,而继承在编译时类型已经肯定了。
8.5.1纯继承与扩展
纯粹的继承:基类接口与导出类彻底一致,是is-a关系
扩展:导出类除了基类接口外,还有其余方法,是is-like-a关系,可是这些扩展方法不能以基类引用去调用
8.5.2向下转型与运行时类型识别
向上转型是安全的:基类不会有大于导出类的接口
向下转型须要确保类型的正确性:Java中类型转换(括号强转)都会进行类型检查,不正确抛出ClassCastException。这种在运行期间对类型进行检查的行为称做“运行时类型识别”(RTTI)。
8.6总结
多态意味着“不一样的形式”。在OOP里,咱们持有基类的相同接口,使用该接口的不一样形式:不一样版本的动态绑定。