《Java编程思想》笔记08-多态

在面向对象的程序设计语言中,多态是继数据抽象继承之后的第三基本特征。

多态也称作动态绑定后期绑定运行时绑定

绑定

将一个方法调用同一个方法主体关联起来被称作绑定

若在程序执行前进行绑定(如果有的话,由编译器和连接程序实现),叫做前期绑定。C语言只有前期绑定。

后期绑定也叫做动态绑定或运行时绑定。含义就是在运行时根据对象的类型进行绑定。

Java 中除了 static 方法和 final 方法(private 方法属于** final 方法)之外,其他所有方法都是后期绑定**。

缺陷

“覆盖”私有方法

私有方法不可以被覆盖,但子类中存在于父类私有方法名称一致时,也不会报错,但多态会无效。

所以子类中最好不要存在于父类私有方法名称一致的方法

域于静态方法

多态只对“方法”有效,对“字段”无效。子类向父类转型后,直接访问字段,返回值是父类的字段值。一般所有的字段都是 private,所以一般不会有什么影响。同样最好不要给基类和子类设置同名字段,也不会出现问题。

如果某个方法是静态的,它的行为就不具有多态性。因为静态方法是于类,而并非与单个的对象关联的。

final 方法

可以防止其他人覆盖该方法,更重要的一点是可以有效的“关闭”动态绑定,或者说,告诉编译器不需要对其进行动态绑定。

继承与清理

销毁的顺序应该和初始化的顺序相反,先清理子类,再清理父类。

AndroidActivityonDestroy 方法。

@Override
protected final void onDestroy() {
    doDestroy();
    super.onDestroy();
}

如果成员对象中存在于其它一个或多个对象共享的情况,问题就复杂了。这种情况下,也许就必须使用引用计数来跟踪仍旧访问着共享对象的对象数量了,当共享它的对象全部 dispose,引用计数为 0 时,才会 dispose。

//: polymorphism/ReferenceCounting.java
package polymorphism; /* Added by Eclipse.py */

// Cleaning up shared member objects.
import static net.mindview.util.Print.*;

class Shared {
    private int refcount = 0;
    private static long counter = 0;
    private final long id = counter++;

    public Shared() {
        print("Creating " + this);
    }

    public void addRef() {
        refcount++;
    }

    protected void dispose() {
        if (--refcount == 0)
            print("Disposing " + this);
    }

    public String toString() {
        return "Shared " + id;
    }
}

class Composing {
    private Shared shared;
    private static long counter = 0;
    private final long id = counter++;

    public Composing(Shared shared) {
        print("Creating " + this);
        this.shared = shared;
        this.shared.addRef();
    }

    protected void dispose() {
        print("disposing " + this);
        shared.dispose();
    }

    public String toString() {
        return "Composing " + id;
    }
}

public class ReferenceCounting {
    public static void main(String[] args) {
        Shared shared = new Shared();
        Composing[] composing = { new Composing(shared), new Composing(shared),
                new Composing(shared), new Composing(shared),
                new Composing(shared) };
        for (Composing c : composing)
            c.dispose();
    }
} /*
 * Output:
 * Creating Shared 0
 * Creating Composing 0
 * Creating Composing 1
 * Creating Composing 2
 * Creating Composing 3
 * Creating Composing 4
 * disposing Composing 0
 * disposing Composing 1
 * disposing Composing 2
 * disposing Composing 3
 * disposing Composing 4
 * Disposing Shared 0
 */// :~

构造器内部的多态方法的行为

如果在一个构造器的内部调用正在构造的对象的某个动态绑定方法,那会发生什么情况呢?

class Glyph{
    void draw(){System.out.println("Glyph.draw()");}
    Glyph(){
        draw();
    }
}
class RoundGlyph extends Glyph{
    private int radius = 1;
    Roundglyph(int r){
        radius = r;
        System.out.println("Roundglyph.Roundglyph(), radius=" + radius);
    }
    void draw(){
        System.out.println("Roundglyph.draw(), radius=" + radius);
    }
}
public class PolyConstructors{
    public static void main(String[] args){
        new RoundGlyph(5);
    }
}/* output:
Roundglyph.draw(), radius=0
Roundglyph.RoundGlyph(), radius=5
*/

基类 Glyph 的构造器调用 draw() 方法时,radius 还没有被初始化,不是 1,而是 0。这可能导致程序无法正常运转。

重提类的初始化顺序

  1. 在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制的 0
  2. 子类默认递归调用基类构造函数
  3. 成员字段和成员函数初始化,优先处理静态成员
  4. 最后调用自身构造函数

编写构造器时有一条有效的准则

“用尽可能简单的方法使对象进入正常状态;如果可以的话,避免调用其它方法”。构造器中唯一能够安全调用的那些方法是基类中的 final 方法(也适用于 private 方法,它们自动属于 final 方法)

协变返回类型

Java SE5 中添加了协变返回类型,它表示在子类中的被覆盖方法可以返回基类方法的返回类型的某种子类型



转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 bin07280@qq.com

文章标题:《Java编程思想》笔记08-多态

文章字数:1.1k

本文作者:Bin

发布时间:2018-03-27, 20:38:01

最后更新:2019-08-06, 00:46:42

原始链接:http://coolview.github.io/2018/03/27/Java%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3/%E3%80%8AJava%E7%BC%96%E7%A8%8B%E6%80%9D%E6%83%B3%E3%80%8B%E7%AC%94%E8%AE%B008-%E5%A4%9A%E6%80%81/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录