Think in Java ---Chapter 8 多态 [基础的混凝土大厦]

  • 多态分离做什么和怎么做,从另一接口将接口和实现区分开来。
  • 多态即改善代码的组织结构和可读性,还可创建可扩展的程序,在创建项目时还是是后期扩展时都有用,与封装,继承相辅相成。
  • 想想多态的向上转型,因为在堆的对象结构中父类是作为子对象嵌套存在的,所以对象可以转成任一个子父对象来使用。即缩小了接口。
  • 使用向上转型的多态有点,可以让一个接受父类或者父抽象类或者接口作为类型的参数的方法可以操作许多派生类,而且可以按照子类是否重写等情况自动调用继承路径中的一个最低层方法,即在堆的对象结构中的最外层的重写方法。此处应该有图。有了多态这点就不用重载各种类型的参数了。
  • 将一个方法调用和一个方法主体关联起来叫做绑定,类似C语言可以在编译时绑定,叫静态绑定。java多态的向上转型后,使用动态绑定在运行时确定调用哪个方法,其实现是在堆对象结构内部查找。
  • java中除了static和final方法(包含private即带有final属性),其余的(成员方法)都是使用动态绑定(想想上面说的所有的实例方法调用都要进行堆对象内部查找,即从父类型开始,一层一层向外查找最后一个连续的重写方法)。因为static和final方法不会重写,关闭动绑查找机制。!!!!!!
  • 知道了上面的多态特点,就可以面向基类编程了,对基类发消息,然后让对象自己决定执行哪个方法。即项目为了扩展性,应该使用基类通信。
  • 如果要用到基类的默认实现,则把基类写成抽象类或者实体类;如果要声明接口例如用来RPC,则基类实现成接口。根据需求决定基类是啥。
  • 多态是程序扩展性一个必不可少的工具。无论是增加新子类还是在基类中添加新方法或者删减方法。
  • getClass().getName() 无论是在父类还是在子类调用,都是返回this引用即当前调用方法的对象的类名。
  • 如果父类有方法A、b, A调用B, 子类重写了方法B。 当子类调用方法A时,会调用B的方法,即无论如何,在说一遍:所有的实例方法调用都要进行堆对象内部查找,即从父类型开始,一层一层向外连续的查找最后一个重写方法
  • 看以下代码
public class Father{
    private void f(){System.out.println("private f");} 
    public static void main(String[] args){
        Father fa = new Child();
        fa.f();
    }
}
class Child extends Father{

    //@Override    

    public void f(){System.out.println("public f");}
}
//Output: private f

因为父类中的f方法是私有的,因此自带final属性,不会继承到子类中,因此子类中的f方法是个新方法,f不能被子类重写,因此按照上面一条说的按照多态查找规则的时候就停止在了父类的方法里。最后调用的是父类的私有方法。
连接以上知识组成一条规律,就是私有方法自带final属性 -> 私有方法不能被继承 -> 私有方法不能被重写 -> 子类中的同名方法是自己的方法 -> 按照多态声明引用指向对象时,调用父类的私有方法且不发生多态向下查找

  • 另外,代码中对成员变量的引用是静态绑定的,相比于方法的动态绑定而言。代码如下:
class Super{
    public int field = 0;
    public int getField() {  return field;  }
}
class Sub extends Super {
    public int field = 1;
    public int getField() {  return field;  }
    public int getSuperField() {  return super.field;  } //克服自动多态机制使用super显式调用父类成员变量。
}
public class Main{
    public static final void main(String args[]){
        Super sup = new Sub();
        System.out.println(sup.field + " " + sup.getField()); 
        Sub sub = new Sub();
        System.out.println(sub.field + " " + sub.getField() + sub.getSuperField());            
    }
}
//Output: 0  1   
// 1 1 0

实际上,对例如 sup.field 这种都是在编译阶段就确定的,即静态绑定,依据的是这个变量的显式声明类型。
而静态成员变量和静态方法不具有多态属性,因为他们都是存在于持久区中的,只拥有一份,是类的独有财产。即使用静态绑定。
想不明白的再看看上面的,然后总结出的终极口令就是:

父子出现重名时,父中私有不继承。实例变量静态定,实例方法运行时。不论变量或方法,静态成员都唯一。

其实,在实际中成员变量都应该使用方法来访问,因此就不会出现上面的问题。

  • 构造方法也是自带static,final属性的。在构造链中,是使用递归方式运作的。先构造父类是出于先构造好父类成员后让子类使用的目的。
  • 如果有类似dispose方法,则子类要先做自己的释放工作,如释放变量等,然后调用super.dispose方法。
  • 如果子类在释放时有变量是共享的,则在dispose方法中根据使用计数递减,并检查为0则释放。
  • 一个类被导入到方法区后,就知道多态相关的信息了,这句话是指,若在父类构造方法中调用父子共有的方法,则仍会多态查询,并且这时,因子类成员变量未初始化,调用的在子类中的重写方法若使用子类成员变量则会是清零值。!!!
  • 用继承表达行为间的差异,用字段表达状态上的变化。即结合使用组合和多态。在一个类中包含一个基类引用,基类引用的不同子类表示行为间的差异,同时也表示持有这个引用的类的状态的变化。
  • 子类的内容 >= 父类的内容。 ‘=’时为is - a关系,即子类不增加自己特有的方法。
  • 向下转型时可以使用instanceof方法,运行时类型识别(RTTI)会检查正确性,若有错误则会报ClassCastException。

转载于:https://www.cnblogs.com/yumingle/p/6664400.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值