继承
继承是java面向对象编程技术的一块基石,因为它允许创建分等级层次的类。
继承就是子类继承父类的特征和行为,使得子类对象(实例)具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为。
继承是面向对象最显著的一个特征
继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并扩展新的能力.
Java继承是会用已存在的类的定义作为基础建立新类的技术
新类的定义可以增加新的数据或者新的功能,也可以使用父类的功能,但不能选择性的继承父类(超类/基类)
这种继承使得复用以前的代码非常容易,能够大大的缩短开发的周期,降低开发费用.
继承有什么用?
多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承那个类即可。
被继承的类叫父类,继承的类叫子类,比如类A继承类B,则B为父类,A为子类
继承的关键字为extends
语法: class A extends B{ … }
类的继承格式:
class 父类 { } class 子类 extends 父类 { }
继承的类型:需要注意的是 Java 不支持多继承,但支持多重继承。
继承的好处:
(1)提高类代码的复用性
(2)提高了代码的维护性
(3)使得类和类产生了关系,是多态的前提(它也是继承的一个弊端,类的耦合性提高了)
继承的特性
子类拥有父类非 private 的属性、方法。
子类可以拥有自己的属性和方法,即子类可以对父类进行扩展。
子类可以用自己的方式实现父类的方法,即重写父类方法。
Java 的继承是单继承,但是可以多重继承,单继承就是一个子类只能继承一个父类,多重继承就是,例如 A 类继承 B 类,B 类继承 C 类,所以按照关系就是 C 类是 B 类的父类,B 类是 A 类的父类,这是 Java 继承区别于 C++ 继承的一个特性。
继承可以使用 extends 和 implements 这两个关键字来实现继承,而且所有的类都是继承于 java.lang.Object,当一个类没有继承的两个关键字,则默认继承object(这个类在 java.lang 包中,所以不需要 import)祖先类。
提高了类之间的耦合性(继承的缺点,耦合度高就会造成代码之间的联系越紧密,代码独立性越差)。
特点
使用extends关键字来表示继承关系
相当于子类把父类的功能复制了一份
Java只支持单继承
继承可以传递(爷爷/儿子/孙子这样的关系)
父类的私有成员也会被继承,但由于是私有的不可见,所以子类不能使用父类的私有资源
继承多用于功能的修改,子类可以在拥有父类功能的同时,进行功能拓展
像是is a的关系
super
可以通过这个关键字使用父类的内容,Super代表的是父类的一个引用对象
注意:在构造方法里,出现的调用位置必须是第一行
补全构造方法
描述
有父类Base,内部定义了x、y属性。有子类Sub,继承自父类Base。子类新增了一个z属性,并且定义了calculate方法,在此方法内计算了父类和子类中x、y、z属性三者的乘积。请补全子类构造方法的初始化逻辑,使得该计算逻辑能够正确执行。
输入描述:
三个整数:x, y, z
输出描述:
三个整数的乘积:xyz
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNextInt()) { int x = scanner.nextInt(); int y = scanner.nextInt(); int z = scanner.nextInt(); Sub sub = new Sub(x, y, z); System.out.println(sub.calculate()); } } } class Base { private int x; private int y; public Base(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } } class Sub extends Base { private int z; public Sub(int x, int y, int z) { //write your code here } public int getZ() { return z; } public int calculate() { return super.getX() * super.getY() * this.getZ(); }
答案解析:
我们的任务只是完善子类的构造方法。首先因为父类的成员变量都是private类型的,无法直接访问,因此赋初值只能通过super调用父类的构造方法,然后变量z是子类特有的,因此可以自己给自己赋值。
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNextInt()) { int x = scanner.nextInt(); int y = scanner.nextInt(); int z = scanner.nextInt(); Sub sub = new Sub(x, y, z); System.out.println(sub.calculate()); } } } class Base { private int x; private int y; public Base(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } } /** * 我们的任务只是完善子类的构造方法。首先因为父类的成员变量都是private类型的,无法直接访问, * 因此赋初值只能通过super调用父类的构造方法,然后变量z是子类特有的,因此可以自己给自己赋值。 */ class Sub extends Base { private int z; public Sub(int x, int y, int z) { //子类构造方法 super(x,y); //调用父类构造方法 this.z=z; //write your code here } public int getZ() { return z; } public int calculate() { return super.getX() * super.getY() * this.getZ(); }
运行结果是
1 2 3 6
重写计算逻辑
描述
在父类Base中定义了计算方法calculate(),该方法用于计算两个数的乘积(X*Y)。请在子类Sub中重写该方法,将计算逻辑由乘法改为除法(X/Y)。注意,当分母为0时输出“Error”。
输入描述:
两个整数
输出描述:
两个整数的商(int类型,不考虑小数情况)
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNextInt()) { int x = scanner.nextInt(); int y = scanner.nextInt(); Sub sub = new Sub(x, y); sub.calculate(); } } } class Base { private int x; private int y; public Base(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } public void calculate() { System.out.println(getX() * getY()); } } class Sub extends Base { //write your code here...... }
解析答案
public static void main(String[] args) { Scanner scanner = new Scanner(System.in); while (scanner.hasNextInt()) { int x = scanner.nextInt(); int y = scanner.nextInt(); System.out.println("除法"); Sub sub = new Sub(x, y); sub.calculate(); System.out.println("乘法"); Base base= new Base(x, y); base.calculate(); } } } class Base { private int x; private int y; public Base(int x, int y) { this.x = x; this.y = y; } public int getX() { return x; } public int getY() { return y; } public void calculate() { System.out.println(getX() * getY()); } } class Sub extends Base { public Sub(int x, int y) { super(x, y); } //write your code here...... public void calculate() { if (getY() == 0) { System.out.println("Error"); } else { System.out.println(getX() / getY()); } }
结果为
5 10 除法 0 乘法 50
扩展: 理解extends与implements的区别
注意:若同时用到 extends 和 implements 的时候,extends 必须放在 implements 关键字之前。
class 子类名 extends 父类名 implenments 接口名 {... }
Java只能单继承,接口为了弥补单继承的不足就出现了。
继承解决的是代码复用以及对象的关系,接口解决的是解耦.
1.在类的声明中,通过关键字extends来创建一个类的子类。一个类通过关键字implements声明自己使用一个或者多个接口。 extends 是继承某个类, 继承之后可以使用父类的方法, 也可以重写父类的方法; implements 是实现多个接口, 接口的方法一般为空的, 必须重写才能使用
2.extends是继承父类,只要那个类不是声明为final或者那个类定义为abstract的就能继承,JAVA中不支持多重继承,但是可以用接口 来实现,这样就要用到implements,继承只能继承一个类,但implements可以实现多个接口,用逗号分开就行了
比如:EG
class A extends B implements C,D,E
implements是一个类实现一个接口用的关键字,他是用来实现接口中定义的抽象方法。比如:people是一个接口,他里面有say这个方法。
public interface people(){ public say();}
但是接口没有方法体。只能通过一个具体的类去实现其中的方法体。比如chinese这个类,就实现了people这个接口。
public class chinese implements people{ public say() {System.out.println("你好!");}}
接口实现的注意点:
a.实现一个接口就是要实现该接口的所有的方法(抽象类除外)。
b.接口中的方法都是抽象的。
c.多个无关的类可以实现同一个接口,一个类可以实现多个无关的接口。
DEMO
这里有一个游戏,人猿泰山。 主角是一个单独的类,这里我们主要用怪物说明接口的用法: 怪物有很多种, 按地域分:有的在天上飞,有的在地上跑,有的在水里游 按攻击方式分:有的能近距离物理攻击,有的能远距离射击
假设游戏里需要这样的几 种怪——
野狗:地上移动,近距离攻击
黑熊:地上移动,近/远距离攻击
秃鹫:地上/天上移动,远距离攻击
食人鱼: 水中移动,近距离攻击
鳄鱼:地上/水中移动,近距离攻击
显然,如果我们将每一种怪物定义为一个类,那就不是面向对象的程序开 发了,我们应当使用接口:
interface OnEarth{//陆地接口 int earthSpeed;//陆地移动速度 void earthMove();//陆地移动方法 } interface OnWater{//水中接口 int waterSpeed;//水中移动速度 void waterMove();//水中移动方法 } interface OnAir{//空中接口 int airSpeed;//水中移动速度 void airMove();//水中移动方法 } interface NearAttack{//近距离攻击接口 int nearAttackPower;//近距离攻击力 void nearAttack();//近距离攻击方法 } interface FarAttack{//远距离攻击接口 int farAttackPower;//远距离攻击力 void farAttack();//远距离攻击方法 } 这样一来,根据需求,我们可以选择性的继承接口: class Tyke implements OnEarth, NearAttack{//野狗类 void earthMove(){//实现继承的方法1 } void nearAttack(){//实现继承的方法2 } } class BlackBear implements OnEarth, NearAttack, FarAttack{//黑熊类 void earthMove(){//实现继承的方法1 } void nearAttack(){//实现继承的方法2 } void farAttack(){//实现继承的方法3 } } class Vulture implements OnEarth, OnAir, FarAttack{//秃鹫类 void earthMove(){//实现继承的方法1 } void airMove(){//实现继承的方法2 } void farAttack(){//实现继承的方法3 } } class ManeatFish implements OnWater, NearAttack{//食人鱼类 void waterMove(){//实现继承的方法1 } void nearAttack(){//实现继承的方法2 } } class Crocodile implements OnEarth, OnWater, NearAttack{//鳄鱼类 void earthMove(){//实现继承的方法1 } void waterMove(){//实现继承的方法2 } void nearAttack(){//实现继承的方法3 } }