📄 java04_09.htm
字号:
<html>
<head>
<meta http-equiv="Content-Language" content="zh-cn">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name="GENERATOR" content="Microsoft FrontPage 4.0">
<meta name="ProgId" content="FrontPage.Editor.Document">
<title>Java程序设计</title>
</head>
<body background="Bg.gif">
<p align="center"><font size="5"><b>§4.9 运行时多态</b></font></p>
<p align="left">
运行时多态将多态的特性发挥到及至。它允许程序员不必在编制程序时就确定调用哪一个方法,而是当方法被调用时,系统根据当时对象本身所属的类来确定调用哪个方法,这种技术称为后期(动态)联编。当然这会降低程序的运行效率,所以只在子类对父类方法进行覆盖时才使用。</p>
<p align="left"> 我们先来看一个简单的例子:</p>
<p align="left">例1<br>
class father{<br>
public void normal() {<br>
System.out.println("这是父类的普通方法");<br>
} <br>
}<br>
class sun extends father{<br>
public void normal() {
//这里覆盖了父类的同名方法<br>
System.out.println("这是子类的普通方法");<br>
} <br>
}<br>
<br>
public class inheritApp{<br>
public static void main(String argv[]){<br>
father pfather;<br>
sun psun;<br>
pfather=new father();<br>
pfather.normal(); //这里输出:这是父类的普通方法<br>
psun = new sun();<br>
psun.normal(); //这里输出:这是子类的普通方法<br>
}<br>
} <br>
从上面这个例子来看,pfather调用了父类的normal()方法,psun调用了子类的normal()方法,这似乎可以在编译的时候就确定,但实际情况并非如此,看下面这个更复杂的例子。</p>
<p align="left">例2<br>
class father{<br>
private int value;<br>
public father(int k) {<br>
System.out.println("这是父类的带参数的构造函数,参数为:"+k);<br>
value=k;<br>
}<br>
public void normal() {<br>
System.out.println("这是父类的普通方法");<br>
} <br>
public void show(){<br>
System.out.println("value="+value);<br>
} <br>
}<br>
<br>
class sun extends father{<br>
public sun(){<br>
System.out.println("这是子类的构造函数");<br>
}<br>
public void normal() {<br>
System.out.println("这是子类的普通方法");<br>
} <br>
}<br>
<br>
public class inheritApp{<br>
public static void main(String argv[]){<br>
father p,other;
//注意,这里都声明成父类的变量<br>
System.out.println("下面开始用父类的构造方法生成对象");<br>
p=new father(7788); //用父类的构造函数<br>
other=p;<br>
other.normal(); //这是调用的哪个normal呢?<br>
other.show();<br>
System.out.println("下面开始用子类的构造方法生成对象");<br>
p=new sun();
//用的是子类的构造函数 <br>
other=p;<br>
other.normal(); //这是调用的哪个normal呢?<br>
}<br>
} <br>
<br>
补充:在Java中,允许用父类声明的变量用子类的构造函数来实例化,也允许用子类来给它赋值,这时它相当于是子类的对象。但反之则不行。</p>
<p align="left">
看了上面这个例子的输出,我们可以知道调用的哪个normal完全要根据other当时所属的类来决定。</p>
<p align="left">
当对象作为参数传递时,这一特性特别有用,例如下面这个例子:</p>
<p align="left"> void testfun(father p){<br>
.....<br>
p.normal(); <br>
//写这个程序时,完全不知道调用者传入的是哪种对象,所以也就不知道调用了哪个normal()<br>
}</p>
<p align="left">
还要指出的是,这种运行时的多态只对成员方法有效,对的成员变量引用在编译时就已经确定好了,我们来看下面这个例子:</p>
<p align="left">class Point {<br>
int x = 0, y = 0;<br>
void move(int dx, int dy) { x += dx; y += dy; }<br>
int getX() { return x; }<br>
int getY() { return y; }<br>
int color;<br>
}<br>
<br>
class RealPoint extends Point {<br>
float x = 0.0f, y = 0.0f;<br>
void move(int dx, int dy) { move((float)dx, (float)dy); }<br>
void move(float dx, float dy) { x += dx; y += dy; }<br>
int getX() { return (int)Math.floor(x); }<br>
int getY() { return (int)Math.floor(y); }<br>
}</p>
<p align="left">我们来测试输出:</p>
<p align="left">class Test {<br>
<br>
public static void main(String[] args) {<br>
RealPoint rp = new RealPoint();<br>
Point p = rp;<br>
rp.move(1.71828f, 4.14159f);<br>
p.move(1, -1);<br>
show(p.x, p.y);<br>
show(rp.x, rp.y);<br>
show(p.getX(), p.getY());<br>
show(rp.getX(), rp.getY());<br>
}<br>
<br>
static void show(int x, int y) {<br>
System.out.println("(" + x + ", " + y + ")");<br>
}<br>
<br>
static void show(float x, float y) {<br>
System.out.println("(" + x + ", " + y + ")");<br>
}<br>
}<br>
<br>
从这个例子的输出结果可以看出,方法的覆盖和变量的隐藏的表现是不同的。 </p>
<p align="left">再来看下面这个例子:</p>
<p align="left">class Super {<br>
<b>static</b> String greeting() { return "Goodnight"; }<br>
String name() { return "基类"; }<br>
}<br>
<br>
class Sub extends Super {<br>
<b>static</b> String greeting() { return "Hello"; }<br>
String name() { return "子类"; }<br>
}<br>
<br>
class Test {<br>
public static void main(String[] args) {<br>
Super s = new Sub();<br>
System.out.println(s.greeting() + ", " + s.name());<br>
}<br>
}<br>
<br>
从输出可以看出,静态成员方法和实例成员方法的表现也不相同。当然,这些区别只有在运行时多态的情况下才会表现出来。<br>
</p>
<p align="left"><a href="index.htm">回目录</a> <a href="java04_08.htm">上一课</a>
<a href="java04_10.htm">下一课</a></p>
</body>
</html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -