400 likes | 650 Views
第 4 章 继承、抽象类和接口 教学内容: 类的继承 覆盖 抽象类 接口 内部类与匿名类 包 重点 类的继承 覆盖 抽象类 接口 难点 内部类与匿名类 学时 6. 面向对象的 3 个特征: 抽象、封装 继承 多态 软件重用 -- 通过继承实现 可以实现:保留原有的功能,并进行功能扩展。 父类的修改,子类自动得到修改. 张三汽车类. 张三汽车类 改造升级. 张三. 卖. 改. 改. 张三汽车类. 里斯汽 车类. 里斯汽 车类 1.
E N D
第4章 继承、抽象类和接口 教学内容: 类的继承 覆盖 抽象类 接口 内部类与匿名类 包 重点 类的继承 覆盖 抽象类 接口 难点 内部类与匿名类 学时 6
面向对象的3个特征: • 抽象、封装 • 继承 • 多态 • 软件重用 -- 通过继承实现 • 可以实现:保留原有的功能,并进行功能扩展。 • 父类的修改,子类自动得到修改
张三汽车类 张三汽车类 改造升级 张三 卖 改 改 张三汽车类 里斯汽车类 里斯汽车类1 里斯 改 张三汽车类 赵新汽车类 赵新
class Student { //继承的好处? private int num ; private String name, sex; Student(int _num,String _name,String _sex){ num = _num ; name = _name; sex=_sex; } void display(){ System.out.print(num+”,”+name+”,”+sex); } }; class Student1 { //复制代码 private int num ; //学号 private String name,sex; //性别 private int age ; private String addr; Student1(int _num,String _name,String _sex,int _age,String _addr){ num = _num ; name = _name; sex=_sex; age=_age;addr=_addr;} void display(){ System.out.print(num+”,”+name+”,”+sex+”,”+ age+”,”+addr) ; } };
class Student1 extends student { private int age ; private String addr; Student1(int _num,String _name,String _sex, int _age,String _addr){ super(_num,_name,_sex); age=_age;addr=_addr; } void display(){ super.display(); //调用父类的display() System.out.print(age+”“+addr); } };
人 学生 教师 工人 公务员 本科生 研究生 继承
人类: name sex 教师类: 工号 教授课程 学生类: 学号 班级
4.1 类的继承 通过继承可以实现代码的复用。 • 父类或超类(superclass) 被继承的类 • 子类(subclass) 由继承而得到的类 一个父类可以同时拥有多个子类,但由于Java中不支持多重继承,所以一个类只能有一个直接父类。
人类: name sex 教师类: 工号 教授课程 学生类: 学号 班级 4.1 类的继承 • 代码的复用 • 被继承的类称为父类 (基类、超类) • 继承父类的类称为子类 (派生类) • 继承时,子类将获得父类的属性,并具有自身特有的属性。 • 单继承 • java类的共同祖先:java.lang.Object
4.1.1 子类的创建 格式: class SubClass extends SuperClass { …… } • 直接子类,间接子类。 • 没有extends,默认父类为Object。 • 子类继承父类的全部成员,就像是自己的。 • 子类能访问父类的public, default, protected 成员
class C extends B { private int w; void setW(int i){ w=i; } void print(){ show(); System.out.println(w); } } class A{ //继承 private int x; int y; void setX(int i){x=i;} int getX(){return x;} } class B extends A{ private int z; void setZ(int i){ z=i; y = 2*i; } void show(){ System.out.print( x+”,”+y+”,”+z); } } B b1 = new B(); b1.setZ(3); b1.setX(2); z : 3 X : 2 y : 6 b1对象
class Person { //Person类是Object类的子类 private String name; private int age; Person(){ System.out.println(“调用了个人构造方法Person()”); } public void SetNameAge(String name, int age) { this.name=name; this.age=age; } public void show(){ System.out.println(“姓名:“+name+” 年龄:”+age);} } class Student extends Person{ private String department; Student(){ System.out.println(“调用了学生构造方法Student()”); } void SetDepartment(String dep){ department=dep; System.out.println(“我是”+department +”的学生”); } } 1.子类的构建方法
【例8.1】续 public class app8_1 //主类 { public static void main(String args[ ]) { Student stu=new Student(); stu.SetNameAge(“张小三”,21); stu.show(); stu.SetDepartment(“计算机系”); } }
说明: (1)通过extends关键字,可将父类的成员继承给子类。 数据成员、成员方法。 老子的,就是儿子的。(但儿子的,老子不能看) (2)构造方法: 先自动调用父类中没有参数的构造方法, 然后子类的构造方法。 (3) 构造方法是不能被继承的,例如父Person有一个构造方法Person(String,int),不能说子类Student也自动有一个构造方法Person(String,int),但这并不意味着子类不能调用父类的构造方法。
class A { //A 继承谁? 构造方法 protected int x; A(){ x=-1; System.out.print(“A0”);} A(int i) { x = i; System.out.print(“A1”);} } class B extends A { protected int y ; B(){y=-1; System.out.print(“B0”);} B(int j){ y = j; System.out.print(“B1”); } } class C extends B { private int z ; C(){z=-1; System.out.print(“C0”);} C(int k){ z = k; System.out.print(“C1”); } } C c1 = new C(3);
class A { //改错 构造方法 private int x; protected int y; A(int i) { x = i; } void printA(){ System.out.print(x+”“+y); } } class B extends A { private int z ; B(int j){ z = j; } void printB(){ System.out.print (x+”“+y+”“+z); } }
如何初始化父类的数据成员? super 1)调用父类的构造方法 子类构造方法的第一句。 2)访问父类中被隐藏的数据成员 super.成员 3)调用父类中被重写的成员方法 注意:建对象初始化过程先父类,然后子类。 释放对象调用 finalize,先子类后父类。 注意与this 的区别 2.调用父类中特定的构造方法
class A{ private int x , y; A(){ x=-1;y=-1;} A(int i, int j){ x=i; y = j;} void show(){ System.out.print( x+”,”+y);} } class B extends A{ private int z; B(){ } B(int i, int j , int k){ z=k; } } class hello2 { public static void main(String args[]) { B b1=new B(); b1.show(); B b2=new B( 1,2,3); b2.show(); } } 内存示意?? x,y 如何为1,2??
// super 在构造方法中 class A{ private int x , y; A(){ x=-1;y=-2;} A(int i, int j){ x=i; y = j; } void show(){ System.out.print( x+”,”+y);} } class B extends A{ private int z; B(){ } B(int i, int j , int k){ super(i ,j); //完成父类的初始化 z=k; } } class hello2 { public static void main(String args[]) { B b1=new B(); b1.show(); B b2=new B( 1,2,3); b2.show(); } }
class Person { //调用父类中的特定构造方法 private String name; private int age; Person(){ System.out.println(“调用Person 无参构造方法”); } Person(String name, int age) { System.out.println(“调用了Person的有参构造方法”); this.name=name; this.age=age; } void show() { System.out.println(“姓名:“+name+” 年龄:”+age);} } class Student extends Person { private String department; Student(){System.out.println(“调用学生无参构造”);} Student (String name,int age,String dep) { super(name,age); department=dep; System.out.println(“调用了学生的有参构造方法”); } }
【例8.2】续 public class app8_2 //主类 { public static void main(String args[ ]) { Student stu1=new Student(); Student stu2=new Student(“李小四”,23,”信息系”); stu1.show(); stu2.show(); } }
// 成员变量与局部变量 class A{ //this int x=1; int y=2; void f1(){ int x=9; this.x = x; ;} } class A{ //this int x=1; int y=2; void setXY(int i,int j){ x = i; this.y = j;} void f1(){ setXY(3,4);} } 可省略 不可省略
练习 继承构造方法 人:Person,有属性:姓名,年龄。 学生:student, 还有属性 学号,入学年份。 教师:teacher,还有属性 工号,职称 本科学生underGraduate:有属性:专业,特长。 研究生graduate :有属性 专业,方向,导师。 测试: 本科生:08101,张三,21,2008年,计算机,长跑。 研究生:10101,钱四,24,2010年,计算机应用,数据库,王平。 教师:0901,王平,38,副教授 输出2个学生、一个教师的信息。
4.1.2 在子类中访问父类的成员 格式: super.<变量名> super.<方法名> 必须吗?
class B extends A{ int x=7; void show(){ System.out.print(super.x); } System.out.print(x +”,“+y); } void fun( ){ super.show(); } } class hello2 { public static void main(String args[]) { B b=new B(); b.fun( ); b.show(); } } super 调用父类方法 class A{ int x=1; int y=2; void show(){ System.out.print( x+”,”+y);} }
class Person { // super关键字访问父类的成员 protected String name; protected int age; Person() {} Person(String name, int age) { name=name; age=age; } protected void show() { System.out.println(“姓名:“+name+” 年龄:”+age); } } class Student extends Person { private String department; int age=20; Student (String xm,String dep) { name=xm; department=dep; super.age=25; System.out.println(“子类Student中的成员变量age=”+age); super.show(); System.out.println(“系别:”+ department ); } }
31 public class app8_3 //主类 32 { 33 public static void main(String args[ ]) 34 { 35 Student stu=new Student(“李小四”,”信息系”); 36 } 37 } 【例8.3】续
class Person { //找错,并改正 private String name; private int age; Person (){} Person( String pname, int page): name=pname; age=page ;} void Print(){ System.out.print(name+’,’+age); } } class Student extends Person { private String no ; int year ; Student(String pno,String pname,int page,int pYear){ super(pname,page); no=pno; year = pYear;} void print(){ System.out.print(no+”,”+year); System.out.print(name+”,”+age); } }
补充:析构函数 • 析构函数 protected void finalize () 对象被销毁时执行的方法。每个对象一定有一个析构函数。(继承Object类) 必须捕获异常。 • 可以自己调用对象的finalize方法,这种调用与对象销毁无关。 • java的gc() 负责内存的清理。调用gc()并不保证gc()实际执行。 调用gc 检查 finalize 调用情况。 4 析构函数执行:先子类,后父类。
class A { private int x; A(int i) { x = i; System.out.print("A1");} protected void finalize() throws Throwable { System.out.println("~A"); } } class B extends A { private protected int y ; B(int j){ y = j; System.out.print("B1"); } protected void finalize() throws Throwable { System.out.println("~B"); //super.finalize(); } } public class test1 { static void f1(){ B c1 = new B(3); } public static void main(String[] args) { f1(); System.gc(); } }
可以记录当前类创建了多少对象,但有漏洞。 class A { private static int nCount ; private int x ; static { nCount=0;} A(){ x = -1 ; nCount++;} A(int i ){ x = i ; nCount++;} static int getCount(){ return nCount;} } class hello{ public static void main(String args[]) { A a1=new A(); A a2 = new A(2); A a3= new A(4); System.out.print( A.getCount()); a1=null; //释放了 a1 还有? System.out.println( A.getCount()); } }
class A { //完善的记录对象个数 private static int nCount ; private int x ; static { nCount=0;} A(){ x = -1 ; nCount++;} A(int i ){ x = i ; nCount++;} protected void finalize() throws Throwable { System.out.println("~A"); nCount--; } static int getCount(){ return nCount;} } class hello{ public static void main(String args[]) { A a1=new A(); A a2 = new A(2); A a3= new A(4); System.out.print( A.getCount()); a1=null; System.gc(); for(int i=0;i<10000;i++){ //延时 } System.out.println( A.getCount()); } }
继承练习 1 完成一个能表达日期时间的类:JDateTime 类。 1)建立 JDate 类 , 有私有属性year,month,day ; 有一个公有方法 show ,输出日期,格式如:2004年3月2日。 2) 建立JDateTime类,该类有私有属性时、分、秒( hour, minute, second) , 有公有方法show ,输出时间,格式如:2005年3月2日 11:20:22 。 3) 测试: 建立对象 d1 , 表示 2005年10月21日, 输出 d1 建立对象 t1, 表示 2005年10月22日 11:20:22, 输出 t1 日期部分 格式为:2005年 10月22日 。
2 人: 私有成员变量:姓名name、性别sex、年龄age 成员方法 print:输出姓名、性别、年龄 学生: 私有成员变量:学号no、班级 class 成员方法print: 输出学号、姓名、性别、年龄、班级 教师: 私有成员变量:工号 no、所教课程 course。 成员方法print: 输出工号、姓名、性别、年龄、课程 学生、教师继承人,写出此3个类, 测试程序: 1)建立学生对象:student1 : 学号=101、姓名=王利、性别=男、年龄=22、班级=1班 2)建立教师对象:teacher1 : 工号=A01、姓名=高丽、性别=女、年龄=35、课程=数据库 3)输出 student1 , teacher1 对象的值。
class A { 构造方法 protected int x; A(){ x=-1; System.out.print(“A0”);} A(int i) { x = i; System.out.print(“A1”);} } class B extends A { protected int y ; B(){y=-1; System.out.print(“B0”);} B(int j){ y = j; System.out.print(“B1”); } } class C extends B { private int z ; C(){z=-1; System.out.print(“C0”);} C(int k){ z = k; System.out.print(“C1”); } } public class Test { public static void main(String args[ ]){ C c1 = new C( ); C c2 = new C(5) ; }
class A { //改错 构造方法 private int x; protected int y; A(int i) { x = i; } void printA(){ System.out.print(x+”“+y); } } class B extends A { private int z ; B(int j){ z = j; } void printB(){ System.out.print (x+”“+y+”“+z); } }
class B extends A{ int x=5; void show(){ int y =7; System.out.println(super.x);} System.out.println(x); System.out.println(y); } void fun( ){ show(); super.show(); } } class hello2 { public static void main(String args[]) { B b=new B(); b.fun( ); b.setX(9); b.show(); } } //super 调用父类方法 class A{ int x=1; int y=2; void setX(int i){x=i;} void show(){ System.out.println( x+”,”+y);} } 写出程序运行结果?
class B extends A{ int x=7; void set( int i ){ x = i;} void fun(int i,int j){ super.set( i ); set( j ); } void show(){ System.out.print(x); System.out.print(super.x+”,”+y);} } class hello2 { public static void main(String args[]) { B b=new B(); b.fun(1,2); b.show(); } } class A{ //super 调用方法 int x=1; int y=2; void set(int i){ x = i; y =2*i; } void show(){ System.out.print(x+”,”+y);} } 写出程序运行结果?
class A{ //改错 [ super 在构造方法中 ] private int x=-1 ,y=-1; A(int i, int j){ x=i; y = j; } public void show(){ System.out.print(x+”,”+y);} } class B extends A{ private int z; B(){ } B(int i, int j , int k){ z=k; super(i ,j); } } class hello2 { public static void main(String args[]) { B b1=new B(); b1.show(); B b2=new B( 1,2,3); b2.show(); } }