java抽象类重载_Java学习笔记之方法重载,动态方法调度和抽象类

一、方法重载

如果子类中的方法与它的超类中的方法有相同的方法名,则称子类中的方法重载超类中的方法,特别是当超类和子类中的方法名和参数类型都相同时,在子类中调用该方法时,超类中的方法会被隐藏。考虑下面程序:

1 classA2 {3 inti, j;4 A(int a, intb)5 {6 i =a;7 j =b;8 }9

10 //display i and j

11 voidshow()12 {13 System.out.println("i and j: " + i + " " +j);14 }15 }16

17 class B extendsA18 {19 intk;20

21 B(int a, int b, intc)22 {23 super(a, b);24 k =c;25 }26

27 //display k – this overrides show() in A

28 voidshow()29 {30 System.out.println("k: " +k);31 }32 }33

34

35 public classmyJavaTest36 {37 public static voidmain(String args[])38 {39 B subOb = new B(1, 2, 3);40

41 subOb.show(); //this calls show() in B

42 }43 }

运行结果:k: 3

子类B中的show()重载了超类A中的show(),从子类中调用重载方法时(41行),它总是引用子类定义的方法(28-31行),超类中的show()方法(11-14行)被隐藏。当然如果希望访问被重载的超类方法,可以用super,如下:

1 class B extendsA2 {3 intk;4

5 B(int a, int b, intc)6 {7 super(a, b);8 k =c;9 }10 voidshow()11 {12 super.show(); //this calls A's show()

13 System.out.println("k: " +k);14 }15 }

如果用这段代码替换上面的版本,运行结果会变为:

i and j: 1 2

k: 3

super.show()调用了被隐藏的超类的方法。

注意,当子类和超类中仅仅是方法名相同而参数类型不同时,利用子类调用该方法时系统会根据输入的参数类型来判断到底使用哪一个版本。

二、动态方法调度

上面的例子解释了何为方法重载。方法重载的真正意义在于它构成了Java一个最强大的概念的基础:动态方法调度。动态方法调度是一种在程序运行时而不是编译时调用重载方法的机制,它是实现运行时多态性的基础。

考虑下面程序:

1 //Dynamic Method Dispatch

2 classA3 {4 voidcallme()5 {6 System.out.println("Inside A's callme method");7 }8 }9

10 class B extendsA11 {12 //override callme()

13 voidcallme()14 {15 System.out.println("Inside B's callme method");16 }17 }18

19 class C extendsA20 {21 //override callme()

22 voidcallme()23 {24 System.out.println("Inside C's callme method");25 }26 }27

28 public classmyJavaTest29 {30 public static voidmain(String args[])31 {32 A a = new A(); //object of type A

33 B b = new B(); //object of type B

34 C c = new C(); //object of type C

35 A r; //声明一个对A的引用 r

36

37 r = a; //引用r指向A的对象

38 r.callme(); //calls A's version of callme

39

40 r = b; //引用r指向B的对象

41 r.callme(); //calls B's version of callme

42 r = c; //引用r指向C的对象

43 r.callme(); //calls C's version of callme

44 }45 }

输出如下:

Inside A's callme method

Inside B's callme method

Inside C's callme method

程序创建了一个名为A的超类以及它的两个子类B和C。子类B和C重载A中定义的callme( )方法。main( )主函数中,声明了A、B和C类的对象。而且,一个A类型的引用r也被声明。就像输出所显示的,所执行的callme( )版本由调用时引用对象的类型决定。

由上述例子我们可以看到,重载方法允许Java支持运行时多态性,就是在程序运行的时候选择使用哪一个版本的方法,从而实现“一个接口,多个方法”。超类提供子类可以直接运用的所有元素。多态也定义了这些派生类必须自己实现的方法。这允许子类在加强一致接口的同时,灵活的定义它们自己的方法。

三、应用方法重载

下面的程序创建了一个名为Figure的超类,它存储不同二维对象的大小。它还定义了一个方法area( ),该方法计算对象的面积。程序从Figure派生了两个子类。第一个是Rectangle,第二个是Triangle。每个子类重载area( )方法,它们分别返回一个矩形和一个三角形的面积。

1 classFigure2 {3 doubledim1;4 doubledim2;5

6 Figure(double a, doubleb)7 {8 dim1 =a;9 dim2 =b;10 }11

12 doublearea()13 {14 System.out.println("Area for Figure is undefined.");15 return 0;16 }17 }18

19 class Rectangle extendsFigure20 {21 Rectangle(double a, doubleb)22 {23 super(a, b);24 }25

26 //override area for rectangle

27 doublearea()28 {29 System.out.println("Inside Area for Rectangle.");30 return dim1 *dim2;31 }32 }33

34 class Triangle extendsFigure35 {36 Triangle(double a, doubleb)37 {38 super(a, b);39 }40

41 //override area for right triangle

42 doublearea()43 {44 System.out.println("Inside Area for Triangle.");45 return dim1 * dim2 / 2;46 }47 }48

49 public classmyJavaTest50 {51 public static voidmain(String args[])52 {53 Figure f = new Figure(10, 10);54 Rectangle r = new Rectangle(9, 5);55 Triangle t = new Triangle(10, 8);56

57 Figure figref;58

59 figref =r;60 System.out.println("Area is " +figref.area());61

62 figref =t;63 System.out.println("Area is " +figref.area());64

65 figref =f;66 System.out.println("Area is " +figref.area());67

68 }69 }

输出:

Inside Area for Rectangle.

Area is 45.0

Inside Area for Triangle.

Area is 40.0

Area for Figure is undefined.

Area is 0.0

这种情况下, 如果一个对象是从Figure派生, 那么它的面积可以由调用area( )来获得。无论用到哪种图形的类型,该操作的接口是相同的。

四、使用抽象类

回看前面的例子中,超类Figure中,area( )的定义仅是一个占位符,它不会计算和显示任何类型对象的面积。也就是说,有时候我们希望定义一个超类,但是该超类只给定一种类的结构但是不提供方法的实现,而继承超类的子类共享这种结构,具体的实现由每个子类自己填写。

还是考虑上面的例子,对于Triangle类,如果它自己不定义area(),那么它将变得毫无意义。所以这种情况下,必须确保子类真正重载了所有必须的方法。Java对于这个问题的解决使用的是抽象方法(abstract method).通过abstract 修饰符指定某些方法必须由子类实现,你不去实现就不让你运行,这样子类就必须重载它们,而不能简单使用超类中定义的版本。

考虑下面的程序:

1 //A Simple demonstration of abstract.

2 abstract classA3 {4 abstract void callme();//声明抽象方法,不具体实现,交给子类实现5

6 //用一个抽象类去实例化一个对象是不允许的,但在类里面实现一个具体方法还是允许的

7 voidcallmetoo()8 {9 System.out.println("This is a concrete method.");10 }11 }12

13 class B extendsA14 {15 void callme() //实现超类的抽象方法

16 {17 System.out.println("B's implementation of callme.");18 }19 }20

21 public classmyJavaTest22 {23 public static voidmain(String args[])24 {25 A a;26 B b = newB();27 a =b;28 a.callme();29 a.callmetoo();30 }31 }

输出:

B's implementation of callme.

This is a concrete method.

由上面程序总结出使用抽象类要注意:

声明一个抽象方法的通用形式:abstract type name(parameter-list)(第4行)

一个类只要含有一个或多个抽象类方法,它就变成了抽象类,就必须声明为抽象类(第二行所示)

尽管抽象类不能用来实例化(即不能用来建立一个具体的对象,语句A a = new A()就是非法的),但是它们可以用来创建对象引用(如25行所示)

抽象类实例化抽象类不可以,但抽象类可以自己实现任意数量的具体方法(如7-10行实现了一个具体方法)

所有子类都必须具体实现超类中的抽象方法或者改子类自己声明为abstract

下面用抽象类改善前面的Figure类:

1 //Using abstract methods and classes.

2 abstract classFigure3 {4 doubledim1;5 doubledim2;6

7 Figure(double a, doubleb)8 {9 dim1 =a;10 dim2 =b;11 }12

13 //area is now an abstract method

14 abstract doublearea();15 }16

17 class Rectangle extendsFigure18 {19 Rectangle(double a, doubleb)20 {21 super(a, b);22 }23

24 //override area for rectangle

25 doublearea()26 {27 System.out.println("Inside Area for Rectangle.");28 return dim1 *dim2;29 }30 }31

32 class Triangle extendsFigure33 {34 Triangle(double a, doubleb)35 {36 super(a, b);37 }38

39 //override area for right triangle

40 doublearea()41 {42 System.out.println("Inside Area for Triangle.");43 return dim1 * dim2 / 2;44 }45 }46

47 public classmyJavaTest48 {49 public static voidmain(String args[])50 {51 //Figure f = new Figure(10, 10);//非法的,因为抽象类是不能够创建对象的

52 Rectangle r = new Rectangle(9, 5);53 Triangle t = new Triangle(10, 8);54 Figure figref; //仅仅声明了一个指向Figure类的引用,是不会创建具体对象的,所以语句合法

55

56 figref =r;57 System.out.println("Area is " +figref.area());58

59 figref =t;60 System.out.println("Area is " +figref.area());61 }62 }

56行变量figref声明成Figure的一个引用,意思是说它可以用来引用任何从Figure派生的对象。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值