1 / 53

第 4 章 继承、多态与接口

第 4 章 继承、多态与接口. 4.1 继承的概念 4.2 访问控制符 4.3 多态性 4.4 理解 final 修饰 4.5 抽象类和抽象方法 4.6 接口 4.7 内嵌类 4.8 对象引用转换. 父类 或超类。实际上是所有子类的公共域和公共方法的集合 子类 ,父类的特殊化 , 是对公共域和方法在功能、内涵方面的扩展和延伸 ,祖先类的所有成员均将成为子类拥有的 “ 财富 ” Object 类 是所有类的祖先. 继承的概念. class Student { // 未使用继承

anoki
Download Presentation

第 4 章 继承、多态与接口

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第4章继承、多态与接口 4.1 继承的概念 4.2 访问控制符 4.3 多态性 4.4 理解final修饰 4.5 抽象类和抽象方法 4.6 接口 4.7 内嵌类 4.8 对象引用转换

  2. 父类或超类。实际上是所有子类的公共域和公共方法的集合父类或超类。实际上是所有子类的公共域和公共方法的集合 子类,父类的特殊化,是对公共域和方法在功能、内涵方面的扩展和延伸 ,祖先类的所有成员均将成为子类拥有的“财富” Object类是所有类的祖先 继承的概念

  3. class Student { //未使用继承 private String address; //籍贯 private String name; //姓名private int age; //年龄String no; //学号 public Student(String name1,int age1) { name=name1; age=age1; } //其它… } Java继承的实现

  4. class Student extends Person {    String no; //学号   //其它… } Java继承的实现 只有no属性是新加入的,其它属性在Person类中均存在

  5. (1) 当子类未定义构造方法时,创建对象时将无条件地调用父类的无参构造方法; (2) 对于父类的含参数构造方法,子类可以在自己构造方法中使用关键字super来调用它,但super调用语句必须是子类构造方法中的第一个可执行语句; (3) 子类在自己定义构造方法中如果没有用super明确调用父类的构造方法,则在创建对象时,将自动先执行父类的无参构造方法,然后再执行自己定义的构造方法。 继承关系中构造方法的作用

  6. class parent { String my; public parent(String x) { my=x; } } public class subclass extends parent { } 以下程序在编译时将出错,为什么?

  7. class Person { // Person类 private String address; //籍贯 private String name; //姓名 private int age; //年龄 public String getName() { //获取人名 return name; } public Person(String name1,String address1,int age1) { name=name1; address=address1; age=age1; } public Person() { name="无名氏"; } } 例4-1 类的继承中构造方法的调用测试

  8. public class Student extends Person { String no; //学号 public Student(String name1,String address1,int age1,String no1) { super(name1,address1,age1); no=no1; } public static void main(String a[]) { Student x=new Student("张三","江西",25, "20012541"); System.out.println("name="+x.getName()); System.out.println("no="+x.no); //Student y= new Student(); 不能使用,子类无该构造方法 } } 例4-1 类的继承中构造方法的调用测试

  9. class parent {int a=3;int m=2;}public class subclass extends parent {int a=4; int b=1; public static void main(String a[]) { subclass my=new subclass();System.out.println("a="+my.a+",b="+my.b+",m="+my.m); }} 子类中将隐藏父类的同名变量

  10. 作为类的修饰符,将类声明为公共类, 表明它可以被所有的其它类所访问和引用 作为类的成员的访问修饰符,表明在其他类中可以无限制地访问该成员。 要真正做到类成员可以在任何地方访问,在进行类设计时必须同时满足两点:首先类被定义为public,其次,类的成员被定义为public。 4.2.1 公共访问控制符 public

  11. 没有给出访问控制符情形 该类只能被同一个包中的类访问和引用 4.2.2 缺省访问控制符

  12. 用private修饰的域或方法只能被该类自身所访问用private修饰的域或方法只能被该类自身所访问 例4-3 测试对私有成员的访问 class Myclass { private int a; //私有变量 void display() { System.out.println(a); } } public class test { public static void main(String arg[]) { Myclass my=new Myclass(); my.a=5; my.display(); } } 4.2.3私有访问控制符 private

  13. 用protected修饰的成员可以在三种类中所引用: 该类本身; 与它在同一个包中的其它类; 在其它包中的该类的子类。 4.2.4保护访问控制符 protected

  14. 文件1:PackageData.java(该文件存放在sub子目录下) package sub;public class PackageData {protected static int number=1;} 文件2:Mytest.java import sub.*;public class Mytest { public static void main( String args[] ) { System.out.println("result="+PackageData.number); } } 例4-4 测试包的访问控制的一个简单程序

  15. 各类访问控制符的作用可以归纳为表3-1

  16. public class A { protected void test(int x,int y) { System.out.println("test(int,int):"+x+" "+y); } protected void test(int x) { System.out.println("test(int):" + x); } protected void test(String str ) { System.out.println("test(String):" + str); } public static void main (String[] args) { A a1 = new A(); a1.test("hello");a1.test(5,4); } } 4.3.1 方法的重载(例)

  17. 通过形式参数表的差异来区分 方法调用的匹配原则: 1) 精确匹配 2) 自动转换匹配 基本类型转换 对象引用转换 4.3.1 方法的重载

  18. public class A { protected int x = 0; protected void test(int x) { System.out.println("test(int):" + x); } protected void test(Object obj) { System.out.println("test(Object):" + obj ); } protected void test(String str ) { System.out.println("test(String):" + str); } public static void main (String[] args) { A a1 = new A(); a1.test("hello"); a1.test(5); } } 例4-5 方法调用的匹配测试

  19. 如果在以上程序中加上如下方法,并将test(int x)方法注释掉,则调用test(5)如何? protected void test(long x) { System.out.println("test(long):" + x ); } 如果是以下情形, 调用test(6.3)? protected void test(float x) { System.out.println("test(float):" + x ); } 【思考】

  20. 以下类B定义的方法中,方法覆盖如何? class B extends A {protected void test(int x) {System.out.println("in B.test(int):" + x); } protected void test(String x , int y) {System.out.println("in B.test(String,int):" + x+","+y); }} 【思考】通过子类B的对象可调用多少test方法? 4.3.2 方法的覆盖

  21. 方法名、参数列表、返回类型完全相同才会产生方法覆盖; 如果返回类型不一样编译将报错。 方法覆盖不能改变方法的静态与非静态属性。子类中不能将父类非静态方法定义为静态方法,反之也一样。 不允许子类中方法的访问修饰符比父类有更多的限制。例如:子类不能将父类的public方法定义为protected方法。但可以将父类的private方法在子类中重新定义为public方法. final方法不能被覆盖。 关于方法覆盖有以下问题值得注意:

  22. (1)把当前对象的引用作为参数传递给另一个方法。(1)把当前对象的引用作为参数传递给另一个方法。 如: obj.f(this) (2)可以调用当前对象的其它方法或访问当前对象的实例变量。 如: this.g(); (3)使用this可以区分当前作用域中同名的不同变量。 String x; public Test(String x , int a) { this.x=x; } (4)一个构造方法中调用另一个构造方法。 public Test(final int x) { this(x,0); } this ---出现在类的实例方法或构造方法中,用来代表使用该方法的对象

  23. class parent {   int a=3;   void f()  {   a=a+1;    } }public class subclass extends parent {   int a=6;    void f() {super.f();a= a+super.a -3; } (1) 用Super 访问超类的变量或方法

  24. public class graduate_student extends Student { Date enterDate; //入校时间 public graduate_student(String name,int age, Date d) { super(name,age); enterDate=d; } (2)调用超类的构造方法 如果有super(),必须放在构造方法的第一条语句

  25. 子类中调用方法的查找过程以及this和super的用法 【思考】如果graduate_student中无toString()方法,则this.toString()将会出现什么情况?

  26. final作为类修饰符 ----最终类 (不能有子类) 用final修饰方法 ----不能被子类重新定义 用final定义常量 ----只能赋值一次 注意: 如果将引用类型的变量标记为final,那么该变量固定指向一个对象,但可以改变对象内的属性值。 4.5final修饰符

  27. public final class test { public static int totalNumber=5; public final int id; public int weight; public test(int weight) { id=totalNumber++; this.weight=weight; } public static void main(String args[]) { final test t=new test(5); t=new test(4); t.weight=t.weight+2; } } 例4-7 常量赋值测试

  28. abstract class 类名称 { 成员变量; 方法(){……} //一般方法 abstract 方法(); //抽象方法 } 在抽象类中可以包含一般方法和抽象方法。 所有的抽象方法必须存在于抽象类中。 抽象类表示的是一个抽象概念,不能被实例化为对象。 4.6.1 抽象类的定义

  29. abstract class Animal { //抽象类 String name; abstract public int getLeg(); //抽象方法 } class Dog extends Animal { int leg=4; public Dog(String n) { name=n; } public int getLeg() { return leg ; } } 4.6.2 抽象类的实现

  30. class Fish extends Animal { public Fish(String n) { name=n; } public int getLeg() { return 0; } } 4.6.2 抽象类的实现(续1)

  31. public class test { public static void main(String args[]) { Animal a[]=new Animal[3]; a[0]=new Dog("dog-A "); a[1]=new Fish(“fish-A "); a[2]=new Dog("dog-B "); for (int i=0;i<3;i++) { System.out.println(a[i].name+"has "+ a[i].getLeg() +" legs"); } } } 4.6.2 抽象类的实现(续2)

  32. [public] interface 接口名 [extends 父接口名列表 ] { [public] [static] [final] 域类型 域名 = 常量值 ; [public] [abstract] [native] 返回值 方法名(参数列表) [throw 异常列表]; }   声明接口可给出访问控制符; 一个接口还可以继承多个父接口,父接口间用逗号分隔。 系统默认接口中所有属性的修饰都是 public static final; 系统默认接口中所有方法的修饰都是 public abstract。 4.7.1 接口定义

  33. interface Shape { void draw(); //用于绘制形状 double area(); //用于求面积 } 4.7.1 接口定义举例

  34. abstractpublic class Rectangle implements Shape { private double x,y,w,h; public Rectangle(double x,double y,double w,double h) { this.x=x; this.y=y; this.w=w; this.h=h; } public double area() { return w*h; } } 4.7.2 接口的实现

  35. 一个类可以实现多个接口。接口间用逗号分隔; 如果实现某接口的类不是抽象类,则在类的定义部分必须实现指定接口的所有抽象方法; 一个类在实现某接口的抽象方法时,必须使用完全相同的方法头; 接口的抽象方法的访问限制符默认为 public,在实现时要在方法头中显式地加上public修饰。 有关接口的实现,要注意以下问题

  36. interface StartStop { void start (); void stop (); } class Conference implements StartStop { public void start () { System.out.println ("Start the conference."); } public void stop () { System.out.println ("Stop the conference."); } } 例4-9 接口应用举例

  37. class Car implements StartStop { public void start () { System.out.println ("Insert key in ignition and turn."); } public void stop () { System.out.println ("Turn key in ignition and remove."); } } 例4-9 接口应用举例 (续1)

  38. public class TestInterface { public static void main (String [] args) { StartStop [] ss ={ new Car(), new Conference() }; for (int i = 0; i < ss.length; i++) { ss[i].start (); ss[i].stop (); } } } 例4-9 接口应用举例 (续2)

  39. interface Frob { float v = 2.0f; } //接口定义 class Parent { int v = 3; } //父类定义 class Test extends Parent implements Frob { public static void main(String[] args) { new Test().printV(); } void printV() { System.out.println((super.v+ Frob.v)/2); } } 二义性问题

  40. public class OuterOne { private int x=3; InnerOne ino = new InnerOne(); public class InnerOne { //内嵌类 private int y=5; public void innerMethod() { System.out.println("y is "+y); } public void innerMethod2() { System.out.println("x2 is "+x); } } 例4-10 一个简单例子 创建内嵌类的对象作为外部类的一个属性成员

  41. public void OuterMethod() { System.out.println("x is "+x); ino.innerMethod(); ino.innerMethod2(); } public static void main(String arg[]) { OuterOne my=new OuterOne(); my.OuterMethod(); } } 例4-10 一个简单例子(续) 调用内嵌类的方法

  42. 内嵌类经过编译后产生的字节码文件名为:OuterOne$InnerOne.class 在内嵌类中可以访问外层类的成员 内嵌类可以使用访问控制符public、protected、private修饰 有关说明

  43. 方法1:在外层类的成员定义中创建内嵌类的对象,例如:InnerOne ino=new InnerOne(); 然后,在外层类中通过该成员变量ino访问内嵌类的方法 方法2:在程序的某个方法体中创建内嵌类的对象,然后通过该对象访问内嵌类的成员,如: public void accessInner() { Innerone anInner=new Innerone(); anInner.innerMethod(); } 在外层类中访问内嵌类的方法

  44. 在main方法中,要创建内嵌类的对象必须先创建外层类对象,然后通过外层类对象创建内嵌类对象。例如:在main方法中,要创建内嵌类的对象必须先创建外层类对象,然后通过外层类对象创建内嵌类对象。例如: public static void main(String arg[]) { OuterOne.InnerOne i = new OuterOne() . new InnerOne(); i.innerMethod(); } 在main方法中间接创建内嵌类的对象

  45. public class A { private int x=3; public class B { //内嵌类 private int x=5; public void M(int x) { System.out.println("x ="+x); System.out.println("this.x="+this.x); System.out.println("A.this.x="+A.this.x); } } //内嵌类结束 在内嵌类中使用this ---在内嵌类中,this指内嵌类的对象,要访问外层类的当前对象须加上外层类名作前缀 内嵌类对象 外部类的当前对象

  46. public class Outertwo { private static int x=3; private int y=5; public static class Innertwo { //静态内嵌类 public static void Method() { System.out.println("x is "+x); } public void Method2() { System.out.println("x is "+x); } } //内嵌类结束 public static void main(String arg[]) { Outertwo.Innertwo.Method(); new Outertwo.Innertwo().Method2(); } } 例4-12 静态内嵌类举例

  47. public class OuterTwo { private int x=3; public void OuterMethod( int m ) { final int n=x+2; class InnerTwo { //方法内的内嵌类 private int y=5; public void innerMethod() { System.out.println("y is "+y); System.out.println("n is "+n); System.out.println("x is "+x); } } //内嵌类结束 方法中的内嵌类 (例4-13 ) 只能访问外部方法中的常量(带final修饰)

  48. InnerTwo in2=new InnerTwo(); in2.innerMethod(); } public static void main(String arg[]) { OuterTwo my=new OuterTwo(); my.OuterMethod(8); } } 方法中的内嵌类(例4-13续)

  49. interface sample { void testMethod(); } public class AnonymousInner { void OuterMethod() { new sample(){ public void testMethod( ) { System.out.println("just test"); } } .testMethod(); //调用内嵌类中定义的方法 } 匿名内嵌类 由接口派生匿名内嵌类,根据该内嵌类创建对象 ---字节码文件为AnonymousInner$1.class。如果有更多的匿名内嵌类将按递增序号命名

  50. 4.9.1 对象引用赋值转换 Object x=new Apple(); Fruit m=new Orange(); Apple x=new Fruit();

More Related