多态在哪些场景不生效? -- 《JAVA编程思想》22

今天我们来聊聊在哪些场景下,多态是无法生效的。

如果对多态的介绍感兴趣,可查看上一篇文章:什么是多态?

下面直接进入正题,以下场景多态是无法实现的:

1.私有方法不能实现多态

public class Water {

    private void flow() {
        System.out.println("water flow");
    }

    public static void main(String[] args) {
        Water water = new River();
        water.flow();
    }
}
public class River extends Water {

    public void flow() {
        System.out.println("river flow");
    }

}
water flow

很显然,输出结果和预想中的不一致。private 方法默认是 final 的,final 方法不能被重写,对导出类 River 来说是屏蔽的,多态的实现依赖于方法重载,故多态在这里便失效了。在导出类中也应当避免与基类中的 private 方法同名,避免造成歧义。

2.域不适用多态

public class Water {

    public int speed = 10;

}
public class River extends Water {

    public int speed = 15;

    public int getSuperSpeed() {
        return super.speed;
    }

    public static void main(String[] args) {
        Water water = new River();
        System.out.println(" speed ==  " + water.speed);
        River river = new River();
        System.out.println(" speed ==  " + river.speed + " super.speed == " + river.getSuperSpeed());
    }

}

 speed ==  10
 speed ==  15 super.speed == 10

上述例子证明了多态在域中也无法实现。导出类在转换为基类时,任何域的操作访问的都是基类的存储空间。而导出类不仅拥有自身域的存储空间,还保留了基类的存储空间,哪怕字段名称一样,也是不同的存储空间,例子中第二个输出结果证明了此结论。

3.静态方法不适用多态

public class Water {

    public static void getName() {
        System.out.println("I am water");
    }

}
public class River extends Water {

    public static void getName() {
        System.out.println("I am river");
    }

    public static void main(String[] args) {
        Water water = new River();
        water.getName();
        River river = new River();
        river.getName();
    }

}
I am water
I am river

这个例子较为容易理解,因静态方法是直接与类进行绑定,而非与单个对象相关联,故多态也无法生效。

接下来,我们再来看看构造器中的多态行为。假设在基类构造器中调用多态方法,在导出类中会产生什么现象呢?

public class Water {

    public Water() {
        getName();
    }

    public void getName() {
        System.out.println("I am water");
    }

}
public class River extends Water {

    public int speed;

    public void getName() {
        System.out.println("I am river ,speed is " + speed);
    }

    public River(int speed) {
        this.speed = speed;
        System.out.println("river speed is " + speed);
    }

    public static void main(String[] args) {
           River river = new River(15);
    }
    
}
I am river ,speed is 0
river speed is 15

构造器默认是隐式的 static 方法,但确可以适用于多态。这里我们发现基类构造器调用 getName() 方法时,river 对象中的成员变量尚未完成初始化,直到导出类的构造方法调用时才完成初始化。

那么构造器中的初始化顺序究竟是怎么的呢?它们遵循以下顺序:

1.调用基类构造器,随后不断递归调用导出类的构造器,直到遇见最底层的导出类便停止递归(此时还不会调用最底层导出类的构造方法)

2.按声明顺序调用成员的初始化方法

3.调用最底层导出类构造器

这么做的原因是:必须确保基类的所有成员在任何导出类中都是有效的,所以必须优先调用基类的构造器。

本次分享至此结束,希望本文对你有所帮助,若能点亮下方的点赞按钮,在下感激不尽,谢谢您的【精神支持】。

若有任何疑问,也欢迎与我交流,若存在不足之处,也欢迎各位指正!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

BaymaxCS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值