JAVA基础(面向对象进阶) —— 继承

 通过之前对 JAVA基础 —— 面向对象 以及 JAVA基础 —— 面向对象内存图 的学习。

接下来我们将会进一步学习面向对象进阶的相关知识点。

static JAVA基础 (面向对象进阶)—— Static
继承 JAVA基础 (面向对象进阶)—— 继承
多态 JAVA基础 (面向对象进阶)—— 多态
包、final、权限修饰符、代码块、抽象类和抽象方法方法 JAVA基础(面向对象进阶) —— 包、final、权限修饰符、代码块、抽象类和抽象方法方法
接口 JAVA基础 (面向对象进阶)—— 接口
内部类 JAVA基础 (面向对象进阶)—— 内部类

 目录

一、前言

二、 内容概述 

1.  继承概念

 2.  使用继承的好处

3.  什么时候使用继承?

4.  继承的特点

三、 子类继承父类内容

1.  构造方法是否可以被继承

 2.  成员变量是否可以被继承

 3.  成员方法是否可以被继承

 四、 继承中的访问特点

 1.  成员变量的访问特点

2.  成员方法的访问特点

 2.1  方法重写

2.2  重写的本质

2.3  方法重写注意事项和要求

2.3  利用方法的重写设计继承结构

3.  构造方法的访问特点

 五、 this、super使用总结

 练习:带有继承结构的标准Javabean类


一、前言

通过前面面向对象的学习,我们认识到了封装的概念:面向对象

对象代表什么,就得封装对应的数据,并提供数据对应的行为。

通过封装,我们可以把零散的数据和方法封装在一起,例如Student类。

但是,当我们又创建了Teacher类且拥有相同的数据和方法的时候,就会发现,代码发生冗余

JAVA基础(面向对象进阶) —— 继承_第1张图片 JAVA基础(面向对象进阶) —— 继承_第2张图片

 因此,我们就引入了  继承  的概念。

JAVA基础(面向对象进阶) —— 继承_第3张图片

二、 内容概述 

1.  继承概念

Java中提供了一个关键字extends,我们可以让一个类和另一个类建立起继承关系。

public class Student extends Person { } 

Student称为子类(派生类),Person称为父类(基类或超类)


继承的格式:

public class 子类 extends 父类 { } 

 2.  使用继承的好处

  • 可以把多个子类中重复的代码抽取到父类中了,提高代码的复用性。
  • 子类可以在父类的基础上,增加其他的功能,使子类更强大。

3.  什么时候使用继承?

当类与类之间,存在相同(共性)的内容,并满足子类是父类中的一种,就可以考虑使用继承,来优化代码。

4.  继承的特点

  1. Java只能单继承:一个类只能继承一个直接父类
  2. Java不支持多继承,但是支持多层继承
  3. Java中所有的类都直接过间接继承与Object类
  4. 子类只能访问非私有的成员

三、 子类继承父类内容

父类内容 类别1 子类能否继承 类别2 子类能否继承
构造方法 非私有
 
不能 private
 
不能
成员变量
成员方法 不能

1.  构造方法是否可以被继承

假设构造方法构造方法可以被继承,我们在父类中定义一个空参构造,再写一个有参构造

那么子类就可以直接拿过来使用。

JAVA基础(面向对象进阶) —— 继承_第4张图片 JAVA基础(面向对象进阶) —— 继承_第5张图片
但是我们发现方法名和子类名不一致,违背了构造方法定义规则。
public static void main(String[] args) {
	//利用空参构造创建类对象
	Zi z1 = new Zi();
	//利用带参构造创建类对象
	
	//报错: 子类不能继承父类方法
	//如果能继承,子类应该可以有参构造
	Zi z2 = new Zi("张三",23);
}

class Fu{
	String name;
	int age;
	
	public Fu() {}
	public Fu(String name,int age) {
		this.name = name;
		this.age = age;
	}
}

class Zi extends Fu {
	//如果一个类中没有构造方法,虚拟机会自动添加空参构造
}

 2.  成员变量是否可以被继承

不管非私有还是私有,父类中的成员变量都可以继承。

但是私有的不能直接使用,可以采用对应的 get / set 方法进行。

 内存图:

JAVA基础(面向对象进阶) —— 继承_第6张图片 JAVA基础(面向对象进阶) —— 继承_第7张图片
JAVA基础(面向对象进阶) —— 继承_第8张图片

 3.  成员方法是否可以被继承

JAVA基础(面向对象进阶) —— 继承_第9张图片

 如果Java虚拟机设计为A类调用方法B然后B类调用方法C,那大错特错

JAVA基础(面向对象进阶) —— 继承_第10张图片
JAVA基础(面向对象进阶) —— 继承_第11张图片

虚方法表:将类中经常使用的方法拉出来

只有父类中的虚方法才能被子类继承

 内存图:

JAVA基础(面向对象进阶) —— 继承_第12张图片 JAVA基础(面向对象进阶) —— 继承_第13张图片
JAVA基础(面向对象进阶) —— 继承_第14张图片

 四、 继承中的访问特点

 1.  成员变量的访问特点

JAVA基础(面向对象进阶) —— 继承_第15张图片 就近原则:谁离我近,我就用谁
现在局部位置找,本类成员位置找,父类成员位置找,逐级往上。
public class test01 {
	public static void main(String[] args) {
		Zi z = new Zi();
		z.zishow();
	}
}
	
	class Fu{
		String name = "fu";
	}
	class Zi extends Fu{
		String name = "zi";
		public void zishow() {
		String name = "zishow";
		System.out.println(name);  // zishow
		//this不在局部位置找 直接到本类成员位置找
		System.out.println(this.name);   // zi
		//suoer表示父类
		System.out.println(super.name); // fu
		
	}
}

2.  成员方法的访问特点

  • 直接调用满足就近原则:谁离我近,我就用谁
  • super调用,直接访问父类
public class Test {
	public static void main(String[] args) {
		Student s = new Student();
		s.lunch();
	}
}

class Person {
	public void eat() {
		System.out.println("吃米饭,吃菜");
	}

	public void drink() {
		System.out.println("喝开水");
	}
}

// 留学生
class OverseaStudent extends Person {
	public void lunch() {
		this.eat();
		this.drink();

		super.eat();
		super.drink();
	}

	public void eat() {
		System.out.println("吃意大利面");
	}

	public void drink() {
		System.out.println("喝凉水");
	}
}


class Student extends Person {
	public void lunch() {
		// 隐含this. 方法调用需要调用者
		// this.eat\this.drink
		// 现在本类中查看eat 和 drin 方法
		// 如果有就调用, 如果没有就会调用从父类继承下来的eat 和drink 方法
		eat();
		drink();
		// 直接调用父类eat 和drink 方法
		super.eat();
		super.drink();
	}
}

 2.1  方法重写

方法的重写:

当父类的方法不能满足子类现在的需求时,需要进行方法的重写。

书写格式:

在继承体系中,子类出现了父类父类中一模一样的方法声明,我们就称子类这个方法是重写的方法。

@Override重写注解:

  1. @Override是放在重写后的方法上,校验子类重写时语法是否正确。
  2. 加上注解后如果有红色波浪线,表示语法错误。
  3. 建议重写方法都加@Override注解,代码安全,优雅!
//父类
class Person {
	public void eat() {
		System.out.println("吃米饭,吃菜");
	}

	public void drink() {
		System.out.println("喝开水");
	}
}

// 子类
class OverseaStudent extends Person {
	public void lunch() {
		
	}
	@Override
	public void eat() {
		System.out.println("吃意大利面");
	}
	@Override
	public void drink() {
		System.out.println("喝凉水");
	}
}

2.2  重写的本质

JAVA基础(面向对象进阶) —— 继承_第16张图片
如果发生了重写,则会覆盖

2.3  方法重写注意事项和要求

  1. 重写方法的名称、形参列表必须与父类中的一致
  2. 子类重写父类方法时,访问权限子类必须大于等于父类                                             (暂时了解:空 < protected < public )
  3. 子类重写父类方法时,返回值类型类型必须小于等于父类。
  4. 建议:重写的方法尽量和父类保持一致
  5. 私有方法不能被重写
  6. 子类不能重写父类的静态方法,如果重写会报错的。
  7. 只有被添加到虚方法表中的方法才能被重写

2.3  利用方法的重写设计继承结构

现在有三种动物:哈士奇、沙皮狗、中华田园犬

暂时不考虑属性,只要考虑行为。
请按照继承的思想特点进行继承体系的设计。
三种动物分别有以下的行为:

哈士奇 吃饭(吃狗粮) 喝水、看家、拆家
沙皮狗 吃饭(吃狗粮、吃骨头) 喝水、看家
中华田园犬 吃饭(吃剩饭) 喝水、看家
//dog类
public class Dog {
	public void eat() {
		System.out.println("狗在吃狗粮");
		}
	public void drink() {
		System.out.println("狗在喝水");
		}
	public void lookHome() {
		System.out.println("狗在看家");
		}
	
}


//哈士奇类
public class Husky extends Dog{
	//哈士奇额外方法 - 拆家
	public void breakHome() {
		System.out.println("哈士奇又在拆家");
	}
	
}


//沙皮犬类
public class Sharpei {
	//沙皮狗吃饭 - 狗粮和骨头
	//父类中的方法不能满足需求 - 需要对方法进行重写
	
	@Override
	public void eat() {
		super.eat();
		System.out.println("狗在啃骨头");
	}
}

//中华田园犬类
public class ChineseDog extends Dog{
	//中华田园犬吃饭 - 吃剩饭
	//父类中的方法不能满足需求 - 需要对方法进行重写
	// 而且完全用不到父类方法  所以用不到super
	@Override
	public void eat() {
		System.out.println("吃剩饭");
	}
}

//测试类

public class DogTest {
public static void main(String[] args) {
	//创建对象并调用
	
	Husky h= new Husky();
	h.eat();
	h.drink();
	h.lookHome();
	h.breakHome();
	
	ChineseDog cd = new ChineseDog();
	cd.eat();
	cd.drink();
	cd.lookHome();
}
}

运行结果:

JAVA基础(面向对象进阶) —— 继承_第17张图片

3.  构造方法的访问特点

  1. 父类中的构造方法不会被子类继承
  2. 子类中所有的构造方法默认先访问父类的无参构造,再执行自己。

为什么?

  • 子类在初始化之前,有可能会使用父类中的数据,如果父类没有完成初始化,子类将无法使用父类的数据。
  • 子类初始化之前,一定要调用父类构造方法先完成父类数据空间的初始化。

怎么调用父类构造方法的?

  • 子类构造方法的第一行语句默认都是:super(),不写也存在,且必须放在第一行。
  • 如果想调用父类有参构造,必须手动写super进行调用。
//Person.java

public class Person {
	String name;
	int age;
	
	public Person(){
		System.out.println("父类的无参构造");
	}
	public Person(String name,int age) {
		this.name = name;
		this.age = age;
	}
}


//Student.java

public class Student extends Person{
	public Student() {
		//子类构造方法中隐藏的super()去访问父类的无参构造
		super();
		System.out.println("子类的无参构造");
		//super()放下面会报错

	}
	public Student(String name,int age) {
		//调用父类带参构造
		super(name,age);
	}
}
//测试类

public class Test {
	public static void main(String[] args) {
		//创建学生对象
		Student stu1 = new Student();
		//此时new Student()中没有数据 将调用子类无参构造
		//结果:父类无参构造  子类无参构造
		
		Student stu2 = new Student("zhangsan",23);
		System.out.println(stu2.name + "," + stu2.age);
	}
}

运行结果:

 五、 this、super使用总结

  • this:理解为一个变量,表示当前方法调用者的地址值;

JAVA基础(面向对象进阶) —— 继承_第18张图片

  •  super:代表父类存储空间
关键字 访问成员变量 访问成员方法 访问构造方法
this

this.成员变量

访问本类成员变量

this.成员方法( )

访问本类成员方法

this( )

访问本类构造方法

super

super.成员变量

访问父类成员变量

super.成员方法( )

访问父类成员方法

super( )

访问父类构造方法

 练习:带有继承结构的标准Javabean类

1.经理
成员变量:工号,姓名,工资,管理奖金

成员方法:工作(管理其他人),吃饭(吃米饭)
2.厨师
成员变量:工号,姓名,工资
成员方法:工作(炒菜),吃饭(吃米饭)

//Employee.java

public class Employee {
	private String id;
	private String name;
	private double salary;
	
	public Employee() {}
	public Employee(String id,String name,double salary) {
		this.id = id;
		this.name = name;
		this.salary = salary;
	}
	
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	
	public  void work() {
		System.out.println("员工在工作");
	}
	public void eat() {
		System.out.println("吃米饭");
	}
}

//Manager.java
public class Manager extends Employee{
	private double bouns;
	
	//空参构造
	public Manager() {}
	//带全部参数构造
	public Manager(String id,String name,double salary,double bouns) {
		super(id,name,salary);
		this.bouns = bouns;
	}
	
	public double getBouns() {
		return bouns;
	}
	public void setBouns(double bouns) {
		this.bouns = bouns;
	}
	
	@Override
	public void work() {
		System.out.println("管理其他人");
	}
}


//Cooker.java
public class Cooker extends Employee{
	
	public Cooker() {}
	public Cooker(String id,String name,double salary) {
		super(id,name,salary);
	}
	
	@Override
	public void work() {
		System.out.println("厨师在炒菜");
	}
}
//测试类
public class Test {
	public static void main(String[] args) {
		// 创建对象并赋值调用

		Manager m = new Manager("001", "张三", 15000, 8000);
		System.out.println(m.getId() + "," + m.getName() +
				"," + m.getSalary() + "," + m.getBouns());

		m.work();
		m.eat();

		Cooker c = new Cooker();
		c.setId("002");
		c.setName("李四");
		c.setSalary(8000);
		System.out.println(c.getId() + "," + c.getName() + "," + c.getSalary());
		c.work();
		c.eat();

	}
}

运行结果:

JAVA基础(面向对象进阶) —— 继承_第19张图片

你可能感兴趣的:(JAVA基础入门,java,开发语言)