Java Review (十一、面向对象----多态)

Java面向对象之多态详解

多态是同一个行为具有多个不同表现形式或形态的能力。
 

多态性

Java 引用变量有两个类型 :一个是编译时类型,一个是运行时类型,编译时类型由声明该变量时使用的类型决定,运行时类型由实际赋给该变量的对象决定,如果编译时类型和运行时类型不一致,就可能出现所谓的多态(Polymorphism)

多态实例

<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java">
<span style="color:#a626a4">class</span> <span style="color:#4078f2">BaseClass</span> {
	<span style="color:#a626a4">public</span> <span style="color:#986801">int</span> <span style="color:#986801">book</span> <span style="color:#ab5656">=</span> <span style="color:#986801">6</span>;

	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">base</span>() {
		System.out.println(<span style="color:#50a14f">"父类的普通方法"</span>);
	}

	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">test</span>() {
		System.out.println(<span style="color:#50a14f">"父类的被覆盖的方法"</span>);
	}
}

<span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">SubClass</span> <span style="color:#a626a4">extends</span> <span style="color:#4078f2">BaseClass</span> {
	<span style="color:#a0a1a7"><em>// 重新定义一个 book 实例变量隐藏父类 book 实例变量</em></span>
	<span style="color:#a626a4">public</span> <span style="color:#986801">String</span> <span style="color:#986801">book</span> <span style="color:#ab5656">=</span> <span style="color:#50a14f">"子类书籍 "</span>;

	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">test</span>() {
		System.out.println(<span style="color:#50a14f">" 子类的覆盖父类的方法"</span>);
	}

	<span style="color:#a626a4">public</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">sub</span>() {
		System.out.println(<span style="color:#50a14f">"子类的普通方法 "</span>);
	}

	<span style="color:#a626a4">public</span> <span style="color:#a626a4">static</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">main</span>(String[] args) {
		<span style="color:#a0a1a7"><em>// 下面编译时类型和运行时类型完全一样 因此不存在多态</em></span>
		<span style="color:#986801">BaseClass</span> <span style="color:#986801">bc</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">BaseClass</span>();
		<span style="color:#a0a1a7"><em>// 输出</em></span>
		System.out.println(bc.book);
		<span style="color:#a0a1a7"><em>// 下面两次调用将执行 BaseClass的方法</em></span>
		bc.base();
		bc.test();
		<span style="color:#a0a1a7"><em>// 下面编译时类型和运行时类型完全 样,因此不存在多态</em></span>
		<span style="color:#986801">SubClass</span> <span style="color:#986801">sc</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">SubClass</span>();
		<span style="color:#a0a1a7"><em>// 输出 轻量级 Java EE 企业应用实战"</em></span>
		System.out.println(sc.book);
		<span style="color:#a0a1a7"><em>// 下面调用将执行从父类继承到的 base ()方法</em></span>
		sc.base();
		<span style="color:#a0a1a7"><em>// 下面调用将执行当前类的 test ()方法</em></span>
		sc.test();
		<span style="color:#a0a1a7"><em>// 下面编译时类型和运行时类型不 样,多态发生</em></span>
		<span style="color:#986801">BaseClass</span> <span style="color:#986801">ploymophicBc</span> <span style="color:#ab5656">=</span> <span style="color:#a626a4">new</span> <span style="color:#4078f2">SubClass</span>();
		<span style="color:#a0a1a7"><em>// 输出表明访问的是父类对象的实例变量</em></span>
		System.out.println(ploymophicBc.book);
		<span style="color:#a0a1a7"><em>// 下面调用将执行从父类继承到的 base ()方法</em></span>
		ploymophicBc.base();
		<span style="color:#a0a1a7"><em>// 下面调用将执行当前类的 test ()方法</em></span>
		ploymophicBc.test();
		<span style="color:#a0a1a7"><em>// 因为 ploymophicBC 的编译时类型是 BaseClass</em></span>
		<span style="color:#a0a1a7"><em>// BaseClass 类没有提供 sub ()方法,所以下面代码编译时会出现错误</em></span>
		<span style="color:#a0a1a7"><em>// plonophicBc.sub()</em></span>

	}
}


</code></span></span>

结果:

<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#986801">6</span>
父类的普通方法
父类的被覆盖的方法
子类书籍 
父类的普通方法
 子类的覆盖父类的方法
<span style="color:#986801">6</span>
父类的普通方法
 子类的覆盖父类的方法
</code></span></span>
  • 父类引用指向子类对象时,多态发生了

引用变量在编译阶段只能调用其编译时类型所具有的方法,但运行时则执行它运行时类型所具有的方法 。因此,编写 Java 代码时,引用变量只能调用声明该变量时所用类里包含的方法。 例如,通过 Object p = new Person()代码定义一个变量 ,则这个变量只能调用Object 类的方法,而不能调用 Person 类里定义的方法

引用变量的强制类型转换

编写Java程序时,引用变量只能调用它编译时类型的方法,而不能调用它运行时类型的方法,即使它实际所引用的对象确实包含该方法。如果需要让这个引用变量调用它运行时类型的方法,则必须把 它强制类型转换成运行时类型,强制类型转换需要借助于类型转换运算符。

类型转换运算符是小括号,类型转换运算符的用法是:(type)variable,这种用法可以将variable变量转换成一个type类型的变量。类型转换运算符可以将一个基本类型变量转换成另一个类型。

除此之外,这个类型转换运算符还可以将一个引用类型变量转换成其子类类型。这种强制类型转换不是万能的,当进行强制类型转换时需要注意:

  • 基本类型之间的转换只能在数值类型之间进行,这里所说的数值类型包括整数型、字符型和浮 点型。但数值类型和布尔类型之间不能进行类型转换。
  • 引用类型之间的转换只能在具有继承关系的两个类型之间进行,如果是两个没有任何继承关系 的类型,则无法进行类型转换,否则编译时就会出现错误。如果试图把一个父类实例转换成子 类类型,则这个对象必须实际上是子类实例才行(即编译时类型为父类类型,而运行时类型是子类类型),否则将在运行时引发ClassCastException异常。

下面是进行强制类型转换的示范程序。下面程序详细说明了哪些情况可以进行类型转换,哪些情况不可以进行类型转换。

引用类型强制转换实例

<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">ConversionTest</span> {
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">static</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">main</span>(String[] args) {
		<span style="color:#986801">double</span> <span style="color:#986801">d</span> <span style="color:#ab5656">=</span> <span style="color:#986801">13.4</span>;
		<span style="color:#986801">long</span> <span style="color:#986801">l</span> <span style="color:#ab5656">=</span> (<span style="color:#986801">long</span>) d;
		System.out.println(l);
		<span style="color:#986801">int</span> <span style="color:#986801">in</span> <span style="color:#ab5656">=</span> <span style="color:#986801">5</span>;
    <span style="color:#a0a1a7"><em>//试图把 个数值类型的变量转换为 boolean 类型,下面代码编译出错</em></span>
    <span style="color:#a0a1a7"><em>//编译时会提示:不可转换的类型</em></span>
   <span style="color:#a0a1a7"><em>// boolean b = (boolean)in ; </em></span>
		<span style="color:#986801">Object</span> <span style="color:#986801">obj</span> <span style="color:#ab5656">=</span> <span style="color:#50a14f">"Hello"</span>;
    <span style="color:#a0a1a7"><em>// obj 变量的编译时类型为 Object,Object、String 存在继承关系,可以强制类型转换</em></span>
    <span style="color:#a0a1a7"><em>//而且 obj 变量的实际类型是 String ,所以运行时也可通过</em></span>
		<span style="color:#986801">String</span> <span style="color:#986801">objStr</span> <span style="color:#ab5656">=</span> (String) obj;
		System.out.println(objStr);

   <span style="color:#a0a1a7"><em>// 定义一个 objpri 变量,编译时类型为 bject ,实际类型为 Integer</em></span>
		<span style="color:#986801">Object</span> <span style="color:#986801">objpri</span> <span style="color:#ab5656">=</span> Integer.valueOf(<span style="color:#986801">5</span>);
    <span style="color:#a0a1a7"><em>// objpri 变量的编译时类型为 Object, objPr的运行时类型为 Integer</em></span>
   <span style="color:#a0a1a7"><em>// Object Integer 存在继承关系</em></span>
   <span style="color:#a0a1a7"><em>// 可以强制类型转换,而 objpri 变量的实际类型是 Integer</em></span>
   <span style="color:#a0a1a7"><em>// 所以下面代码运行时引发 ClassCastException 异常</em></span>
    <span style="color:#a0a1a7"><em>//String str = (String)objPri;</em></span>
	}
}
</code></span></span>

当把子类对象赋给父类引用变量时,被称为向上转型( upcasting ),这种转型总是可以成功的,这也从另一个侧面证实了子类是一种特殊的父类 。这种转型只是表明这个引用变量的编译时类型是父类,但实际执行它的方法时,依然表现出子类对象的行为方式。但把一个父类对象赋给子类引用交量时,就需要进行强制类型转换,而且还可能在运行时产ClassCastException 异常,使用 instanceof 运算符可以让强制类型转换更安全。

instanceof 运算符

instanceof运算符的前一个操作数通常是一个引用类型变量,后一个操作数通常是一个类(也可以是接口),它用于判断前面的对象是否是后面的类,或者其子类、实现类的实例。如果是,则返回true,否则返回false。

在使用instanceof运算符时需要注意:instanceof运算符前面操作数的编译时类型要么与后面的类相 同,要么与后面的类具有父子继承关系,否则会引起编译错误。

下面程序示范了 instanceof运算符的用法。

instanceof运算符实例

<span style="color:#141418"><span style="background-color:#ffffff"><code class="language-java"><span style="color:#a626a4">public</span> <span style="color:#a626a4">class</span> <span style="color:#4078f2">InstanceTest</span> {
	<span style="color:#a626a4">public</span> <span style="color:#a626a4">static</span> <span style="color:#a626a4">void</span> <span style="color:#4078f2">main</span>(String[] args) {
		<span style="color:#a0a1a7"><em>// 声 hello 时使用 Object 类,则 hello 的编译类型是 Object</em></span>
		<span style="color:#a0a1a7"><em>// Object 是所有类的父类,但 hello 量的实际类型是 String</em></span>
		<span style="color:#986801">Object</span> <span style="color:#986801">hello</span> <span style="color:#ab5656">=</span> <span style="color:#50a14f">"Hello"</span>;
		<span style="color:#a0a1a7"><em>// String Object 类存在继承关系,可以进行 instanceof 运算 返回 true</em></span>
		System.out.println(<span style="color:#50a14f">" 字符串是否是 Object 类的实例"</span> + (hello <span style="color:#a626a4">instanceof</span> Object));
		System.out.println(<span style="color:#50a14f">"字符串是否是 String 类的实例:"</span> + (hello <span style="color:#a626a4">instanceof</span> String)); <span style="color:#a0a1a7"><em>// 返回 true</em></span>
		<span style="color:#a0a1a7"><em>// Math Object 类存在继承关系,可以进行 instanceof 运算。返回 false</em></span>
		System.out.println(<span style="color:#50a14f">"字符串是否是 Math 类的实例"</span> + (hello <span style="color:#a626a4">instanceof</span> Math));
		<span style="color:#a0a1a7"><em>// Stri 呵实现了 Comparable 接口,所以返回 true</em></span>
		System.out.println(<span style="color:#50a14f">"字符串是否是 Comparable 接口的实例"</span> + (hello <span style="color:#a626a4">instanceof</span> Comparable));
		<span style="color:#986801">String</span> <span style="color:#986801">a</span> <span style="color:#ab5656">=</span> <span style="color:#50a14f">"He llo"</span>;
		<span style="color:#a0a1a7"><em>// String 类与 Math 类没有继承关系,所以下面代码编译无法通过</em></span>
		<span style="color:#a0a1a7"><em>// System.out.println( "字符串是否是 Math 类的实例" + (a instanceof Math));</em></span>
	}
}
</code></span></span>

多态实现方式

  • 重写
  • 接口
  • 抽象类和抽象方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值