一、继承概述
无须改变现有的类型,采用现有类,并在其中添加新的代码,由此产生新的类,这种方式
叫做继承。通过使用entends关键字来实现继承,示例代码:
//Student类继承Person类
public class Student extends Person {
public void study() {
System.out.println("good study");
}
public static void main(String[] args) {
Student s = new Student();
s.showWho();
s.study();
}
}
//Worker类继承Person类
public class Worker extends Person {
public void work() {
System.out.println("good work");
}
public static void main(String[] args) {
Worker w = new Worker();
w.showWho();
w.work();
}
}
Student和Worker在现实中首先是Person,所以Student类和Work类都同时具备Person的属性
(name,age...),因此,我们可以使用现有的Person类来生成新的类。在java语言中支持单继承,
不支持多继承。因为多继承有安全隐患,比如在多个父类中定义了相同的方法,但方法的内容不
同,子类不知道执行哪一个。
注意:必须是类与类之间有所属关系(is a),才可以继承,千万不可为获取其它类的方法而继承。
如何使用一个继承体系:
想要使用体系中的类,先查阅体系父类的描述,因为父类定义的是该体系中共性功能。了解了共性
的功能,知道了该体系的基本功能,那么这个体系已经可以基本使用了。在具体调用时,要创建最
子类的对象。
二、父子类的成员变量
在继承关系下,我们如何使用成员呢?这里先看下成员变量:
子父类中出现非私有同名变量时,子类要访问本类变量用关键字this。
子类要访问父类的同名变量用关键字super。
class Fu {
//父子同名变量
int num = 5;
//父特有变量
int num1 =1;
}
class Zi extends Fu{
//父子同名变量
int num = 4;
//子特有变量
int num2 =2;
void showFuNum() {
//打印父类变量num
System.out.println("The Fu num is " + super.num );
}
}
class ExtendsDome {
public static void main(String[] args) {
Zi z = new Zi();
System.out.println("The num is " + z.num );
System.out.println("The num1 is " + z.num1 + "The num2 is " + z.num2);
z.showFuNum();
}
}
三、父子类的一般方法——覆盖
当父子类中出现一模一样的方法时,子类对象调用该方法时,运行子类方法的内容,
这情况称为覆盖。这个特性方便对原有功能进行扩展。
class Fu {
int num1 =1;
//父子同名方法
void show() {
System.out.println("Fu show");
}
}
class Zi extends Fu{
int num2 =2;
//父子同名方法
void show() {
System.out.println("Zi show");
}
}
class ExtendsDome {
public static void main(String[] args) {
Zi z = new Zi();
z.show();
}
}
注意:1、子类覆盖父类,必须保证子类的权限,才可以覆盖,否则编绎失败
2、静态只能覆盖静态
3、在类中,包括子父类都不允许出现返回值不同的同名方法
4、private类型无法覆盖
四、父子类的构造方法——子类实例化过程
在所有的子类的构造方法中,都会有在第一行中调用super(),访默认的空参数父类的构
造方法。也可以在子类的构造方法中的第一行显示的用super调用指定的父类构造方法。
若子类在构造方法中的第一行使用this关键字调用本类中的构造方法,super语句就不会
隐示添加在此构造方法中,但至少有一个子类构造方法中会调用父类的构造方法
class Fu {
int num;
Fu() {
System.out.println("Fu run");
}
Fu(int num) {
this.num = num;
System.out.println("num of Fu is " + num);
}
}
class Zi extends Fu{
Zi() {
//隐式super();
System.out.println("Zi run");
}
Zi(int num) {
//显示调用特定super(num)
super(num);
System.out.println("Zi run");
}
}
public class ExtendsDome {
public static void main(String[] args) {
Zi z = new Zi();
Zi z1 = new Zi(2);
}
}
五、final关键字
1、final关键字可修饰类、方法、变量
2、final关键字修饰的类不可被继承
3、final关键字修饰的方法不能被覆盖
4、final关键字修饰换变量是一个常量
5、内部类定义在类中的局部位置上时,只能访问局部final修饰的局变量
六、抽象类
包括抽象方法的类称为抽象类,也必须被修饰为抽象类,用abstract关键字修。
抽象类不能直接创建对象,必须被继承,由子类重写所有的抽象方法,再创建子类对象
如果该子类只覆盖了部分抽象方法,那么子类也是抽象方法。
抽象类也可以不定义抽象方法,原因是是不让该类建立对象
abstract class Student {
//抽象类的定义方式
abstract void study();
static void show() {
System.out.println("可以直接使用吗?");
}
}
class BaseStudent extends Student{
void study() {
System.out.println("base study");
}
}
class AdvStudent extends Student {
void study() {
System.out.println("adv study");
}
}
public class AbstractDemo {
public static void main(String[] args) {
Student.show();
BaseStudent baseStudent = new BaseStudent();
AdvStudent advStudent = new AdvStudent();
baseStudent.study();
advStudent.study();
}
}
七、抽象类的一个应用
/*
* 使用继承建立一个员工系统。员工都有name,id,pay的属性。有专业人士类
* 和经理类。经理除了这三个属性外,还有奖金属性
*/
//员工基类
abstract class Employee {
private String name;
private String id;
private double pay;
Employee(String name,String id,double pay) {
this.name = name;
this.id = id;
this.pay = pay;
}
abstract void work();
}
//经理类
class Manager extends Employee {
private double bouns;
Manager(String name,String id,double pay,double bouns){
super(name,id,pay);
this.bouns = bouns;
}
void work() {
System.out.println("Manager work");
}
}
//专业人员类
class Pro extends Employee {
Pro(String name,String id,double pay){
super(name,id,pay);
}
void work() {
System.out.println("Pro work");
}
}
public class EmployeeDome {
public static void main(String[] args) {
Manager m = new Manager("Mname","M123",2,2);
Pro p = new Pro("Pname","P123",1);
m.work();
p.work();
}
}
八、模版方法
什么是模版方法:
在定义功能时,功能的一部分是确定的,但是有一部分时不确定的,而确定的部分在使用不确
定的部分。那么这时就不确定的部分暴露出去,由该类的子类去完成。
/*
* 需求:获取一段程序的运行时间
* 原理:获取程序开始和结束的时间并相减即可
*/
abstract class GetTime {
public final void getRunCodeTime() {
//获取当前时间戳
long start = System.currentTimeMillis();
//runCode是不确定的,暴露出,由子类实现
runCode();
long end = System.currentTimeMillis();
System.out.println("这段代码的运行时间是"+(end - start) +"ms");
}
abstract void runCode();
}
class SubGetTime extends GetTime {
void runCode() {
for(int i = 0;i<4000;i++) {
System.out.println(" " + i);
}
}
}
public class GetTimeDome {
public static void main(String[] args) {
SubGetTime subGetTime = new SubGetTime();
subGetTime.getRunCodeTime();
}
}