为何Java中子类重写方法的访问权限不能低于父类中权限

因为 向上转型及Java程序设计维护的原因

例:

假设一个父类A 拥有的方法public void setXXX(){}可以被其他任意对象调用这个方法被子类B 覆写后 为void setXXX(){}即默认的访问权限只能被本包极其子类 所访问假设其他包中的对象 C调用 方法为:

get( A  a){

a.setXXX();}

而此时传入的对象为B类对象,假设为b此时b将转型为a但是b中的setXXX() 调用权限

已经被缩小了这将造成错误。所以子类对象不能比父类对象访问权限大

以上只是一个例子还有其他出于易维护、易代码结构设计的设计思想原因

其他:子类中重写的方法抛出的异常应该为父类中方法的子异常或相同异常,并且抛出的异常种类不能多于父类中的方法。

实际上是遵循里氏替换原则。

一、里氏替换原则的定义

1、里氏替换原则通俗的来讲就是:子类可以扩展父类的功能,但不能改变父类原有的功能。

2、里氏代换原则告诉我们,在软件中将一个基类对象替换成它的子类对象,程序将不会产生任何错误和异常,反过来则不成立,如果一个软件实体使用的是一个子类对象的话,那么它不一定能够使用基类对象。

3、里氏代换原则是实现开闭原则的重要方式之一,由于使用基类对象的地方都可以使用子类对象,因此在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对象。

二、里氏替换原则包含的含义

1、子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法

在我们做系统设计时,经常会设计接口或抽象类,然后由子类来实现抽象方法,这里使用的其实就是里氏替换原则。子类可以实现父类的抽象方法很好理解,事实上,子类也必须完全实现父类的抽象方法,哪怕写一个空方法,否则会编译报错。

里氏替换原则的关键点在于不能覆盖父类的非抽象方法。(尽量不要重写)父类中凡是已经实现好的方法,实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些规范,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。

2、子类中可以增加自己特有的方法

在继承父类属性和方法的同时,每个子类也都可以有自己的个性,在父类的基础上扩展自己的功能。前面其实已经提到,当功能扩展时,子类尽量不要重写父类的方法,而是另写一个方法。

3、当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。

4、当子类覆盖或实现父类的方法时,方法的后置条件(即方法的返回值)要比父类方法的返回值更严格。

现在我们可以对以上四层含义逐个讲解。

子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法

在我们做系统设计时,经常会设计接口或抽象类,然后由子类来实现抽象方法,这里使用的其实就是里氏替换原则。子类可以实现父类的抽象方法很好理解,事实上,子类也必须完全实现父类的抽象方法,哪怕写一个空方法,否则会编译报错。

里氏替换原则的关键点在于不能覆盖父类的非抽象方法。父类中凡是已经实现好的方法,实际上是在设定一系列的规范和契约,虽然它不强制要求所有的子类必须遵从这些规范,但是如果子类对这些非抽象方法任意修改,就会对整个继承体系造成破坏。而里氏替换原则就是表达了这一层含义。

在面向对象的设计思想中,继承这一特性为系统的设计带来了极大的便利性,但是由之而来的也潜在着一些风险。就像开篇所提到的那一场景一样,对于那种情况最好遵循里氏替换原则,类C1继承类C时,可以添加新方法完成新增功能,尽量不要重写父类C的方法。否则可能带来难以预料的风险,比如下面一个简单的例子:

public class C {

public int func(int a, int b){

return a+b;

}

}

public class C1 extends C{

@Override

public int func(int a, int b) {

return a-b;

}

}

public class Client{

public static void main(String[] args) {

C c = new C1();

System.out.println("2+1=" + c.func(2, 1));

}

}

运行结果:2+1=1

上面的运行结果明显是错误的。类C1继承C,后来需要增加新功能,类C1并没有新写一个方法,而是直接重写了父类C的func方法,违背里氏替换原则,引用父类的地方并不能透明的使用子类的对象,导致运行结果出错。

子类中可以增加自己特有的方法

在继承父类属性和方法的同时,每个子类也都可以有自己的个性,在父类的基础上扩展自己的功能。前面其实已经提到,当功能扩展时,子类尽量不要重写父类的方法,而是另写一个方法,所以对上面的代码加以更改,使其符合里氏替换原则,代码如下:

public class C {

public int func(int a, int b){

return a+b;

}

}

public class C1 extends C{

public int func2(int a, int b) {

return a-b;

}

}

public class Client{

public static void main(String[] args) {

C1 c = new C1();

System.out.println("2-1=" + c.func2(2, 1));

}

}

运行结果:2-1=1

当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松

import java.util.HashMap;

public class Father {

public void func(HashMap m){

System.out.println("执行父类...");

}

}

import java.util.Map;

public class Son extends Father{

public void func(Map m){//方法的形参比父类的更宽松

System.out.println("执行子类...");

}

}

import java.util.HashMap;

public class Client{

public static void main(String[] args) {

Father f = new Son();//引用基类的地方能透明地使用其子类的对象。

HashMap h = new HashMap();

f.func(h);

}

}

运行结果:执行父类...

注意Son类的func方法前面是不能加@Override注解的,因为否则会编译提示报错,因为这并不是重写(Override)。

当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格

import java.util.Map;

public abstract class Father {

public abstract Map func();

}

import java.util.HashMap;

public class Son extends Father{

@Override

public HashMap func(){//方法的返回值比父类的更严格

HashMap h = new HashMap();

h.put("h", "执行子类...");

return h;

}

}

public class Client{

public static void main(String[] args) {

Father f = new Son();//引用基类的地方能透明地使用其子类的对象。

System.out.println(f.func());

}

}

执行结果:{h=执行子类...}

总结

继承作为面向对象三大特性之一,在给程序设计带来巨大便利的同时,也带来了一些弊端,它增加了对象之间的耦合性。因此在系统设计时,遵循里氏替换原则,尽量避免子类重写父类的方法,可以有效降低代码出错的可能性。

我们都知道面向对象有三大特性:封装、继承、多态。所以我们在实际开发过程中,子类在继承父类后,根据多态的特性,可能是图一时方便,经常任意重写父类的方法,那么这种方式会大大增加代码出问题的几率。比如下面场景:类C实现了某项功能F1。现在需要对功能F1作修改扩展,将功能F1扩展为F,其中F由原有的功能F1和新功能F2组成。新功能F由类C的子类C1来完成,则子类C1在完成功能F的同时,有可能会导致类C的原功能F1发生故障。这时候里氏替换原则就闪亮登场了。

java 重写方法 访问权限_为何Java中子类重写方法的访问权限不能低于父类中权限(内含里氏替换原则)...相关推荐

  1. Java设计模式(03) -- 里氏替换原则

    六大设计原则 单一职责原则定义:约定一个类应该有且仅有一个改变类的原因: 开闭原则定义:规定软件中的对象.类.模块和函数对扩展应该是开放的,但对于修改是封闭的,核心思想也可以理解为面向抽象编程. 里氏 ...

  2. java设计模式3,里氏替换原则

    目录 一.里氏替换原则定义 二.里氏替换原则的作用 三.违背原则场景 四.里氏替换原则改变代码 1.抽象人物类 2.哪吒子类 3.敖丙子类 五.关注公众号哪吒编程,回复1024,获取Java学习资料, ...

  3. java 七大设计原则之依赖倒置,里氏替换原则(文字代码相结合理解)

    java 七大设计原则之依赖倒置,里氏替换原则,文字代码相结合理解 七大设计原则有哪些? 为什么要使用七大设计原则? 依赖倒置原则 里氏替换原则 喜欢就争取,得到就珍惜,错过就忘记.人生也许不尽完美, ...

  4. java里氏替换原则例子_java设计模式学习笔记——里氏替换原则

    oo中的继承性的思考和说明 1.继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些七月,但是如果子类对这些已经实现的方法任意修改,就会对 ...

  5. 为何Java中子类重写方法的访问权限不能低于父类中权限

    参考:http://zhidao.baidu.com/link?url=E-c1LVmYCi3I-X1u5imdsDsdoyfeY2dJau6tU1bWnf4QAS4uthnM_8ffm6K177GE ...

  6. java 继承的内存分配_图解Java继承内存分配

    继承的基本概念: (1)Java不支持多继承,也就是说子类至多只能有一个父类. (2)子类继承了其父类中不是私有的成员变量和成员方法,作为自己的成员变量和方法. (3)子类中定义的成员变量和父类中定义 ...

  7. java solid设计原则_六大设计原则之里氏替换原则(LSP)

    一.SOLID 设计模式的六大原则有: Single Responsibility Principle:单一职责原则 Open Closed Principle:开闭原则 Liskov Substit ...

  8. 【源码+图片素材】Java王者荣耀游戏开发_开发Java游戏项目【王者荣耀】1天搞定!!!腾讯游戏_Java课程设计_Java实战项目_Java初级项目

    王者荣耀是当下热门手游之一,小伙伴们是否想过如何制作一款属于自己的王者荣耀游戏呢? 本课程讲解了一个王者荣耀游戏的详细编写流程,即使你是刚入门Java的新手,只要你简单掌握了该游戏所需要的JavaSE ...

  9. Java里氏转换_详解Java设计模式编程中的里氏替换原则

    定义1:如果对每一个类型为 T1的对象 o1,都有类型为 T2 的对象o2,使得以 T1定义的所有程序 P 在所有的对象 o1 都代换成 o2 时,程序 P 的行为没有发生变化,那么类型 T2 是类型 ...

最新文章

  1. 揭秘PHP深受Web开发者喜爱的原因
  2. oracle修改连接数
  3. LINK : fatal error LNK1168: cannot open Debug/Test.exe for writing
  4. 麻省理工告诉我们男女配对的真相!
  5. vue路由参数改变,组件数据没重新更新问题
  6. linux没有那个文件或目录_Linux安装python faiss模块
  7. 如何使用Facebook广告为shopify商店引流
  8. git:关联github和本地仓库
  9. BJUI--data-rule规则及自定义
  10. 数学建模MATLAB之分析法(一)
  11. 计算机组成原理无符号数除法,计算机组成原理课设 不恢复余数的无符号阵列除法器.doc...
  12. 医保是不是只有住院才能在单位报销 什么样的病才能报销
  13. D - Plane 航空管制2 HYSBZ - 2535
  14. webStorm的一些快捷键
  15. 实现android广告栏效果
  16. Maven手动导入依赖
  17. Matplotlib——绘制多个子图(Axes)及其布局
  18. 计算机视觉基础系列(python与opencv的操作与运用/tensorflow的基础介绍)(八)---小例子(神经网络逼近股票收盘价格)
  19. 使用高斯混合模型(GMM)近似未知分布:EM算法的应用
  20. 【转】java调用http接口的几种方式总结

热门文章

  1. 用户表如何存放用户密码
  2. LZW算法PHP实现方法 lzw_decompress php
  3. Activity生命周期的补充
  4. groovy --不注意的小错误(java.lang.String.positive() is applicable)
  5. 开源 java CMS - FreeCMS2.3会员个人资料
  6. Android学习3—电话拨号器
  7. ABAP-DOI技术的优化
  8. 24、Power Query-数学运算的应用(统计男女人数)
  9. 快消行业指的是哪些?
  10. SAP HANA会代替BW吗?