Java基础---继承
前言
本篇文章将介绍Java继承的相关内容
关于继承
简而言之,继承主要解决的问题就是:共性抽取
代码定义:
//父类:也称作基类、超类
public class 父类名称 {
// ...
}
//子类:也称作派生类
public class 子类名称 extends 父类名称 {
// ...
}
最高父类其实就是一个普通类,这点在代码定义时就可以看出来;
在继承的关系中,“子类就是一个父类”。也就是说,子类可以被当做父类看待。(例如:父类是员工,其子类有经理、业务员。那么可以有这样的表达:“经理、业务员是员工”)
在继承关系中:
子类可以
拥有父类的“内容”
子类还可以定义除父类之外的
专有内容
Java语言是
单继承
的:一个类的直接父类只能有唯一一个Java语言可以
多级继承
:
class A {}
Class B extends A {}
class C extends B {}
- 一个父类可以拥有很多个子类:
class A {}
class B extends A {}
class C extends A {}
用法
基本使用
定义父类Father
:
public class Father {
String father_string = "这是父类变量";
public void father_method() {
System.out.println("这是父类方法");
}
}
定义子类Son
:
public class Son extends Father {
String son_string = "这是子类变量";
public void son_method() {
System.out.println("这是子类方法");
}
}
使用类Demo
:
public class Demo {
public static void main(String[] args) {
Son son = new Son();
System.out.println(son.father_string); //访问父类变量
System.out.println(son.son_string); //访问子类变量
son.father_method(); //访问父类方法
son.son_method(); //访问子类方法
}
}
运行结果:
这是父类变量
这是子类变量
这是父类方法
这是子类方法
成员变量访问
- 局部变量:
局部变量名
- 本类的成员变量:
this.成员变量名
- 父类的成员变量:
super.成员变量名
定义父类Father
:
public class Father {
String words = "父类变量";
}
定义子类Son
:
public class Son extends Father {
String words = "子类变量";
public void son_method() {
String words = "局部变量";
System.out.println(words); //局部变量
System.out.println(this.words); //子类变量
System.out.println(super.words); //父类变量
}
}
使用类Demo
:
public class Demo {
public static void main(String[] args) {
Son son = new Son();
son.son_method(); //访问子类方法
}
}
运行结果:
局部变量
子类变量
父类变量
成员方法访问
基本使用
访问规则
:创建的对象是谁,就优先用谁的方法,如果没有,则向上找父类。
重写
在继承关系当中,方法名称一样,参数列表也一样。
注意区别重写与重载:
- 重写(Override):方法的名称一样,参数列表也一样
- 重载(Overload):方法的名称一样,参数列表不一样
注解@Override
:写在方法前面,用来检测是不是有效的正确重写。(也可以不写,但建议书写,起到检测作用)
定义父类Father
:
public class Father {
public void method() {
System.out.println("父类重名方法执行");
}
}
定义子类Son
:
public class Son extends Father {
@Override
public void method() {
System.out.println("子类重名方法执行");
}
}
使用类Demo
:
public class Demo {
public static void main(String[] args) {
Son son = new Son();
son.method(); //访问子类方法
}
}
运行结果:
子类重名方法执行
重写注意事项:
- 如果
父类
方法访问修饰符为private则子类就不能重写
该方法 子类
方法的抛出异常范围必须小于等于父类
方法的抛出异常范围子类
方法的返回值必须小于等于父类
方法的返回值范围java.lang.Object类
是所有类的公共最高父类,而java.lang.String类
就是Object的子类子类
方法的权限必须大于等于父类
方法的权限修饰符public > protected > (default) > private
(注:(default)不是关键字default,而是什么都不写,留空)
构造方法访问
基本使用
继承关系中,构造方法的访问特点:
- 子类构造方法当中有一个默认隐含的
super();
调用,所以一定是先调用的父类构造方法,后执行的子类构造方法 - 子类构造方法可以通过
super
关键字来调用父类重载构造方法 - super的父类构造调用,
必须是
子类构造方法的第一个语句
(不能一个子类构造调用多次super构造)
定义父类Father
:
public class Father {
public Father() {
System.out.println("父类无参构造方法");
}
}
定义子类Son
:
public class Son extends Father {
public Son() {
System.out.println("子类无参构造方法");
}
}
使用类Demo
:
public class Demo {
public static void main(String[] args) {
Son son = new Son();
}
}
运行结果:
父类无参构造方法
子类无参构造方法
super
用法:
- 在子类的成员方法中,访问父类的成员变量
- 在子类的成员方法中,访问父类的成员方法
- 在子类的构造方法中,访问父类的构造方法
定义父类Father
:
public class Father {
String string = "父类变量";
public Father() {
System.out.println("父类无参构造方法");
}
public Father(String string) {
this.string = string;
System.out.println("父类有参构造方法");
}
}
定义子类Son
:
public class Son extends Father {
String string = "子类变量";
public Son() {
super("调用父类的有参构造方法");
System.out.println("子类无参构造方法");
}
public Son(String string) {
this.string = string;
System.out.println("子类有参构造方法");
}
}
使用类Demo
:
public class Demo {
public static void main(String[] args) {
Son son = new Son();
}
}
运行结果:
父类有参构造方法
子类无参构造方法
this
用法:
- 在本类的成员方法中,访问本类的成员变量
- 在本类的成员方法中,访问本类的另一个成员方法
- 在本类的构造方法中,访问本类的另一个构造方法
注意:
this(...)
调用也必须是构造方法的第一个语句
,且是唯一的一个
super(...)
和this(...)
两种构造调用,不能同时使用
使用类Demo
:
public class Demo {
int num;
String words;
public Demo() {
this(1);
System.out.println("无参构造方法");
}
public Demo(int num) {
this(1,"参数");
this.num = num;
System.out.println("仅含一个参数的构造方法");
}
public Demo(int num, String words) {
this.num = num;
this.words = words;
System.out.println("全参构造方法");
}
public static void main(String[] args) {
Demo demo = new Demo();
}
}
运行结果:
全参构造方法
仅含一个参数的构造方法
无参构造方法
抽象(abstract)
如果父类中的方法不确定如何具体实现方法体的内容,那么就应该考虑使用抽象方法
。
例如:父类为
Animal
,其有两个子类Dog
、Cat
。在Animal
父类中定义了一个Eat(...){...}
的方法,但是由于狗啃骨头、猫吃鱼,这两个子类的吃行为是不一样的,无法在父类的方法体中进行准确定义,这时就需要将Eat(...)
定义为抽象方法
。
概念:
- 抽象方法:用
abstract
关键字修饰,然后去掉方法体,直接分号结束public abstract void method(...);
- 抽象类:抽象方法所在的类,必须是抽象类才行。在
class之前
用abstract
关键字修饰
使用时需要注意:
- 不能直接new抽象类对象
- 必须用一个子类来继承抽象父类
- 子类必须覆盖重写抽象父类当中所有的抽象方法,否则该子类也必须为抽象类
- 抽象类需要创建子类对象进行使用
- 一个抽象类不一定含有抽象方法,只要保证抽象方法所在的类是抽象类即可(在一些特殊场景下有用途)
定义父类Father
:
public abstract class Father {
public abstract void method();
public void normalMethod() {
System.out.println("普通的成员方法(子类不用重写此方法)");
}
}
定义子类Son
:
public class Son extends Father {
@Override
public void method() {
System.out.println("重写父类的抽象方法");
}
}
使用类Demo
:
public class Demo {
public static void main(String[] args) {
Son son = new Son();
son.method();
}
}
运行结果:
重写父类的抽象方法