一. 引言在学习面向对象后,我们就可以使用类来描述对象共有的特征(属性)和行为举止(方法),如果我们用类来描述猫、狗和企鹅,可以进行如下编码:
publicclassCat{privateString name;//名字privateintage;//年龄privateString strain; //品种//省略getter和setter方法} publicclassDog{privateString name;//名字privateintage;//年龄privateString strain; //品种//省略getter和setter方法} publicclassPenguin{privateString name;//名字privateintage;//年龄privateString sex; //性别//省略getter和setter方法} 复制代码你会发现,在上面的3个类中存在大量的重复代码,那么该如何优化呢?这里我们可以使用继承来优化!
二. 继承1. 什么是继承当我们编写的多个类中存在相同的属性或方法时,可以将这些类中相同的属性和方法抽取到一个新的类中,然后再让这些类继承于这个新类,就可以重用新类中的属性和方法,这些类称为子类,这个新类称为父类,这就是Java中的继承 。
2. 如何使用继承我们将上面的案例抽取出一个父类如下:
publicclassAnimal{String name;//名字intage;//年龄} 复制代码接下来只需要继承于这个父类即可 。在Java中,继承使用extends关键字 来表示,上面的三个类修改如下:
publicclassCatextendsAnimal{//猫类继承于动物类privateString strain; //品种//省略getter和setter方法} publicclassDogextendsAnimal{//狗类继承于动物类privateString strain; //品种//省略getter和setter方法} publicclassPenguinextendsAnimal{//企鹅类继承于动物类privateString sex; //性别//省略getter和setter方法} 复制代码接下来我们可以编写一个测试案例 。
publicclassAnimalTest{ publicstaticvoid main(String[] args) { Catc= new Cat(); c.setName("苗苗"); c.setAge(1); c.setStrain("咖啡猫"); } } 复制代码我们发现,在 Cat 类中并没有 setName 和 setAge 方法,但却可以直接使用这些方法,说明这两个方法都是从父类中继承过来的,其他两个类也一样 。
3. 子类能够继承父类的哪些属性和方法3.1 API文档在官方文档中有这样的描述:
A subclass inherits all of the public and protected members of its parent, no matter what package the subclass is in. If the subclass is in the same package as its parent, it also inherits the package-private members of the parent.解释说明:
不论子类与父类是否在同一个包中,父类中使用 public 或者 protected 修饰的属性和方法,都能够被子类继承 。如果子类和父类在同一个包中,那么子类还能继承受包保护的属性和方法(受包保护指的是没有使用访问修饰符的属性和方法) 。
A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.解释说明:
子类不会继承父类中定义的私有成员 。但如果父类有提供使用 public 或者 protected 修饰的访问该字段的方法,这些方法也能在子类中被使用 。
为了验证这些文档中的说法是否正确,接下来我们通过几个案例来进行验证 。
3.2 案例一publicclassAnimal{ privateString name;//修改访问修饰符为privateintage;//年龄//省略getter和setter方法} publicclassCatextendsAnimal{ privateString strain; publicString getStrain(){ returnstrain; } publicvoidsetStrain(String strain){ this.strain = strain; } publicvoidshow(){ //添加一个show方法,打印name和age属性System.out.println(name + age); } } 复制代码此时编译也出错,name 属性不能访问,但 age 属性可以 。
文章插图
该案例说明了父类中私有的属性不能被继承,但受包保护的属性可以被继承 。
3.3 案例二packagecom.qf.oop; //给父类添加包名publicclassAnimal{ privateString name;//修改访问修饰符为privateintage;//年龄//省略getter和setter方法} packagecom.qf.oop.sub; //给子类添加包名importcom.qf.oop.Animal; publicclassCatextendsAnimal{ privateString strain; publicString getStrain(){ returnstrain; } publicvoidsetStrain(String strain){ this.strain = strain; } publicvoidshow(){ System.out.println(name + age); } } 复制代码此时编译也出错,name 和 age 属性都不能访问 。
文章插图
该案例说明了在不同的包中,子类不能继承父类中的私有属性和受包保护的属性 。
3.4 案例三packagecom.qf.oop; publicclassAnimal{ publicString name; //修改访问修饰符为publicprotectedintage; //修改访问修饰符为protected//省略getter和setter方法} packagecom.qf.oop.sub; importcom.qf.oop.Animal; publicclassCatextendsAnimal{ privateString strain; publicString getStrain(){ returnstrain; } publicvoidsetStrain(String strain){ this.strain = strain; } publicvoidshow(){ System.out.println(name + age); } } 复制代码此时编译正常 。
文章插图
该案例说明了在不同的包中,子类可以继承父类中公开的属性和受保护的属性,方法的继承与属性的继承规则一致 。
三. 方法重写1. 什么是方法重写方法重写指的是在具有继承关系的子类中,如果存在一个成员方法,与父类中的成员方法有相同的签名和返回值类型,那么,这个方法就重写了父类中的成员方法,称为方法重写 。
方法签名指的是方法名、参数类型和参数个数 。2. 为什么要使用方法重写我们知道方法表示的是行为举止,子类继承父类,当然也可以继承父类的行为举止 。但我们经常会遇到子类和父类做一件事情的方式不一样,也就是说,子类中的方法实现和父类中的方法实现存在差别 。例如:动物会吃食物,但不同的动物吃的食物也不一样 。
相同的方法签名指的是方法名、参数类型、参数个数和参数出现的位置均相同 。
publicclassAnimal{ publicvoideat(){ System.out.println("动物吃食物"); } } publicclassCatextendsAnimal{ publicvoideat(){ System.out.println("猫吃鱼"); } } 复制代码子类 Cat 中的 eat 方法与父类 Animal 中的 eat 方法具有相同的签名和返回值类型,这样的方法我们称其为重写了父类中eat 方法 。
为了方便查看重写的方法,Java 提供了 @Override 注解来标识 。这个注解仅仅就是一个标识,写与不写都不影响 。
【java继承的概念和特点 java中什么是继承机制】publicclassCatextendsAnimal{ @Override//重写的方法的一个标识publicvoideat(){ System.out.println("猫吃鱼"); } } 复制代码3. 如何使用方法重写现有这样一个场景:几何图形都有面积和周长,不同的几何图形,面积和周长的算法也不一样 。矩形有长和宽,通过长和宽能够计算矩形的面积和周长;圆有半径,通过半径可以计算圆的面积和周长 。请使用继承相关的知识完成程序设计 。
packagecom.qf.oop.shape; /** * 几何图形 */publicclassShape{ /** * 计算周长 * @return*/publicdoublecalculatePerimeter(){ return0; } /** * 计算面积 * @return*/publicdoublecalculateArea(){ return0; } } packagecom.qf.oop.shape; /** * 矩形 */publicclassRectangleextendsShape{ privateintwidth; privateintlength; publicRectangle(intwidth, intlength){ this.width = width; this.length = length; } @OverridepublicdoublecalculatePerimeter(){//重写计算周长的方法return(width + length) * 2; } @OverridepublicdoublecalculateArea(){//重写计算面积的方法returnwidth * length; } } packagecom.qf.oop.shape; /** * 圆 */publicclassCircleextendsShape{ privateintradius; publicCircle(intradius){ this.radius = radius; } @OverridepublicdoublecalculateArea(){//重写计算面积的方法returnMath.PI * radius * radius; } @OverridepublicdoublecalculatePerimeter(){//重写计算周长的方法return2* Math.PI * radius; } } packagecom.qf.oop.shape; publicclassShapeTest{ publicstaticvoidmain(String[] args){ Shape s1 = newRectangle(10, 9); System.out.println(s1.calculatePerimeter()); System.out.println(s1.calculateArea()); Shape s2 = newCircle(5); System.out.println(s2.calculatePerimeter()); System.out.println(s2.calculateArea()); } } 复制代码重写方法时访问修饰符的级别不能降低 。
推荐阅读
- 剪短发的说说发朋友圈
- 雪菜黄豆的做法
- 喝墨鱼汁是一种怎样的体验
- 大豆花荚脱落的原因是什么
- 米其林是生产轮胎还是餐厅?“轮胎人”的由来?
- 佛山大顶苦瓜炖盅汤怎样做 佛山大顶苦瓜炖盅汤的做法
- 云南糖糕怎么做 云南糖糕的做法
- 吃虾的蘸料最简单的:白灼虾的蘸料怎么做?
- 友谊朋友圈流行的话语
- 光明与黑暗的语录