Java学习笔记之方法重载,动态方法调度和抽象类
一、方法重载
如果子类中的方法与它的超类中的方法有相同的方法名,则称子类中的方法重载超类中的方法,特别是当超类和子类中的方法名和参数类型都相同时,在子类中调用该方法时,超类中的方法会被隐藏。考虑下面程序:
class A
{
int i, j;
A(int a, int b)
{
i = a;
j = b;
} // display i and j
void show()
{
System.out.println("i and j: " + i + " " + j);
}
} class B extends A
{
int k; B(int a, int b, int c)
{
super(a, b);
k = c;
} // display k – this overrides show() in A
void show()
{
System.out.println("k: " + k);
}
} public class myJavaTest
{
public static void main(String args[])
{
B subOb = new B(1, 2, 3); subOb.show(); // this calls show() in B
}
}
运行结果:k: 3
子类B中的show()重载了超类A中的show(),从子类中调用重载方法时(41行),它总是引用子类定义的方法(28-31行),超类中的show()方法(11-14行)被隐藏。当然如果希望访问被重载的超类方法,可以用super,如下:
class B extends A
{
int k; B(int a, int b, int c)
{
super(a, b);
k = c;
}
void show()
{
super.show(); // this calls A's show()
System.out.println("k: " + k);
}
}
如果用这段代码替换上面的版本,运行结果会变为:
i and j: 1 2
k: 3
super.show()调用了被隐藏的超类的方法。
注意,当子类和超类中仅仅是方法名相同而参数类型不同时,利用子类调用该方法时系统会根据输入的参数类型来判断到底使用哪一个版本。
二、动态方法调度
上面的例子解释了何为方法重载。方法重载的真正意义在于它构成了Java一个最强大的概念的基础:动态方法调度。动态方法调度是一种在程序运行时而不是编译时调用重载方法的机制,它是实现运行时多态性的基础。
考虑下面程序:
// Dynamic Method Dispatch
class A
{
void callme()
{
System.out.println("Inside A's callme method");
}
} class B extends A
{
// override callme()
void callme()
{
System.out.println("Inside B's callme method");
}
} class C extends A
{
// override callme()
void callme()
{
System.out.println("Inside C's callme method");
}
} public class myJavaTest
{
public static void main(String args[])
{
A a = new A(); // object of type A
B b = new B(); // object of type B
C c = new C(); // object of type C
A r; // 声明一个对A的引用 r r = a; // 引用r指向A的对象
r.callme(); // calls A's version of callme r = b; // 引用r指向B的对象
r.callme(); // calls B's version of callme
r = c; // 引用r指向C的对象
r.callme(); // calls C's version of callme
}
}
输出如下:
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( )方法,它们分别返回一个矩形和一个三角形的面积。
class Figure
{
double dim1;
double dim2; Figure(double a, double b)
{
dim1 = a;
dim2 = b;
} double area()
{
System.out.println("Area for Figure is undefined.");
return 0;
}
} class Rectangle extends Figure
{
Rectangle(double a, double b)
{
super(a, b);
} // override area for rectangle
double area()
{
System.out.println("Inside Area for Rectangle.");
return dim1 * dim2;
}
} class Triangle extends Figure
{
Triangle(double a, double b)
{
super(a, b);
} // override area for right triangle
double area()
{
System.out.println("Inside Area for Triangle.");
return dim1 * dim2 / 2;
}
} public class myJavaTest
{
public static void main(String args[])
{
Figure f = new Figure(10, 10);
Rectangle r = new Rectangle(9, 5);
Triangle t = new Triangle(10, 8); Figure figref; figref = r;
System.out.println("Area is " + figref.area()); figref = t;
System.out.println("Area is " + figref.area()); figref = f;
System.out.println("Area is " + figref.area()); }
}
输出:
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 修饰符指定某些方法必须由子类实现,你不去实现就不让你运行,这样子类就必须重载它们,而不能简单使用超类中定义的版本。
考虑下面的程序:
// A Simple demonstration of abstract.
abstract class A
{
abstract void callme();//声明抽象方法,不具体实现,交给子类实现 // 用一个抽象类去实例化一个对象是不允许的,但在类里面实现一个具体方法还是允许的
void callmetoo()
{
System.out.println("This is a concrete method.");
}
} class B extends A
{
void callme() //实现超类的抽象方法
{
System.out.println("B's implementation of callme.");
}
} public class myJavaTest
{
public static void main(String args[])
{
A a;
B b = new B();
a = b;
a.callme();
a.callmetoo();
}
}
输出:
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类:
// Using abstract methods and classes.
abstract class Figure
{
double dim1;
double dim2; Figure(double a, double b)
{
dim1 = a;
dim2 = b;
} // area is now an abstract method
abstract double area();
} class Rectangle extends Figure
{
Rectangle(double a, double b)
{
super(a, b);
} // override area for rectangle
double area()
{
System.out.println("Inside Area for Rectangle.");
return dim1 * dim2;
}
} class Triangle extends Figure
{
Triangle(double a, double b)
{
super(a, b);
} // override area for right triangle
double area()
{
System.out.println("Inside Area for Triangle.");
return dim1 * dim2 / 2;
}
} public class myJavaTest
{
public static void main(String args[])
{
// Figure f = new Figure(10, 10); // 非法的,因为抽象类是不能够创建对象的
Rectangle r = new Rectangle(9, 5);
Triangle t = new Triangle(10, 8);
Figure figref; // 仅仅声明了一个指向Figure类的引用,是不会创建具体对象的,所以语句合法 figref = r;
System.out.println("Area is " + figref.area()); figref = t;
System.out.println("Area is " + figref.area());
}
}
56行变量figref声明成Figure的一个引用,意思是说它可以用来引用任何从Figure派生的对象。
Java学习笔记之方法重载,动态方法调度和抽象类的更多相关文章
- Java学习笔记-File类的基本方法
要渐渐养成写博客的习惯-----> 前段时间看Mars的java中的I/O流没怎么懂,发现I/O流好难啊.今天重新看一遍其他教学,还有书籍,做些笔记,记录下每天的学习生活. File类的一些方法 ...
- Java学习笔记6---字符串比较方法compareTo(String str)
方法原型为int compareTo(String str),返回值为int型,参数为字符串类型. 下面是简单示例: /* * compareTo()返回参与比较的两个字符串的ascii码差值 * O ...
- java学习笔记(中级篇)—JDK动态代理
一.什么是代理模式 相信大家都知道代理商这个概念,在商业中,代理商无处不在.假设你要去买东西,你不可能去找真正的厂家去买,也不可能直接跟厂家提出需求,代理商就是这中间的一桥梁,连接买家和厂商.你要买或 ...
- java学习笔记5--类的方法
接着前面的学习: java学习笔记4--类与对象的基本概念(2) java学习笔记3--类与对象的基本概念(1) java学习笔记2--数据类型.数组 java学习笔记1--开发环境平台总结 本文地址 ...
- Java程序猿的JavaScript学习笔记(9—— jQuery工具方法)
计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...
- 《深入Java虚拟机学习笔记》- 第19章 方法的调用与返回
<深入Java虚拟机学习笔记>- 第19章 方法的调用与返回
- Java笔记 —— 方法重载和方法重写
Java笔记 -- 方法重载和方法重写 h2{ color: #4ABCDE; } a{ text-decoration: none !important; } a:hover{ color: red ...
- Java学习笔记之---方法和数组
Java学习笔记之---方法与数组 (一)方法 (1)什么是方法? 方法是解决一类问题的步骤的有序组合 方法包含于类或对象中 方法在程序中被创建,在其他地方被引用 (2)方法的优点 使程序变得更简短而 ...
- Java学习总结之方法重载和方法重写
在学习方法的阶段我学习了方法重载(Overload),而在学习面向对象三大特性之继承的时候我又学习了方法重写(Override). 概念: 方法重载:在同一个类中,允许存在一个以上的同名方法,只要 ...
随机推荐
- LoadRunner--内存指标介绍
Threads——线程数当前全部线程数============================================ Available MBytes——物理内存的可用数指计算机上可用于运行 ...
- Linux中的.emacs文件
刚开始的时候在Windows下使用emacs,那个时候配置 .emacs文件直接去C盘里\Users\(username)\AppData\Roaming 路径下查找就可以了(最开始的时候可以打开em ...
- BITED程序员语言学习心得之:C#语言基础
一.HelloWorld 我们先来看看最简单的C#代码——HelloWorld: using System; using System.Collections.Generic; using Syste ...
- 【转】 Linux Shell 命令--rename
重命名文件,经常用到mv命令,批量重命名文件rename是最好的选择,Linux的rename 命令有两个版本,一个是C语言版本的,一个是Perl语言版本的,判断方法:输入man rename 看到第 ...
- Linux网卡启动报错(this device is not active)
重启网络服务 service network restart 报如下错误: shutting down interface eth0: error:device "eth0" ...
- Hadoop学习记录(7)|Eclipse远程调试Hadoop
1.创建Hadoop项目 2.创建包.类 这里使用hdfs.WordCount为例 3.编写自定Mapper和Reducer程序 MyMapper类 static class MyMapper ext ...
- 【Maven】Maven下载源码和Javadoc的方法
1:Maven命令下载源码和javadocs 当在IDE中使用Maven时如果想要看引用的jar包中类的源码和javadoc需要通过maven命令下载这些源码,然后再进行引入,通过mvn命令能够容易的 ...
- AndroidStudio debug
1. view as text
- HDU 2516 取石子游戏(FIB博弈)
取石子游戏 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submi ...
- OpenXML操作word
OpenXML概述 项目中经常需要操作word,之前的方式是采用COM接口,这个接口很不稳定,经常报错.现在开始采用OpenXML.OpenXML(OOXML)是微软在Office 2007中提出的一 ...