第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参
-1个方法 显示信息
管理人员
-4属性 name, age, position, income
-2构造 无参, 4参
-1个方法 显示信息
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, } } }