⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 java04_09.htm

📁 JAVA的课件
💻 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"> &nbsp;   
运行时多态将多态的特性发挥到及至。它允许程序员不必在编制程序时就确定调用哪一个方法,而是当方法被调用时,系统根据当时对象本身所属的类来确定调用哪个方法,这种技术称为后期(动态)联编。当然这会降低程序的运行效率,所以只在子类对父类方法进行覆盖时才使用。</p>  
  
<p align="left">&nbsp;&nbsp;&nbsp; 我们先来看一个简单的例子:</p>  
  
<p align="left">例1<br>  
class father{<br>   
&nbsp; public void normal()  {<br>   
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("这是父类的普通方法");<br>  
&nbsp; }&nbsp;<br>  
}<br>  
class sun extends father{<br>   
&nbsp;&nbsp; public void normal()  {&nbsp;   
//这里覆盖了父类的同名方法<br>  
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("这是子类的普通方法");<br>  
&nbsp; }&nbsp;<br>  
}<br>  
<br>  
public class inheritApp{<br>   
&nbsp; public static void main(String argv[]){<br>   
&nbsp;&nbsp; father pfather;<br>  
&nbsp;&nbsp; sun&nbsp;&nbsp;&nbsp; psun;<br>  
&nbsp;&nbsp; pfather=new father();<br>  
&nbsp;&nbsp; pfather.normal();&nbsp; //这里输出:这是父类的普通方法<br>  
&nbsp;&nbsp; psun = new sun();<br>  
&nbsp;&nbsp; psun.normal();&nbsp;&nbsp;&nbsp;&nbsp; //这里输出:这是子类的普通方法<br>  
&nbsp;}<br>  
}&nbsp;<br>  
&nbsp;&nbsp;   
从上面这个例子来看,pfather调用了父类的normal()方法,psun调用了子类的normal()方法,这似乎可以在编译的时候就确定,但实际情况并非如此,看下面这个更复杂的例子。</p>  
<p align="left">例2<br>  
class father{<br>   
&nbsp; private int value;<br>   
&nbsp; public father(int k)  {<br>   
&nbsp;&nbsp; System.out.println("这是父类的带参数的构造函数,参数为:"+k);<br>  
&nbsp;&nbsp; value=k;<br>  
&nbsp; }<br>  
&nbsp; public void normal()  {<br>   
&nbsp;&nbsp;&nbsp; System.out.println("这是父类的普通方法");<br>  
&nbsp; }&nbsp;<br>  
&nbsp; public void show(){<br>   
&nbsp;&nbsp;&nbsp; System.out.println("value="+value);<br>  
&nbsp; }&nbsp;<br>  
}<br>  
<br>  
class sun extends father{<br>   
&nbsp; public sun(){<br>   
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("这是子类的构造函数");<br>  
&nbsp;&nbsp; }<br>  
&nbsp;&nbsp; public void normal()  {<br>   
&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("这是子类的普通方法");<br>  
&nbsp;&nbsp; }&nbsp;<br>  
}<br>  
<br>  
public class inheritApp{<br>   
&nbsp; public static void main(String argv[]){<br>   
&nbsp;&nbsp;&nbsp; father p,other;&nbsp;&nbsp;&nbsp;   
//注意,这里都声明成父类的变量<br>  
&nbsp;&nbsp;&nbsp; System.out.println("下面开始用父类的构造方法生成对象");<br>  
&nbsp;&nbsp;&nbsp; p=new father(7788);&nbsp; //用父类的构造函数<br>  
&nbsp;&nbsp;&nbsp; other=p;<br>  
&nbsp;&nbsp;&nbsp; other.normal();&nbsp; //这是调用的哪个normal呢?<br>  
&nbsp;&nbsp;&nbsp; other.show();<br>  
&nbsp;&nbsp;&nbsp; System.out.println("下面开始用子类的构造方法生成对象");<br>  
&nbsp;&nbsp;&nbsp; p=new sun();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;   
//用的是子类的构造函数&nbsp;&nbsp;<br>  
&nbsp;&nbsp;&nbsp; other=p;<br>  
&nbsp;&nbsp;&nbsp; other.normal();&nbsp; //这是调用的哪个normal呢?<br>  
&nbsp; }<br>  
}&nbsp;<br>  
<br>  
&nbsp;&nbsp;   
补充:在Java中,允许用父类声明的变量用子类的构造函数来实例化,也允许用子类来给它赋值,这时它相当于是子类的对象。但反之则不行。</p>  
<p align="left">&nbsp;&nbsp;   
看了上面这个例子的输出,我们可以知道调用的哪个normal完全要根据other当时所属的类来决定。</p>  
<p align="left">&nbsp;&nbsp;   
当对象作为参数传递时,这一特性特别有用,例如下面这个例子:</p>  
<p align="left">&nbsp;&nbsp; void testfun(father p){<br>  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; .....<br>  
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; p.normal();&nbsp;<br>  
//写这个程序时,完全不知道调用者传入的是哪种对象,所以也就不知道调用了哪个normal()<br>  
&nbsp;&nbsp; }</p>  
<p align="left">&nbsp; 
还要指出的是,这种运行时的多态只对成员方法有效,对的成员变量引用在编译时就已经确定好了,我们来看下面这个例子:</p>
<p align="left">class Point {<br> 
&nbsp; int x = 0, y = 0;<br> 
&nbsp; void move(int dx, int dy) { x += dx; y += dy; }<br> 
&nbsp; int getX() { return x; }<br> 
&nbsp; int getY() { return y; }<br> 
&nbsp; int color;<br> 
}<br> 
<br> 
class RealPoint extends Point {<br> 
&nbsp;&nbsp; float x = 0.0f, y = 0.0f;<br> 
&nbsp;&nbsp; void move(int dx, int dy) { move((float)dx, (float)dy); }<br> 
&nbsp;&nbsp; void move(float dx, float dy) { x += dx; y += dy; }<br> 
&nbsp;&nbsp; int getX() { return (int)Math.floor(x); }<br> 
&nbsp;&nbsp; int getY() { return (int)Math.floor(y); }<br> 
}</p> 
<p align="left">我们来测试输出:</p>
<p align="left">class Test {<br> 
<br> 
&nbsp; public static void main(String[] args) {<br> 
&nbsp;&nbsp;&nbsp; RealPoint rp = new RealPoint();<br> 
&nbsp;&nbsp;&nbsp; Point p = rp;<br> 
&nbsp;&nbsp;&nbsp; rp.move(1.71828f, 4.14159f);<br> 
&nbsp;&nbsp;&nbsp; p.move(1, -1);<br> 
&nbsp;&nbsp;&nbsp; show(p.x, p.y);<br> 
&nbsp;&nbsp;&nbsp; show(rp.x, rp.y);<br> 
&nbsp;&nbsp;&nbsp; show(p.getX(), p.getY());<br> 
&nbsp;&nbsp;&nbsp; show(rp.getX(), rp.getY());<br> 
&nbsp; }<br>
<br>
&nbsp; static void show(int x, int y) {<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("(" + x + ", " + y + ")");<br> 
&nbsp; }<br>
<br>
&nbsp; static void show(float x, float y) {<br> 
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println("(" + x + ", " + y + ")");<br> 
&nbsp; }<br>
}<br>
<br>
从这个例子的输出结果可以看出,方法的覆盖和变量的隐藏的表现是不同的。&nbsp;</p>
<p align="left">再来看下面这个例子:</p>
<p align="left">class Super {<br> 
&nbsp; <b>static</b> String greeting() { return "Goodnight"; }<br> 
&nbsp; String name() { return "基类"; }<br> 
}<br> 
<br> 
class Sub extends Super {<br> 
&nbsp; <b>static</b> String greeting() { return "Hello"; }<br> 
&nbsp; String name() { return "子类"; }<br> 
}<br> 
<br> 
class Test {<br> 
&nbsp; public static void main(String[] args) {<br> 
&nbsp; Super s = new Sub();<br> 
&nbsp; System.out.println(s.greeting() + ", " + s.name());<br> 
&nbsp;}<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 + -