第12 章 : 繼承的定義與使用
59 繼承問題引出
繼承:擴充已有類的功能
60 繼承的實作
class 子類 extends 父類
子類:派生類
父類:超類
繼承實作的主要目的
子類可以重用父類中的結構,并且擴充功能
class Person{
private String name ;
private int age ;
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public Person(String name, int age){
this.name = name ;
this.age = age ;
}
}
class Student extends Person{
String school ;
public void setSchool(String school){
this.school = school ;
}
public String getSchool(){
return this.school ;
}
public Student(String name, int age, String school){
super(name, age);
this.school = school ;
}
}
class Demo{
public static void main(String[] args) {
Student student = new Student("張三" , 23, "大學");
System.out.println(student.getName());
// 張三
System.out.println(student.getSchool());
// 大學
}
}
61 子類對象執行個體化流程
子類執行個體化會自動調用父類構造方法
預設執行 super()
子類構造方法預設調用父類無參構造方法,隻允許放在子類構造方法首行
結論:
定義類的時候最好寫無參構造方法
執行個體化子類對象的同僚一定會執行個體化父類對象
class Person{
private String name ;
private int age ;
public Person(){}
public Person(String name, int age){
this.name = name ;
this.age = age ;
}
}
class Student extends Person{
public Student(String name, int age){
super(name, age); // 調用父類構造方法
}
}
class Demo{
public static void main(String[] args) {
Student student = new Student("張三" , 23);
}
}
super, this 兩個語句不能同時出現
相同點:
1、都可以調用構造方法
2、都隻能放在構造方法首行
不同點:
1、super 調用父類構造方法
2、this 調用本類構造方法
62 繼承定義限制
Java不允許多重繼承,隻允許多層繼承
多重繼承
class A{}
class B{}
class C extends A, B{}
多層繼承, 一脈傳承
class A{}
class B extends A{}
class C extends B{}
繼承關系最好不要超過三層
子類可以繼承父類中所有操作結構
顯式繼承非私有操作
隐式繼承私有操作
class Person{
private String name ;
public String getName(){
return this.name ;
}
public Person(){}
public Person(String name){
this.name = name ;
}
}
class Student extends Person{
public void fun(){
// 錯誤, 子類不能通路父類中的私有屬性
// System.out.println(this.name);
// 子類間接通路父類中的私有屬性
System.out.println(this.getName());
// 張三
}
public Student(String name){
super(name);
}
}
class Demo {
public static void main(String[] args) {
Student student = new Student("張三");
student.fun();
}
}
63 方法覆寫
覆寫意義:優化功能
子類調用父類方法
super.方法()
調用本類方法, this可省略
this.方法()
class Resource{
public void connect(){
System.out.println("資源連接配接");
}
}
class Database{
public void connect(){
System.out.println("資料庫資源連接配接");
}
}
class Demo{
public static void main(String[] args) {
Database db = new Database();
// 調用子類的方法
db.connect();
// 資料庫資源連接配接
}
}
64 方法覆寫限制
覆寫的方法通路控制權限要 大于等于 父類方法控制權限
通路權限控制
public > default(不寫) > private
差別Override Overloading
Override 覆寫
概念:方法名,簽名(參數類型,個數),傳回值相同
權限:被覆寫的方法不能有更嚴格的權限控制
範圍:發生在繼承關系中
Overloading 重載
概念:方法名相同,簽名(參數類型,個數)不同,推薦傳回類型一緻
權限:沒有權限控制
範圍:發生在一個類中
65 屬性覆寫
屬性覆寫:子類定義了與父類相同名稱的成員
差別:this super
this 先查找本類,再查找父類,this可以表示本類對象
super 直接查找父類
class Father{
private String name = "Father" ;
}
class Child{
private String name = "Child" ;
public String getName(){
return this.name;
}
}
class Demo{
public static void main(String[] args) {
Child child = new Child();
System.out.println(child.getName()) ;
// Child
}
}
66 final關鍵字
final 定義不能被繼承的類,不能被覆寫的方法,常量
final class Demo{} // 不能有子類
class Demo{
public final void fun(){} // 不能被覆寫
}
class Demo{
private final int ON = 1 ; // 常量不能被重新指派
private final int OFF = 0 ;
}
常量往往都是公共的,全局常量
public static final int ON = 1 ;
public static final int OFF = 0 ;
常量每個字元都必須大寫
67 案例分析一(學生類)
簡單Java類
學生類繼承人類
人類
-四個屬性:name,address, sex, age
-三個構造:四參,兩參,無參
-一個方法:顯示輸出
學生
-增加兩個屬性:math,english
-三個構造:六參,兩餐,無參
-一個重寫方法:顯示輸出
class Person{
private String name ;
private int age ;
private String address;
private char sex;
public void setName(String name){
this.name = name ;
}
public void setAge(int age){
this.age = age ;
}
public void setAddress(String address){
this.address = address ;
}
public void setSex(char sex){
this.sex = sex ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public String getAddress(){
return this.address ;
}
public char getSex(){
return this.sex ;
}
public Person(){}
public Person(String name, int age){
// 調用本類構造方法
this(name, age, "", '男');
}
public Person(String name, int age, String address, char sex){
this.name = name ;
this.age = age ;
this.address = address ;
this.sex = sex ;
}
public String getInfo(){
return "name: " + this.name +
" age: " + this.age +
" address: " + this.address +
" sex: " + this.sex ;
}
}
// 繼承
class Student extends Person{
private double math ;
private double english ;
public void setMath(double math){
this.math = math ;
}
public void setEnglish(double english){
this.english = english ;
}
public double getMath(){
return this.math ;
}
public double getEnglish(){
return this.english ;
}
// 重載構造方法
public Student(){}
public Student(String name, int age){
// 調用父類構造方法
super(name, age);
}
public Student(String name, int age, String address, char sex,
double math, double english){
super(name, age, address, sex);
this.math = math ;
this.english = english ;
}
// 覆寫父類方法
public String getInfo(){
return super.getInfo() +
" math: " + this.math +
" english: " + this.english ;
}
}
class Demo{
public static void main(String[] args) {
Student student = new Student("張三", 16, "北京", '男', 99.9, 87.9);
System.out.println(student.getInfo());
// name: 張三 age: 16 address: 北京 sex: 男 math: 99.9 english: 87.9
}
}
68 案例分析二(管理人員與職員)
員工類
-2個屬性 name, age
-2個構造 無參, 2參
-1個方法 顯示資訊
普通職員
-4屬性 name, age, dept, salary
-2構造 無參, 4參
管理人員
-4屬性 name, age, position, income
class Employee{
private String name ;
private int age ;
public Employee(){}
public Employee(String name, int age){
this.name = name ;
this.age = age ;
}
public String getInfo(){
return "name: " + this.name + " age: " + this.age ;
}
}
class Stuff extends Employee{
private String dept ;
private double salary ;
public Stuff(){}
public Stuff(String name, int age, String dept, double salary){
super(name, age);
this.dept = dept ;
this.salary = salary ;
}
public String getInfo(){
return "【Stuff】 " + super.getInfo() +
" dept: " + this.dept +
" salary: " + this.salary;
}
}
class Manager extends Employee{
private String position ;
private double income ;
public Manager(){}
public Manager(String name, int age, String position, double income){
super(name, age);
this.position = position ;
this.income = income ;
}
public String getInfo(){
return "【Manager】 " + super.getInfo() +
" position: " + this.position +
" income: " + this.income;
}
}
class Demo{
public static void main(String[] args) {
Stuff stuff = new Stuff("張三", 23, "技術部", 3000.0);
Manager manager = new Manager("李四", 32, "技術總監", 150000.0);
System.out.println(manager.getInfo());
// 【Manager】 name: 李四 age: 32 position: 技術總監 income: 150000.0
System.out.println(stuff.getInfo());
// 【Stuff】 name: 張三 age: 23 dept: 技術部 salary: 3000.0
}
}
69 案例分析三(字元串統計)
統計 字元o 和 n 出現的次數 do you know?
方式一:傳回數組
class CountDemo{
// 統計兩個字元個數,第一個為o, 第二個為u
public static int[] getCount(String str){
int[] countData = new int[2] ;
char[] data = str.toCharArray() ;
for(char c : data){
if(c == 'o' || c == 'O'){
countData[0] ++;
}
else if(c == 'u' || c == 'U'){
countData[1] ++;
}
}
return countData;
}
public static void main(String[] args) {
int[] countData = CountDemo.getCount("are you ok?") ;
System.out.println("o: " + countData[0]); // o: 2
System.out.println("u: " + countData[1]); // u: 1
}
}
方式二:傳回對象
class StringUtil{
private String content ;
public StringUtil(String content){
this.content = content ;
}
public String getContent(){
return this.content ;
}
}
class CountDemo extends StringUtil {
private int oCount = 0;
private int uCount = 0;
public CountDemo(String content){
super(content) ;
this.countChar() ; //構造方法調用統計
}
// 統計兩個字元個數
public void countChar(){
char[] data = super.getContent().toCharArray() ;
for(char c : data){
if(c == 'o' || c == 'O'){
this.oCount ++;
}
else if(c == 'u' || c == 'U'){
this.uCount ++;
}
}
}
public int getOCount(){
return this.oCount ;
}
public int getUCount(){
return this.uCount ;
}
}
class Demo{
public static void main(String[] args) {
CountDemo countData = new CountDemo("are you ok?") ;
System.out.println("o: " + countData.getOCount()); // o: 2
System.out.println("u: " + countData.getUCount()); // u: 1
}
}
70 案例分析四(數組操作)
1、實作數組儲存資料
(1)大小由外部決定
(2)增加資料,滿了則失敗
(3)數組擴容
(4)取得數組全部資料
2、實作兩個派生類
(1)數組排序
(2)數組反轉
如果子類方法和父類方法功能相同,優先考慮覆寫父類方法
class ArrayDemo{
private int point = 0;
private int[] data = null;
public ArrayDemo(int length){
// 傳入的長度如果小于1則等于1
if(length < 1){
length = 1;
}
// 開辟數組空間
this.data = new int[length];
}
// 添加元素
public boolean add(int element){
if(this.point < this.data.length){
this.data[this.point] = element ;
this.point ++ ;
return true;
}
else{
return false;
}
}
// 數組擴容
public void increment(int num){
// 數組一旦确定大小就不能被改變
int[] newData = new int[data.length + num];
// arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
System.arraycopy(this.data, 0, newData, 0, this.data.length);
//修改數組引用
this.data = newData ;
}
public int[] getData(){
return this.data ;
}
public void printData(){
System.out.print("{");
for(int i : this.getData()){
System.out.print(i);
System.out.print(", ");
}
System.out.println("}");
}
}
// 排序數組
class SortArray extends ArrayDemo{
public SortArray(int length){
super(length);
}
public int[] getData(){
java.util.Arrays.sort(super.getData());
return super.getData();
}
}
// 反轉數組
class ReverseArray extends ArrayDemo{
public ReverseArray(int length){
super(length);
}
public int[] getData(){
int center = super.getData().length / 2;
int head = 0 ;
int tail = super.getData().length - 1;
for(int i = 0 ; i < center ; i++){
int temp = super.getData()[head] ;
super.getData()[head] = super.getData()[tail] ;
super.getData()[tail] = temp ;
head ++ ;
tail -- ;
}
return super.getData();
}
}
class Demo{
public static void main(String[] args) {
ArrayDemo array = new ArrayDemo(3);
System.out.println(array.add(1)); // true
System.out.println(array.add(2)); // true
System.out.println(array.add(3)); // true
System.out.println(array.add(4)); // false
System.out.println(array.add(5)); // false
array.increment(3) ;
System.out.println(array.add(6)); // true
System.out.println(array.add(7)); // true
array.printData();
// {1, 2, 3, 6, 7, 0, }
// 排序數組
SortArray sortArray = new SortArray(5);
sortArray.add(2);
sortArray.add(6);
sortArray.add(3);
sortArray.add(5);
sortArray.printData();
// {0, 2, 3, 5, 6, }
// 反轉數組
ReverseArray reverseArray = new ReverseArray(5) ;
reverseArray.add(1) ;
reverseArray.add(2) ;
reverseArray.add(3) ;
reverseArray.add(4) ;
reverseArray.add(5) ;
reverseArray.printData() ;
// {5, 4, 3, 2, 1, }
}
}