Java编程思想简要笔记——第八章 多态

多态的一些定义和属性

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

  2. 多态通过分离做什么和怎么做来将接口和实现分离开来。

  3. “封装”通过合并特征和行为来创建新的数据类型。“实现隐藏”则通过将细节“私有化”把接口和实现分离开来。

  4. “多态”的作用是消除类型间的耦合。

  5. Java中除了static和final方法(private 方法属于final方法)外,都是后期绑定的。

  6. 多态通过后期绑定实现,提高了其可扩展性。

  7. 导出类无法覆写基类的私有方法,最好改为不同的名字。

  8. 父类声明引用指向子类对象时,调用覆写方法,其实调用的还是子类的,调用被覆盖的域时父类的。

  9. 静态方法是跟类关联的,无所谓多态性,所以不能用@override修饰。

其中8,9两条可以看下面的代码作为证明。

/**
 * PolymorphismTest
 * @author kiba
 * @since 2020/2/8 
 */
public class PolymorphismTest {
    public static void main(String[] args) {
        Base derived = new Derived();
        Derived derived1 = (Derived) derived;
        System.out.println("field - derived.value:" + derived.value);
        System.out.println("method - derived.getValue():" + derived.getValue());
        System.out.println("field - derived1.value:" + derived1.value);
        System.out.println("method - derived1.getValue():" + derived1.getValue());
        System.out.println("Base static method - Base.getString():" + Base.getString());
        System.out.println("Derived static method - derived.getString():" + Derived.getString());
    }
}

class Base {
    public int value = 0;

    public static String getString() {
        return "Base";
    }

    public int getValue() {
        return value;
    }
}

class Derived extends Base {
    public int value = 1;

    // @Override 静态方法关联的是类,无所谓多态性,这块写override会报编译错误
    public static String getString() {
        return "Derived";
    }

    @Override
    public int getValue() {
        return value;
    }
}

构造器与多态

具有继承关系的构造器调用顺序可以通过下面的代码进行总结。

/**
 * Sandwich
 * @author kiba
 * @since 2020/2/8 
 */
public class Sandwich extends PortableLunch {
    private Bread bread = new Bread();
    private Cheese cheese = new Cheese();
    private Lettuce lettuce = new Lettuce();

    public static void main(String[] args) {
        new Sandwich();
    }

    public Sandwich() {
        System.out.println("SanWich()");
    }
}

class Meal {
    Meal() {
        System.out.println("Meal()");
    }
}

class Bread {
    Bread() {
        System.out.println("Bread()");
    }
}

class Cheese {
    Cheese() {
        System.out.println("Cheese()");
    }
}

class Lettuce {
    Lettuce() {
        System.out.println("Lettuce()");
    }
}

class Lunch extends Meal {
    Lunch() {
        System.out.println("Lunch()");
    }
}

class PortableLunch extends Lunch {
    PortableLunch() {
        System.out.println("PortableLunch()");
    }
}
  1. 调用基类构造器
  2. 按声明顺序调用域的初始化方法
  3. 调用导出类的构造器主题

继承与清理

当覆盖被继承类的dispose方法时,必须调用父类的dispose方法,否则基类清理动作将不会发生。

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

构造器不应调用可覆写方法。具体原因见上一篇博客《在构造方法内不应调用可被覆写的方法》

协变返回类型

Java SE5新增特性,他表示导出类中的被覆盖方法可以返回基类方法的返回类型的某种导出类型,测试代码如下。

package xlab.thinkinginjava.chapter08polymorphism;

class A {
    public C method() {
        return new C();
    }
}

class B extends A {
    @Override
    public D method() {
        return new D();
    }
}

class C {

}

class D extends C {

} 

用继承进行设计

  1. 优先考虑组合的设计思路
  2. 用继承表示行为间的差异,并用字段表达状态上的变化。(这句话真的没看懂。。。)

纯继承与扩展

继承是is-a的概念,扩展接口是is-like-a的概念,如果向上转型会丢掉导出类的扩展接口。

向下转型和类型识别

向下转型失败时,会抛出ClassCastException异常,最好能做一下instanceOf。


测试代码路径:
https://github.com/kiba-zwei/ThinkingInJava/tree/master/src/xlab/thinkinginjava/chapter08polymorphism

发布了20 篇原创文章 · 获赞 13 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/kiba_zwei/article/details/104228718
今日推荐