2022-07-23 第二组 程梓杭 Java(8) 继承封装的实例
今日学习内容:继承封装实例
实例1:学校教师学生关系
需求分析:
点击查看内容
- 至少设置三个类:学校、教师、学生。(实际设置了四个,在教师和学生之上设置了父类,Person,来感受继承的作用。)
- 设置Person的基础属性:姓名(name)与身份证号码(cardID)。(实际增加了年龄,虽然感觉这里没什么作用。)
- 设置教师(Teacher)和学生(Student)的属性:教师id(teaNo)和课程学生表(stus),学生id(stuNo)和授课教师(Teacher)。(一个学生对应一个教师,一个教师对应多个学生,所以教师属性里的学生是对象数组,学生属性里的教师是对象)
- 设置学校(School)的属性:学生表(students)和教师表(teachers)
- 方法总结:对全体private权限属性的设置与查看方法,每个类的toString方法重写,体现教师和学生双方关系的两个输出方法
- 在实现上述需求下,设置录入教师与学生信息过程中依据身份证号码排除重复者的方法。
代码示例:
Person类属性与方法
点击查看
public class Person {
private String name;
private Integer age;
private String cardId;
public Person(String name, Integer age, String cardID){
this.name =name;
this.age = age;
this.cardId = cardID;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public String getCardId() {
return cardId;
}
public void setCardId(String cardId) {
this.cardId = cardId;
}
@Override
public String toString() {
return "name:"+name+"age:"+age+"cardID"+cardId;
}
}
Student类属性与方法:
点击查看
public class Student extends Person {
private String stuNo;
private Teacher teacher;
public Student(String name, Integer age, String cardID,String stuNo,Teacher teacher) {
super(name, age, cardID);
this.stuNo = stuNo;
this.teacher = teacher;
}
public String study(){
return this+",\n 老师是"+teacher;
}
public String getStuNo() {
return stuNo;
}
public void setStuNo(String stuNo) {
this.stuNo = stuNo;
}
public Teacher getTeacher() {
return teacher;
}
public void setTeacher(Teacher teacher) {
this.teacher = teacher;
}
@Override
public String toString() {
return super.toString()+"学号:"+stuNo+"授课教师:"+teacher;
}
}
Teacher类属性与方法
点击查看
import java.util.Arrays;
public class Teacher extends Person {
private String teaNo;
private Student [] stu;
public Teacher(String name, Integer age, String cardID,String teaNo) {
super(name, age, cardID);
this.teaNo = teaNo;
}
public String teach() {
return this+",\n"+ Arrays.toString(stu);
}
public String getTeaNo() {
return teaNo;
}
public void setTeaNo(String teaNo) {
this.teaNo = teaNo;
}
public Student[] getStu() {
return stu;
}
public void setStu(Student[] stu) {
this.stu = stu;
}
@Override
public String toString() {
return super.toString()+"教师号:"+teaNo+"现教学生有:"+stu;
}
}
School类属性与方法
点击查看
public class School {
private Teacher[] teacher;
private Student[] students;
public Teacher[] getTeacher() {
return teacher;
}
public void setTeacher(Teacher[] teacher) {
this.teacher = teacher;
}
public Student[] getStudents() {
return students;
}
public void setStudents(Student[] students) {
this.students = students;
}
@Override
public String toString() {
return teacher.toString()+'\n'+students.toString();
}
}
主类说明:
考虑到反复输入的随机性和验证输入过于繁琐。推荐在验证中直接使用有参构造器直接为属性赋值而非调用set方法反复赋值。依次需要输入不包含学生信息的教师信息,包含了教师信息的学生信息并分别调用构造器创建对象。set设置教师的学生信息,set设置学校的教师与学生信息。验证教师与学生的toString方法和teach方法-study方法显示各自信息与关联信息。验证学校的toString方法。
查询重复说明:
可以是在输入时调用get方法,然后查重,也可以是在Student和Teacher类中在构造器外设置查重方法并在构造器内调用,(设置在School中会提前创建对象并影响师生个关联信息,不尽合理)。
查重方法思路很简单
先查数组是否非空(非空不用查,直接赋值)
后遍历数组查有无cardID属性等于输入属性
是则重复,退出循环返回false即可。
否则遍历完成,返回true即可。
实例2:超级数组类
需求分析
点击查看
- 无限长数组实际是有限长数组不断扩容的结果,先设置一个创建有限长数组的构造器,有参构造器接收参数为创建数组的长度,无参构造器调用有参构造器并传递默认数组长度为参数。
- 查询数组长度方法size
- 查询输入下标是否越界方法rangeCheck
- 查询某下标数组内容方法get
- 数组扩容方法ensureCapacity
- 数组尾端赋值方法add
- 数组特定下标赋值方法add(方法重载)
- 数组特定下标内容删除方法deleteData
- 数组特定内容删除方法deleteData(方法重载)
- 数组特定下标内容修改方法changeData
说明:方法间存在相互调用,例如无参构造器调用有参构造器,例如内容删除可以在查询到特定内容后,依据下标调用另一删除方法。
SuperArray类代码:
点击查看
public class SuperArray {
private Integer [] array;
private int size;
private int capacity;
public SuperArray(){
this(10);
}
public SuperArray(int capacity){
array = new Integer[capacity];
this.capacity = capacity;
}
public void add(Integer data) {
ensureCapacity(size + 1);
array[size++] = data;
}
public void add(int index,Integer data){
if(rangeCheck(index)){
ensureCapacity(size + 1);
System.arraycopy(array,index,array,index + 1,size - index);
array[index] = data;
size++;
}
}
public int size(){
return size;
}
public Integer get(int index) {
if(rangeCheck(index)){
return array[index];
}
return null;
}
private boolean rangeCheck(int index) {
return (index >=0 && index <= size - 1);
}
private void ensureCapacity(int needCapacity) {
if(needCapacity > capacity){
capacity = capacity + (capacity >> 1);
Integer [] newArray = new Integer[capacity];
System.arraycopy(array,0,newArray,0,array.length);
array = newArray;
}
}
public void deleteData(Integer data){
for (int i = 0;i<size;i++){
if(array[i] == data){
deleteData(i);
}
}
}
public void deleteData(int index){
if(rangeCheck(index)){
Integer [] newArray = new Integer[capacity];
System.arraycopy(array,0,newArray,0,index);
System.arraycopy(array,index+1,newArray,index,array.length-index-1);
array = newArray;
}
}
public void changeData(int index,Integer data){
if(rangeCheck(index)){
array[index] = data;
}
}
}
一些思考:
有时候过度在意输入输出验证的复杂反而会影响了类方法的思考与编写。既然是面向对象的编程,只要好好编写类方法,调用自然不会有大的问题。
多体会编程背后的思想比编程过程更让人影响深刻。
联系继承和封装在现实中很容易找到对照的实例:
继承的实质是属性方法的继承。稚鸟继承了母亲的外形是属性继承,学会母亲的飞翔则是方法继承,稚鸟拥有了更强的适应能力则是继承后的成长(方法重写,额外属性,额外方法等等)。
封装的实质是复杂问题简单化和分离思想。让我们从无到有制作一个电脑会十分困难,但是如果让我们购买成品元件然后组装或许会简便一些,若是让我们直接购买一个成品电脑则没有什么难度了。封装方法即可以让我们脱离方法本身的构造来思考整体的实现,又能让我们脱离整体的问题来思考方法的构建。