前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【10】JAVASE-面向对象-继承【从零开始学JAVA】

【10】JAVASE-面向对象-继承【从零开始学JAVA】

作者头像
用户4919348
发布2024-05-25 14:02:50
320
发布2024-05-25 14:02:50
举报
文章被收录于专栏:波波烤鸭波波烤鸭

Java零基础系列课程-JavaSE基础篇

Lecture:波哥

Java 是第一大编程语言和开发平台。它有助于企业降低成本、缩短开发周期、推动创新以及改善应用服务。如今全球有数百万开发人员运行着超过 51 亿个 Java 虚拟机,Java 仍是企业和开发人员的首选开发平台。

四、继承

1.继承的语法格式

格式

代码语言:javascript
复制
class 子类名称 extends 父类名称{
    
}

被继承的这个类称为父类、 基类或者 超类

继承的这个类称为子类 或者 派生类

2. 继承的案例

父类:

代码语言:javascript
复制
package com.bobo.oop08;

/**
 * 这是个Person类,抽取了 Student、Doctor、Police三个类的公共代码
 * @author dpb
 *
 */
public class Person {
	
	public String name;

	public int age;

	public String gender;

	public void sleep() {
		System.out.println("sleep .... ");
	}
}

Student,Police,Doctor三个子类

代码语言:javascript
复制
package com.bobo.oop08;

/**
 * 这是一个学生类
 * @author dpb
 *
 */
public class Student extends Person{
	
	public String stuNo; // 学生编号
	
	public void study(){
		System.out.println("study ....");
		
	}
}

Police

代码语言:javascript
复制
package com.bobo.oop08;

/**
 * 这是一个警察类
 * @author dpb
 *
 */
public class Police extends Person{
	
	public String policeNo; // 警员编号
	
	
	/**
	 * 抓坏人的方法
	 */
	public void catchBadGuys(){
		System.out.println(".....");
		
	}
}

Doctor

代码语言:javascript
复制
package com.bobo.oop08;

/**
 * 这是一个医生类
 * @author dpb
 *
 */
public class Doctor extends Person{
	
	
	public String doctorNum; // 医生编号
	
	public String department; // 部门
	
	
	public void savePeople(){
		System.out.println("save ...");
	}
}

3.继承的好处

  1. 简化了代码
  2. 提高了代码的可维护性
  3. 提高了扩展性

4.继承的缺点

开发设计思想:高内聚低耦合(尽量在一个类里面内聚,类和类之间的关系尽量保持独立)

继承后耦合性提高,牵一发动全身, 这个缺点不能改进,在Java中里面尽量不要使用继承

5. 继承的注意事项

  1. 继承是对一批类的抽象,类是对一批对象的抽象
  2. Java中只支持单继承,不支持多继承,但是支持多层继承
  3. 子类可以继承父类private修饰的属性和方法,但是不可见
  4. 子类不可以继承父类构造方法
  5. 子类出来继承父类的属性和方法以外,还可以添加自己的属性和方法

6. 怎么使用继承

继承的本质是什么? --> 简化代码

  1. 先写出所有的子类,观察子类共有的成员变量和成员方法
  2. 抽象出共同点,书写出父类
  3. 让子类区继承父类,并把子类中的共有属性删除

7.课堂案例

1、定义一个人类(姓名,年龄,性别,吃,睡) ,学生类继承人类(学号,班级,课程) ,老师类继承人类(工号,教龄,教书)

代码语言:javascript
复制
package com.bobo.oop09;

/**
 * 姓名,年龄,性别,吃,睡
 * @author dpb
 *
 */
public class Person {

	public String name;
	
	public int age;
	
	public String gender;
	
	public void eat(){
		System.out.println("Person.eat() ....");
	}
	
	public void sleep(){
		System.out.println("Person.sleep() ...");
	}
}
代码语言:javascript
复制
package com.bobo.oop09;

/**
 * 老师类继承人类(工号,教龄,教书)
 * @author dpb
 *
 */
public class Teacher extends Person{

	public String workNum;
	
	public int schoolAge;
	
	public String course;
	
	
}
代码语言:javascript
复制
package com.bobo.oop09;

/**
 * 学生类继承人类(学号,班级,课程)
 * @author dpb
 *
 */
public class Student extends Person{
	
	public String stuNo;
	
	public String className;
	
	public String course;
	
}

8. super关键字

​ super关键字可以理解为 父类对象,this关键字表示当前对象

​ 当一个属性的使用没有添加this或者super关键字,那么他的查找顺序是 局部变量–>成员变量–>父类变量 如果还没有找到那么就会包编译异常。

​ 被this修饰的变量,如果本类的成员变量中没有找到,同样也会去父类中查找

​ 被super修饰的变量只会从父类中查找,如果父类中没有,而子类中存在,同样会报编译错误

super和this关键字访问成员的区别

成员变量

  1. this.成员变量
  2. super.成员变量 super 是不能访问私有的成员变量的,可以通过访问对应的共有方法实现

成员方法:

  1. this.成员方法
  2. super.成员方法

构造方法:

  1. this(参数列表);
  2. super(参数列表); 任何一个构造方法都默认的会在构造方法的第一句上写上 super(); 访问父类的无参构造方法 目的是初始化父类的成员变量 Constructor call must be the first statement in a constructor

super和this方法构造方法都必须出现在构造方法的第一句,this和super在方法构造方法的时候,二者是不能共存

static静态的上下文都是不能出现this和super的

案例代码:

代码语言:javascript
复制
package com.bobo.oop01;

public class Son extends Father{
	

	/**
	 * 在子类中定义了一个和父类中同名的属性
	 * 子类中定义的同名的属性会覆盖掉父类中的属性
	 */
	public int num = 30;
	
	public void show(){
		// 局部变量会覆盖掉成员变量
		//int num = 40;
		// 输出局部变量
		System.out.println("num:" + num);
		// 输出成员变量
		System.out.println("num:" + this.num);
		// 输出父类的成员变量
		System.out.println("num:" + super.num);
		System.out.println(super.getAge());
		eat();
	}
	
	public Son(){
		// 在构造方法中,默认都会添加一句 super(); 而且必须是第一行 
		// Constructor call must be the first statement in a constructor
		System.out.println("Son 子类构造器执行了...");
	}
	
	public Son(int num){
		this();
		//super(); 会在无参构造方法中执行 super(); 此处如果再执行一次就会出现两次初始化父类中成员变量的情况
	}

}
代码语言:javascript
复制
package com.bobo.oop01;

public class Father {
	
	public int num = 10;
	
	private int age ;
	
	public void eat(){
		System.out.println("Father.eat ...");
	}
	
	public Father(){
		System.out.println("Father 。。。。构造器执行了");
	}

	public int getAge() {
		return age;
	}
}
代码语言:javascript
复制
package com.bobo.oop01;

public class OOPDemo01 {

	public static void main(String[] args) {
		Son son = new Son();
		son.show();

	}
}

9. 访问权限修饰符

作用:表示被修饰的元素的访问权限

访问权限修饰符有四个: public protected [default] private

访问权限修饰符可以修饰的元素:

  1. 类 只有public、abstract和final能够修饰,或者不加【private和protected可以修饰内部类】
  2. 成员变量
  3. 成员方法

四个修饰符的特点

  1. public修饰的成员对一切类可见
  2. protected修饰的成员本包下面都可见,不同包下只有子类可见
  3. default修饰的成员仅对同包下面的可见
  4. private修饰的成员仅对本类可见

Java中的封装就是通过访问权限修饰符来实现的

访问权限修饰符的宽严的关系

代码语言:javascript
复制
public  > protected  >  default  >  private

public

protected

[default]

private

同一类中

同一包中子类、其它类

不同包中子类

不同包中其它类

10. 方法的重写

​ 如果从父类继承的方法不能满足子类的需求的情况下,可以对其进行改写,这个过程叫方法的覆盖(override),也称为方法的重写,子类中出现了和父类中一模一样的方法声明,,也称为方法的覆盖或者方法的复写。

方法的重写的规则

  1. 方法名称相同
  2. 参数列表相同
  3. 返回值类型相同或者是其子类
  4. 访问权限修饰符不能严于父类

方法重写的注意事项:

  1. 父类中的私有的方法不能重写的
  2. 构造方法不能被重写
  3. 子类重写父类方法时,访问权限不能更低
  4. 重载和重写的区别

面试题:

重载和重写的区别:

重载的定义:

  1. 同一个类中
  2. 方法名称相同
  3. 参数列表不同
  4. 和返回值及访问权限修饰符没有关系

位置

方法名

参数列表

返回值

访问权限修饰符

方法重写

子类

相同

相同

相同或者子类

不能严于父类

方法重载

同类

相同

不相同

没有关系

没有关系

11. 课堂案例讲解

(1)设计一个User类,其中包括用户名、口令等属性以及构造方法(至少重载2个)。获取和设置口令的方法,显示和修改用户名的方法等。编写应用程序测试User类。

代码语言:javascript
复制
package com.bobo.oop05;

public class OOPDemo01 {

	/**
	 * 设计一个User类,其中包括用户名、口令等属性以及构造方法(至少重载2个)。
	 * 获取和设置口令的方法,显示和修改用户名的方法等。编写应用程序测试User类。
	 * @param args
	 */
	public static void main(String[] args) {
		User user = new User("admin","123");
		System.out.println(user.getUserName()); 
		System.out.println(user.getPassword());

	}

}
class User{
	
	private String userName;
	
	private String password;
	
	public User(){
	}
	
	public User(String userName,String password){
		this.userName = userName;
		this.password = password;
	}

	public String getUserName() {
		return userName;
	}

	public void setUserName(String userName) {
		this.userName = userName;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}
}

(2)定义一个Student类,其中包括用户名、密码、姓名、性别、出生年月等属行以及init()——初始化各属性、display()——显示各属性、modify()——修改姓名等方法。实现并测试这个类。

代码语言:javascript
复制
package com.bobo.oop05;

public class OOPDemo02 {

	/**
	 * 定义一个Student类,其中包括用户名、密码、姓名、性别、出生年月等属行
	 * 以及init()——初始化各属性、display()——显示各属性、
	 * modify()——修改姓名等方法。实现并测试这个类。
	 * @param args
	 */
	public static void main(String[] args) {
		Student stu = new Student();
		// 初始成员变量
		stu.init("root", "123", "波波老师", "男", "198704");
		// 打印信息
		stu.display();
		// 修改姓名
		stu.modify("张三");
		// 打印信息
		stu.display();

	}

}

class Student{
	private String userName;
	private String password;
	private String name;
	private String gender;
	private String birth;
	
	/**
	 * 初始化成员变量
	 * @param userName
	 * @param password
	 * @param name
	 * @param gender
	 * @param birth
	 */
	public void init(String userName,String password
			,String name,String gender,String birth)
	{
		this.userName = userName;
		this.password = password;
		this.name = name;
		this.gender = gender;
		this.birth = birth;
		
	}
	
	/**
	 * 打印各个属性的方法
	 */
	public void display(){
		System.out.println("userName=" + this.userName
				+ "\t password=" + this.password
				+ "\t name=" + this.name
				+ "\t gender=" + this.gender
				+ "\t birth="+this.birth);
	}
	
	/**
	 * 修改姓名的方法
	 * @param name
	 */
	public void modify(String name){
		this.name = name;
	}
}

(3)从上题的Student类中派生出Granduate(研究生)类,添加属性:专业subject、导师adviser。重载相应的成员方法。并测试这个类。

代码语言:javascript
复制
package com.bobo.oop05;

public class OOPDemo02 {

	/**
	 * 定义一个Student类,其中包括用户名、密码、姓名、性别、出生年月等属行
	 * 以及init()——初始化各属性、display()——显示各属性、
	 * modify()——修改姓名等方法。实现并测试这个类。
	 * @param args
	 */
	public static void main(String[] args) {
		/*Student stu = new Student();
		// 初始成员变量
		stu.init("root", "123", "波波老师", "男", "198704");
		// 打印信息
		stu.display();
		// 修改姓名
		stu.modify("张三");
		// 打印信息
		stu.display();*/
		Granduate  g = new Granduate();
		g.init("root", "123", "波波老师", "男", "198704","医学专业","xxxx");
		g.display();
		g.modify("aaa");
		g.display();

	}

}

class Student{
	public String userName;
	public String password;
	public String name;
	public String gender;
	public String birth;
	
	/**
	 * 初始化成员变量
	 * @param userName
	 * @param password
	 * @param name
	 * @param gender
	 * @param birth
	 */
	public void init(String userName,String password
			,String name,String gender,String birth)
	{
		this.userName = userName;
		this.password = password;
		this.name = name;
		this.gender = gender;
		this.birth = birth;
		
	}
	
	/**
	 * 打印各个属性的方法
	 */
	public void display(){
		System.out.println("userName=" + this.userName
				+ "\t password=" + this.password
				+ "\t name=" + this.name
				+ "\t gender=" + this.gender
				+ "\t birth="+this.birth);
	}
	
	/**
	 * 修改姓名的方法
	 * @param name
	 */
	public void modify(String name){
		this.name = name;
	}
}
/**
 * 从上题的Student类中派生出Granduate(研究生)类,
 * 添加属性:专业subject、导师adviser。重载相应的成员方法。并测试这个类。
 * @author dpb
 *
 */
class Granduate extends Student{
	public String subject;
	
	public String adviser;
	
	/**
	 * 重载的init方法  实现子类成员变量的初始化和父类中的成员变量的初始化操作
	 * @param subject
	 * @param adviser
	 */
	public void init(String userName,String password
			,String name,String gender,String birth,String subject,String adviser){
		super.init(userName, password, name, gender, birth);
		this.subject = subject;
		this.adviser = adviser;
	}
	
	@Override
	public void display() {
		// TODO Auto-generated method stub
		System.out.println("userName=" + this.userName
				+ "\t password=" + this.password
				+ "\t name=" + this.name
				+ "\t gender=" + this.gender
				+ "\t birth="+this.birth
				+ "\t subject=" + this.subject
				+ "\t adviser=" + this.adviser);
	}
}

(4)创建两个具有继承结构的两个类,父类和子类均有自己的静态代码块、构造方法。观察他们的运行顺序。

代码语言:javascript
复制
package com.bobo.oop05;

public class OOPDemo03 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		Son son1 = new Son();
		Son son2 = new Son();
		Son son3 = new Son();
		
	}

}
/**
 *  创建两个具有继承结构的两个类,
 *  父类和子类均有自己的静态代码块、构造方法。观察他们的运行顺序。
 * @author dpb
 *
 */
class Father{
	
	static{
		System.out.println("father ... 静态代码块");
	}
	public Father(){
		System.out.println("father 构造方法...");
	}
}

class Son extends Father{
	static{
		System.out.println("son .... 静态代码块");
	}
	
	public Son(){
		System.out.println("son ... 构造方法");
	}
}

输出结果

代码语言:javascript
复制
father ... 静态代码块
son .... 静态代码块
father 构造方法...
son ... 构造方法
father 构造方法...
son ... 构造方法
father 构造方法...
son ... 构造方法

(5)编写一个汽车类Car 编写一个宝马类BMW 继承Car 编写一个奔驰类Benz 继承Car 在三个类中都有一个run方法,表示不同车在跑 编写一个人类Person,不同的对象有不同的车

代码语言:javascript
复制
package com.bobo.oop05;

public class OOPDemo04 {

	/**
	 * 编写一个汽车类Car
		编写一个宝马类BMW 继承Car
		编写一个奔驰类Benz 继承Car
		在三个类中都有一个run方法,表示不同车在跑
		编写一个人类Person,不同的对象有不同的车
	 * @param args
	 */
	public static void main(String[] args) {
		Car car = new Car();
		BMW bmw = new BMW();
		Benz benz = new Benz();
		
		Person p1 = new Person(car);
		Person p2 = new Person(bmw);
		Person p3 = new Person(benz);
	}
}

class Car{
	public void run(){
		System.out.println("汽车在运行...");
	}
}

class BMW extends Car{
	
	@Override
	public void run() {
		// TODO Auto-generated method stub
		System.out.println("宝马车在运行...");
	}
}

class Benz extends Car{
	
	@Override
	public void run() {
		System.out.println("奔驰车在运行...");
	}
}

/**
 * 不同的对象又不同的车
 * @author dpb
 *
 */
class Person{
	
	public Car car;
	
	public  Person(Car car){
		this.car = car;
	}
	
}

(6)有农民(farmer),教师(teacher),科学家(scientist),服务生(attendant),其中农民,服务生只有基本工资.教师除基本工资外,还有课酬(元/天),科学家除基本工资外,还有年终奖,请你写出相关类,将各种类型的员工的全年工资打印出来

代码语言:javascript
复制
package com.bobo.oop05;

public class OOPDemo05 {

	/**
	 * 有农民(farmer),教师(teacher),科学家(scientist),服务生(attendant),
	 * 其中农民,服务生只有基本工资.教师除基本工资外,还有课酬(元/天),
	 * 科学家除基本工资外,还有年终奖,
	 * 请你写出相关类,将各种类型的员工的全年工资打印出来
	 * @param args
	 */
	public static void main(String[] args) {
		// TODO Auto-generated method stub

	}

}
// 农民
class Farmer{
	public double basePay; // 基本工资
	
	public void printYearSalary(){
		System.out.println("Farmer全年的工资:" + basePay * 12);
	}
}

class Attendant{
	public double basePay; // 基本工资
	
	public void printYearSalary(){
		System.out.println("Attendant全年的工资:" + basePay * 12);
	}
}

class Teacher extends Farmer{
	
	public double classFee; // 课时费(天)
	
	@Override
	public void printYearSalary() {
		System.out.println("教师的全年工资:" + this.basePay*12 + classFee * 200);
	}
}

class scientist extends Farmer{
	public double yearBonus; // 年终奖
	
	@Override
	public void printYearSalary() {
		System.out.println("科学家全年的收入是:" + this.basePay *12 + yearBonus);
	}  
}

(7)完成如下功能 a.设计一个表示二维平面上点的类Point,包含有表示坐标位置的protected 类型的 成员变量x 和y,获取和设置x 和y 值的public 方法。 b.设计一个表示二维平面上圆的类Circle,它继承自类Point,还包含有表示圆半径 的protected 类型的成员变量r、获取和设置r 值的public 方法、计算圆面积的public 方 法。 c.设计一个表示圆柱体的类Cylinder,它继承自类Circle,还包含有表示圆柱体高的 protected 类型的成员变量h、获取和设置h 值的public 方法、计算圆柱体体积的public 方法。 d.建立Cylinder 对象,输出其轴心位置坐标、半径、面积、高及其体积的值。

代码语言:javascript
复制
package com.bobo.oop05;

public class OOPDemo06 {

	/**
	 * 完成如下功能
		a.设计一个表示二维平面上点的类Point,包含有表示坐标位置的protected 类型的
			成员变量x 和y,获取和设置x 和y 值的public 方法。
		b.设计一个表示二维平面上圆的类Circle,它继承自类Point,还包含有表示圆半径
			的protected 类型的成员变量r、获取和设置r 值的public 方法、计算圆面积的public 方
			法。	
		c.设计一个表示圆柱体的类Cylinder,它继承自类Circle,还包含有表示圆柱体高的
			protected 类型的成员变量h、获取和设置h 值的public 方法、计算圆柱体体积的public
			方法。
		d.建立Cylinder 对象,输出其轴心位置坐标、半径、面积、高及其体积的值。
	 * @param args
	 */
	public static void main(String[] args) {
		Cylinder c = new Cylinder();
		c.x = 1;
		c.y = 1;
		c.r = 2;
		c.h = 2;
		System.out.println("圆心点的底坐标是(" +c.getX() + ","+c.getY()+")");
		System.out.println("圆的半径是:" + c.getR());
		System.out.println("圆的面积是:" + c.getArea());
		System.out.println("圆柱体的体积是:" + c.getVolume());

	}

}

/**
 * a.设计一个表示二维平面上点的类Point,包含有表示坐标位置的protected 类型的
		成员变量x 和y,获取和设置x 和y 值的public 方法。
 * @author dpb
 *
 */
class Point{
	protected int x;
	protected int y;
	public int getX() {
		return x;
	}
	public void setX(int x) {
		this.x = x;
	}
	public int getY() {
		return y;
	}
	public void setY(int y) {
		this.y = y;
	}
}

/**
 * b.设计一个表示二维平面上圆的类Circle,它继承自类Point,还包含有表示圆半径
		的protected 类型的成员变量r、获取和设置r 值的public 方法、计算圆面积的public 方
		法。
 * @author dpb
 *
 */
class Circle extends Point{
	
	protected int r;

	public int getR() {
		return r;
	}

	public void setR(int r) {
		this.r = r;
	}
	
	/**
	 * 获取圆面积的方法
	 *   pi*r*r
	 * @return
	 */
	public double getArea(){
		return Math.PI * this.r * this.r;
	}
	
}

/**
 * c.设计一个表示圆柱体的类Cylinder,它继承自类Circle,还包含有表示圆柱体高的
		protected 类型的成员变量h、获取和设置h 值的public 方法、计算圆柱体体积的public
		方法。
 * @author dpb
 *
 */
class Cylinder extends Circle{
	
	protected int h;

	public int getH() {
		return h;
	}

	public void setH(int h) {
		this.h = h;
	}
	
	
	/**
	 * 计算圆柱体 体积的方法
	 * 面积*高
	 * @return
	 */
	public double getVolume(){
		return super.getArea() * this.h;
	}	
}

输出的结果:

代码语言:javascript
复制
圆心点的底坐标是(1,1)
圆的半径是:2
圆的面积是:12.566370614359172
圆柱体的体积是:25.132741228718345

12. final关键字

final关键字是 最终 的意思,可以修饰类,变量和方法

12.1 修饰类

该类就不能被继承

12.2 修饰变量

变量会变为常量,只能赋值一次,之后就不能改变了, final修饰的变量称为常量,常量名我们都大写,常量一般我们会声明为static

​ 成员变量:在定义的同时必须给出初始值。

​ 局部变量:可以在使用之前赋值

12.3 修饰方法

final修饰的方法,子类是不能重写该方法的!

代码语言:javascript
复制
Cannot override the final method from Person
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-05-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Java零基础系列课程-JavaSE基础篇
  • 四、继承
    • 1.继承的语法格式
      • 2. 继承的案例
        • 3.继承的好处
          • 4.继承的缺点
            • 5. 继承的注意事项
              • 6. 怎么使用继承
                • 7.课堂案例
                  • 8. super关键字
                    • 9. 访问权限修饰符
                      • 10. 方法的重写
                        • 11. 课堂案例讲解
                          • 12. final关键字
                            • 12.1 修饰类
                            • 12.2 修饰变量
                            • 12.3 修饰方法
                        领券
                        问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档