面向对象_继承
in Java with 0 comment

面向对象_继承

in Java with 0 comment

面向对象特性:继承性

继承性的好处:

什么是继承性?

Java中对于继承性的规定。

  1. 一类可以被多个子类继承。
  2. Java只允许类的单继承,不允许多继承。
  3. 子父类是相对的概念。
  4. 子类直接继承的父类,称为直接父类;间接继承的父类,称为间接父类。
  5. 子类继承父类后,就获取了直接父类和间接父类所有声明的属性和方法。

Object类

  1. 如果我们没有显式的声明一个类的父类的话,则继承与java.lang.Object类。
  2. 所有java类(除java.lang.Object)都直接或间接继承java.lang.Object类。
  3. 意味着,所有的java类具有java.lang.Object类声明的功能

练习1-体验继承关系

Person类


/**
 * 父类 person
 * 
 * @author Administrator
 *
 */
public class Person {
	int age;
	//私有的方法,子类继承过去后,需要通过set/get方法获取
	private String name;

	public Person() {

	}

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

	//父类私有化方法后,子类只能在方法中调用此方法。
	private void eat() {
		System.out.println("吃饭");
	}

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

	//父类私有化属性后,子类只能通过set/get方法来调用
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	
}

Student

package com.eachwang.www.java;

/*
 * 子类
 * 在写这个类的过程中,我们发现这个类中的一些属性和方法与Person类重复了
 * 那我们是否可以获取Person类的方法和属性呢?
 * 那就是使用继承(extends)
 * 格式:class A extends B{ }
 * 这样A就继承了B的所有属性和方法
 * 继承后我们就可以将重复的内容注释掉了
 * 提供了代码的复用性,便于功能的扩展
 * 
 * 如果父类中的方法或属性是私有的,我们也是能够继承过来了。
 * 父类私有属性:通过父类中声明set/get方法来调用相关属性
 * 父类私有方法:在父类的其他方法中调用私有方法。
 * @author Administrator
 *
 */
public class Student extends Person {
//	String name;
//	int age;
	String cla;

	public Student() {

	}

	public Student(String name, int age, String cla) {
		setName(name);
//		this.name = name;
		this.age = age;
		this.cla = cla;
	}

//	public void eat() {
//		System.out.println("吃饭");
//	}
//
//	public void sleep() {
//		System.out.println("睡觉");
//	}

	public void study() {
		System.out.println("学习");
	}
}

ExtendTest

package com.eachwang.www.java;
/*
 * 
 */
public class ExtendTest {
	public static void main(String[] args) {
		Student student = new Student();
		//调用父类中的属性
		student.age = 18;
		//调用自己的属性
		student.cla = "高三2班";
		//调用父类中的方法
		student.sleep();
		//调用自己类中的方法
		student.study();
	}
}

多层继承

20200806152650

练习2

父类:

子类:

Eclipse Debug

20200806161440

  1. resume:跳到下一断点,无断点的话直接执行完毕。
  2. terminate:结束程序。
  3. Step info:进入方法。(F5)
  4. Step Over:执行下一行(F6)
  5. Step Return:跳出方法。(F7)
  6. Drop To Frame:返回方法第一行。(F8)

方法的重写(Override)

定义

继承父类中可以根据需要对从父类继承来的方法进行改造,也成为方法的重置。在程序执行时,子类的方法覆盖父类的方法。

重写的规定

方法的格式:

权限修饰符 返回值类型 方法名(形参列表) throws 异常{
	方法体;
}

约定:子类的方法叫做重写的方法,父类中的方法叫做被重写的方法。

  1. 子类重写的方法要与父类被重写的方法的方法名、形参列表相同。
  2. 子类重写的方法的权限修饰符一定要大于等于父类被重写的方法的权限修饰符。
    1. 特殊的:父类被重写的方法权限修饰符为private,子类无法构成重写。
  3. 返回值:
    1. void:父类的被重写的方法返回值是void,子类重写的方法必须是void
    2. 引用数据类型:父类的被重写的方法返回值是引用数据类型,子类重写的方法必须是引用数据类型的本身或它的子类。
    3. 基本数据类型:父类的被重写的方法返回值是基本数据类型,子类重写的方法必须一致。
  4. 异常:子类重写的方法抛出异常不大于父类被重写的方法抛出的异常
  5. 父类中static声明的方法(静态方法)不能被重写。

实例

Person,父类

/**
 * 父类
 * 
 */
public class Person {
	String name;
	int age;

	public Person() {
	}

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

	public void eat() {
		System.out.println("吃饭");
	}

	public void walk(int distance) {
		System.out.println("走路走了" + distance + "公里");
	}

	// 父类中私有的方法,子类无法构成重写
	private void show() {

	}
	
	public int show1() {
		return 0;
	}
	
	public Object show2() {
		return null;
	}
	
	public static void data() {}
}

Student,子类

public class Student extends Person {
	String major;

	public Student() {
	}

	public Student(String name, int age, String major) {
		this.name = name;
		this.age = age;
		this.major = major;
	}

	public void major() {
		System.out.println("专业是:" + major);
	}

	// 如果权限修饰符是缺省,会报错
	// Cannot reduce the visibility of the inherited method from Person
	// 所以,子类的权限修饰符一定要大于等于父类的权限修饰符
	public void eat() {
		System.out.println("学生去食堂吃饭");
	}

	// 父类中私有的方法,子类无法构成重写
	private void show() {

	}
	
	//父类中返回值基本数据类型int,子类必须一样。
//	public long show1() {
//		return 0;
//	}
	
	//父类返回值类型是Object,子类的返回值必须是Object本身或其子类
	public Student show2() {
		return null;
	}
	
	//静态的方法无法构成重写
	public static void data() {}
}

Test,测试类

public class Test {
	public static void main(String[] args) {
		Student student = new Student();
		student.age = 10;
		student.eat();
		student.major = "计算机系";
		student.major();
	}
}

关键字super

概念

  1. **作用:父类的.... **,使用在子类,可以调用父类的方法、属性、构造器。
  2. 属性与方法中使用:
    • 我们在子类的方法或构造器中,通过使用“super.方法/属性”的方式,显式的调用父类中的方法或属性。但通常情况下我们习惯省略“super.”
    • 特殊情况:当子类和父类定义了同名的属性时,想要在子类中调用父类中声明的属性,则必须显式的使用“super.属性”的方法,表明调用的是父类中的属性。
    • 特殊情况:当子类重写的父类的方式时,想要在子类中调用父类中声明的方法,则必须显式的使用“super.方法”的方法,表明调用的是父类中的方法。
  3. 构造器中使用:
    • 在子类的构造器中显式的使用“super(形参列表)”的方式,调用父类中指明的构造器。
    • super(形参列表)必须声明在子类构造器的首行。
    • 在类的构造器中,super(形参)和this(形参)只能二选一。
    • 我们在类的构造器的首行中,没有显示的声明super(形参)和this(形参),则默认有一个super(),调用父类中的空参构造器。
    • 在类的多个构造器中,至少有一个类的构造器使用了super(),调用父类的构造器。

练习

父类

public class Person {
	String name;
	int age;
	int id = 370111;// 身份证号

	public Person() {

	}

	public Person(String name) {
		this.name = name;
	}

	public Person(int age) {
		this.age = age;
	}

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

	public void eat() {
		System.out.println("人:吃饭");
	}

	public void walk() {
		System.out.println("人:说话");
	}
}

子类

public class Student extends Person {
	String major;
	int id = 200001;// 学号

	public Student() {
	}

	public Student(String major) {
		this.major = major;
	}

	public Student(String name, int age, String major) {
		//调用父类的构造器
		super(name, age);
		this.major = major;
	}

	public void study() {
		System.out.println("学生:学习知识");
	}

	public void show() {
		System.out.println("姓名:" + this.name + ",年龄:" + super.age);
		System.out.println("学号:" + this.id);
		System.out.println("身份证号:" + super.id);
	}

	@Override
	public void eat() {
		System.out.println("学生:吃有营养食物");
	}

	public void show2() {
		eat();
		this.eat();
		super.eat();
	}
}

测试类

public class Test {
	public static void main(String[] args) {
		Student student = new Student();
		System.out.println("```调用子类或父类的属性```");
		student.show();
		System.out.println("```调用子类或父类的方法```");
		student.show2();
		System.out.println("```调用父类的构造器```");
		Student student2 = new Student("Tom", 21, "电子商务");
		student2.show();
	}
}

20200810111338

子类对象实例化过程

20200810110008

  1. 从结果上看:
    • 子类继承父类后,就获取了父类中声明的属性或方法。
    • 创建子类对象,在堆空间,就回家再所有父类中声明的属性。
  2. 从过程上看:
    • 当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器.....直到调用了java.lang.Object类中的空参构造器为止。
    • 正因为加载过所有父类的结构,所以才可以看到内存中有父类的结构,子类对象才可以进行调用。
  3. 明确的,虽然创建了父类的构造器,但自始至终就创建了一个对象,即为new的子类对象。

继承练习

创建一个账户类Account,有属性余额,账号,年利率,提供三个属性的set/get方法,提供存钱,取钱的方法。
编写账户类的测试类。
创建一个信用卡类CheckAccount,继承Account,添加独有属性透支额度,重写取钱方法。
编写信用卡类的测试类。

public class Account {
	private int id;// 银行卡号
	private double balance;// 余额
	private double annualProfit;// 年利率

	public Account(int id, double balance, double annualProfit) {
		this.id = id;
		this.balance = balance;
		this.annualProfit = annualProfit;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public double getBalance() {
		return balance;
	}

	public void setBalance(double balance) {
		this.balance = balance;
	}

	public double getAnnualProfit() {
		return annualProfit;
	}

	public void setAnnualProfit(double annualProfit) {
		this.annualProfit = annualProfit;
	}

	// 存钱
	public void deposit(double balance) {
		if (balance <= 0) {
			return;
		}
		this.balance += balance;
	}

	// 取钱
	public void withdraw(double balance) {
		if (balance > this.balance) {
			System.out.println("余额不足");
			return;
		}
		this.balance -= balance;
	}
}


public class AccountTest {
	public static void main(String[] args) {
		Account account = new Account(1001, 20000, 0.05);
		account.withdraw(5000);
		System.out.println("账户余额:" + account.getBalance());
		account.withdraw(50000);
		System.out.println("账户余额:" + account.getBalance());
		account.deposit(6000);
		System.out.println("账户余额:" + account.getBalance());
	}
}


public class CheckAccount extends Account {
	private double checkBalance;

	public CheckAccount(int id, double balance, double annualProfit, double checkBalance) {
		super(id, balance, annualProfit);
		this.checkBalance = checkBalance;
	}

	public double getCheckBalance() {
		return checkBalance;
	}

	public void setCheckBalance(double checkBalance) {
		this.checkBalance = checkBalance;
	}

	@Override
	public void withdraw(double balance) {
		if (balance <= getBalance()) {// 余额足够
			// 方式1
//			setBalance(getBalance() - balance);
			// 方式二
			super.withdraw(balance);
		} else if (checkBalance >= balance - getBalance()) {
			checkBalance -= (balance - getBalance());
			// 方式1
//			setBalance(0);
			setBalance(getBalance() - getBalance());
		} else {
			System.out.println("超出透支额度!");
		}
	}
}

public class CheckTest {
	public static void main(String[] args) {
		CheckAccount acc = new CheckAccount(1002, 20000, 0.05, 5000);
		acc.withdraw(5000);
		System.out.println("账户余额:" + acc.getBalance());
		System.out.println("透支余额:" + acc.getCheckBalance());

		acc.withdraw(15500);
		System.out.println("账户余额:" + acc.getBalance());
		System.out.println("透支余额:" + acc.getCheckBalance());

		acc.withdraw(55000);
		System.out.println("账户余额:" + acc.getBalance());
		System.out.println("透支余额:" + acc.getCheckBalance());

		acc.deposit(2000);
		System.out.println("账户余额:" + acc.getBalance());
		System.out.println("透支余额:" + acc.getCheckBalance());
	}
}

Day11问题

  1. 客户信息管理系统代码