java怎么还是那么渣O(∩_∩)O哈哈~父类与子类关系怎么那么复杂

哈哈,今天又来更新博文了,又有疑惑得到解决了,分享给还懵懂不清的同学,嘻嘻。

在看到继承这一章的时候,有很多很高大上的概念,比如,多态,动态绑定,还有向上转型,不要想的太复杂,很简单。

我们首先定义一些代码来说明问题:

public class Father{
    private String name;
    private int age;
    public void Sleep(){
    }
}
public class Son extends Father{
    private String grade;
    public void Sleep(){
    }
    public void Sleep(Date time){
    }
}

定义主函数中的代码:

public void main(String[] args){
    Father father = new Father();//true
    Son son = new Son();//true

    Father father02 = new Son();//true(这个就是传说中的“向上转型”)
    Son son02 = new Father();//false(这样转换是错的,如果不知道为什么,我们可以换成这样:
    //Manager ma = new Employee();
    //这里的Manager类继承自Employee类
    //这样是错的,如果是对的话就表示所有的雇员都是经理,但事实上这是不可能的事

    Son son03 = (Son)father02;//true;
    //这样为什么是对的呢?因为上面的father02引用指向的对象是Son的实例化对象,所以这里转换是可以的
    Son son04 = (Son)father;//false
    //这里错的原因就在于引用father指向的对象是Father的实例化对象,所以这里这样转换是错的
}

这里写图片描述

不清楚要什么情况引用应该指向哪个对象的话,可以看这张图,上层的可以做引用,下层的只能当引用指向的对象。

解决了上面一些疑惑之后,我们再来说说继承中多态中方法的动态绑定,动态绑定呢其实也就是后期绑定,在java中,方法的绑定分为前期绑定和后期绑定,前期绑定这个是默认执行的,因此,如果单纯只有前期绑定的话,那么在多态中,只有一个引用的情况下,就像上面代码中父类和子类都有签名一样的方法Sleep(),如果:

Father father = new Son();
father.Sleep();

这样前期绑定是不知道该执行哪个方法的,所以,解决的方法就是后期绑定,后期绑定在运行时根据对象的类型进行绑定,而前期绑定在编译的时候进行绑定,所以后期绑定也叫作动态绑定或者是运行时绑定。然而,动态绑定不需要程序员操控,它会自动发生。

java中除了static还有final以及private定义的函数之外,其他方法都是后期绑定的,static方法只能由类本身调用,而不是由类的实例化对象调用,而final方法只存在于父类中不允许子类覆写,子类不能覆写了,因此在指向子类的引用中调用父类的方法的时候不用再去考虑子类是否覆写了方法,因此这时候不需要动态绑定的参与。而private方法其实只能由父类本身调用,因此指向子类的引用调用方法的时候也不需考虑到子类有没有相同签名的方法。

我们要知道的是,指向子类对象的父类类型引用在调用方法的时候,如果父类中的方法被子类覆写的话,调用的方法是在子类中被覆写的方法。

package test02;

public class Father {
    public void Sleep(){
        System.out.println("爸爸在睡觉");
    }
}

package test02;

public class Son extends Father{
    public void Sleep(){
        System.out.println("儿子在睡觉");
    }

}

package test02;

public class Main {
    public static void main(String[] args){
        Father father = new Son();
        father.Sleep();
    }
}

这里写图片描述

但是有些情况要注意,
如果我改成这样的话:

package test02;

public class Father {
    private void Sleep(){
        System.out.println("爸爸在睡觉");
    }
}

package test02;

public class Son extends Father{
    private void Sleep(){
        System.out.println("儿子在睡觉");
    }

}

package test02;

public class Main {
    public static void main(String[] args){
        Father father = new Son();
        father.Sleep();
    }
}

这里写图片描述
代码提示说父类中的Sleep()是不可见的,这个意思呢不是说因为引用是父类类型的,子类覆写了父类中的方法,所以程序照理应该调用子类中覆写的那个方法,但是由于引用是父类类型,所以不能调用子类中的private方法,不是这样,是父类中的Sleep()是private,对外不可见,所以子类既然继承了父类,所以这个方法是不能被覆写的。这才是错误的原因。

还有,如果子类覆写父类方法时擅自更改方法限制也是错误的:

public class Father{
    public void Sleep(){
    }
public class Son extends Father{
    private void Sleep(){
    }

这里写图片描述

反正总结一点,就是方法签名相同的情况下,返回类型就得相同,方法限制符也得相同。无论如果,如果你想在子类中重载Sleep()函数,可以,但是一定要有Sleep()函数的签名和返回类型以及限制符跟父类方法是一模一样的

package test02;

public class Father {
    public String name="爸爸";
    public void Sleep(){
        System.out.println("爸爸在睡觉");
    }
}

package test02;

public class Son extends Father{
    private String name="儿子";
    public void  Sleep(){
        System.out.println("儿子在睡觉");
    }
    private int Sleep(int name){
        return 0;
    }

}

package test02;

public class Main {
    public static void main(String[] args){
        Father father = new Son();
        father.Sleep();
    }
}

这里写图片描述

但是对于域来讲,private 跟 public 没有区别,因为父类引用根本就不会去理会子类中是不是有跟父类一模一样的域。

package test02;

public class Father {
    public String name="爸爸";
    private void Sleep(){
        System.out.println("爸爸在睡觉");
    }
}

package test02;

public class Son extends Father{
    private String name="儿子";
    public int  Sleep(){
        System.out.println("儿子在睡觉");
        return 0;
    }

}

无论什么情况,始终调用的是父类的域。就算是父类与子类中的相同域都是public,调用的依然是父类中的域。

package test02;

public class Father {
    public String name="爸爸";
    private void Sleep(){
        System.out.println("爸爸在睡觉");
    }
}

package test02;

public class Son extends Father{
    public String name="儿子";
    private void  Sleep(){
        System.out.println("儿子在睡觉");
    }
    private int Sleep(int name){
        return 0;
    }
}

package test02;

public class Main {
    public static void main(String[] args){
        Father father = new Son();
        System.out.println(father.name);
    }
}

这里写图片描述

好的,今天博文更新到这里,谢谢大家。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值