java类的继承中方法的覆盖与重载

java类的继承中方法的覆盖与重载

我们都知道,java中类是可以继承的,而在继承中方法是可以覆盖或者重载的。以前一直在纠结什么时候是覆盖,而什么时候又是重写,直到前几天,终于把一些搞通。以下是本人的一点小结。有总结的不好的,欢迎各位大神指出

原始代码:

class Animal{
    public void sayHello(){
        System.out.println("hello~");
    }
}

class Cat extends Animal{
    public void sayHello(){
        System.out.println("good~");
    }
}
public class Client{
    public static void main(String []args){
        Cat c = new Cat();
        c.sayHello();
        Animal a = new Cat();
        c.sayHello();
    }
}

代码中我们可以看到,Cat继承Animal,且其中都只有一个sayHello方法。参数个数,返回值类型与方法名都与父类Animal相同,符合java程序书继承中类方法的覆盖规则,毫无疑问输出都是good~.即此时的确是方法的覆盖而非重载。接下来,我们再新增一个类,代码如下:

class Animal{
    public void sayHello(){
        System.out.println("Animal say hello~");
    }
}

class Cat extends Animal{
    public void sayHello(){
        System.out.println("Cat say hello~");
    }
}
class Dog extends Animal{
    public void sayHello(){
        System.out.println("dog say Hello~");
    }
}
public class Client{
    public static void main(String []args){
        Animal a = new Dog();
        a.sayHello();
        Animal a1 = new Cat();
        a1.sayHello();
    }
}

输出结果为:

dog say Hello~
Cat say hello~

代码中可看出,我们增加了一个类,Dog继承Animal,且Dog中也有相同的一个方法sayHello(),只是输出内容不相同。在控制台中分别输出了 Dog say Hello~与 Cat say hello。这是因为我们在main方法中声明的对象都为Animal,但是new的类不同,所以调用的方法也不相同。
由此总结出一条结论:当子类继承同一个父类时,我们new的是哪一个类,则调用的就是哪一个类的方法。
看到这里我相信不禁有人会问,如果出现多重继承呢,即Cat类又有一个类去继承它,那么这个方法是否还是可以使用呢?
答案是肯定的,我们不妨在上面的代码中增加以下代码:

class Kitty extends Cat{
    public void sayHello(){
        System.out.println("Kitty say Hello~");
    }
}

即我们又新建一个类Kitty,这个类继承了Cat,而Cat又继承了Animal。它们的关系为:
Kitty->Cat->Animal
Animal类为祖先类,Cat变成了,Kitty为子类。我们依旧声明父类,然后用new运算符创建不同的类,创建对象的代码为:
Animal a1 = new Cat();
a1.sayHello();
Animal a2 = new Kitty();
a2.sayHello();
然后输出结果为:

Cat say hello~
Kitty say Hello~

依旧遵循 当子类继承同一个父类时,我们new的是哪一个类,则调用的就是哪一个类的方法。
由此看出,这条结论是正确的。

查阅java程序设计基础,上面关于继承时类方法的覆盖是这样定义的:
覆盖是指在子类中,定义名称,参数个数与返回值类型均与父类完全相同的方法,用来重写父类中同名方法的操作。
看到这里,我相信大多数的同学都大概明白了,我们只要明确的记住。覆盖时,只有子类的方法名和父类相同,返回值类型和父类完全相同,参数类型与个数和父类相同时才会发生覆盖,否则一律为重载。
但是,可能也有的同学会这么问:要是子类没有父类的方法,new的是子类的对象,那么再用这个对象去调用父类的那个方法,会出项什么情况呢?是编译不通过,还是会调用父类的方法呢?
不急,我们再看看以下代码:

class Animal{
    public void sayHello(){
        System.out.println("Animal say hello~");
    }
}

class Cat extends Animal{
}
public class Client{
    public static void main(String []args){
        Animal a1 = new Cat();
        a1.sayHello();
    }
}

代码中我们可以看到。Animal类中空空无一,但是我们却能编译通过,且运行时结果为:

Animal say hello~

出现这种情况的原因是因为Cat类继承了Animal类,自然的也就把Animal类的方法也给继承过来了。随意运行的时候首先会去子类看看有没有那个方法,如果有,则优先调用子类的方法,若没有,那么再去父类找这个方法。若把Animal方法写成private的话就会出现编译出错的情况。因为继承中我们知道,私有的方法是不能被继承的。

说到私有方法不能被继承,我们不禁会有这样一个疑问。若父类的方法为私有,但是子类方法为public类型的。然后我们再用声明父类指向子类的方式去创建对象,然后用这个对象去调用这个方法。那么又会出现什么情况呢?
这个我们修改后的代码:

class Animal{
    private void sayHello(){
        System.out.println("Animal say hello~");
    }
}
class Cat extends Animal{
    public void sayHello(){
        System.out.println("Animal say hello~");
    }
}
public class Client{
    public static void main(String []args){
        Animal a1 = new Cat();
        a1.sayHello();
    }
}

然后我们编译:

Client.java:14: 错误: sayHello()可以在Animal中访问private
                a1.sayHello();
                  ^
1 个错误

我们会发现,出错了。很多朋友相信都纳闷了。怎么会出错了呢,上面不是说new的是哪个对象,调用的就是哪一个对象的方法吗?难道是刚才的结论有错?
事实不是这样的。刚才的那个结论依旧是正确的。上面我们刚刚说过,继承中子类只能继承父类中protected以上的方法(若子类与父类在同一个包中,也能继承缺省的),而这里我们写的是private,这是不能被继承的,既然不能被继承,那么又何来覆盖一说?所以它就会用子类的对象去访问父类的私有方法,而因为这个方法是私有的,即使new 的是父类的对象,都不能调用,子类更是不可能了。由此我们也得出一个经验,当我们写私有方法时,一定要特别小心。因为这个方法用正常的方式根本不可访问。而实际开发中,我们也几乎只在特定的方法下才写私有方法。

然后我们再这样修改代码。保持参数类型和个数,方法的返回值完全相同。但是访问修饰符不同,又会出现什么情况呢?
我们来看代码:

class Animal{
    public void sayHello(){
        System.out.println("Animal say hello~");
    }
}
class Cat extends Animal{
    protected void sayHello(){
        System.out.println("Animal say hello~");
    }
}
public class Client{
    public static void main(String []args){
        Animal a1 = new Cat();
        a1.sayHello();
    }
}

这个时候,我们依旧是用父类指向子类的方式去创建对象。但是父类的访问修饰符为public,而子类为protected;即子类的访问修饰符比父类低。然后我们再来看看编译结果:

Client.java:7: 错误: Cat中的sayHello()无法覆盖Animal中的sayHello()
        protected void sayHello(){
                       ^
  正在尝试分配更低的访问权限; 以前为public
1 个错误

糟糕,又出错了。什么原因呢?最后问了一下老师,然后才知道,原来java中关于方法的覆盖还有一大两小这么个说法
这是我自己总结的一大两小原则:
*大:
1.子类的访问修饰符 大于等于 父类的访问修饰符
两小:
1.子类的返回类型 小于等于 父类的返回类型
2.抛出异常时,只能 小于等于 父类的异常*
以上结论本人已经全部实验过。都是正确的。因为篇幅太长,在这里就不一一写出来了。看到这里的各位也可以自己验证验证,有不懂得欢迎提问。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值