动手动脑-多态

怎样判断对象是否可以转换? 

可以使用instanceof运算符判断一个对象是否可以转换为指定的类型:
Object obj="Hello";
if(obj instanceof String)
System.out.println("obj对象可以被转换为字符串");

下列语句哪一个将引起编译错误?为什么?哪一个会引起运行时错误?为什么?
  m=d;
  d=m;
  d=(Dog)m;
  d=c;(子类是否能给子类赋值)
  c=(Cat)m;

源代码:

class Mammal{}

class Dog extends Mammal {}

class Cat extends Mammal{}

public class TestCast

{

public static void main(String args[])

{

Mammal m;

Dog d=new Dog();

Cat c=new Cat();

m=d;//子类d可以给父类m赋值

//d=m;

d=(Dog)m;

//d=c;//false

//c=(Cat)m;

}

 原因:子类对象可以直接赋给基类变量。

 

          基类对象要赋给子类对象变量,必须执行类型转换,其语法是:子类对象变量=(子类名)基类对象名。

更改后的代码为:

class Mammal{}

class Dog extends Mammal {}

class Cat extends Mammal{}

public class TestCast

{

public static void main(String args[])

{

Mammal m;

Dog d=new Dog();

Cat c=new Cat();

m=d;//子类d可以给父类m赋值

        d=m;

d=(Dog)m;

//d=c;//false 子类不可以给子类赋值

c=(Cat)m;

}

}

 

多态的含义和用途

让我们看一个开发场景:

某动物园有一饲养员小李,

每天需要给他所负责饲养的狮子、猴子和鸽子喂食。

请用一个程序来模拟他喂食的过程。

三种动物对应三个类,每个类定义一个eat()方法,表示吃饲养员给它们的食物。

再设计一个Feeder类代表饲养员,其name字段保存饲养员名字,三个方法分别代表喂养三种不同的动物,其参数分别引用三种动物

public class Zoo

{

public static void main(String args[])
{
Feeder f = new Feeder("小李");
// 饲养员小李喂养一只狮子
f.feedLion(new Lion());
// 饲养员小李喂养十只猴子
for (int i = 0; i < 10; i++)
{
f.feedMonkey(new Monkey());
}
// 饲养员小李喂养5只鸽子
for (int i = 0; i < 5; i++)
{
f.feedPigeon(new Pigeon());
}
}
}
class Feeder
{
public String name;
public Feeder(String name)
{
this.name = name;
}
public void feedLion(Lion l)
{
l.eat();
}
public void feedPigeon(Pigeon p)
{
p.eat();
}
public void feedMonkey(Monkey m)
{
m.eat();
}
}
class Lion
{
public void eat()
{
System.out.println("我不吃肉谁敢吃肉!");
}
}
class Monkey
{
public void eat()
{
System.out.println("我什么都吃,尤其喜欢香蕉。");
}
}
class Pigeon
{
public void eat()
{
System.out.println("我要减肥,所以每天只吃一点大米。");
}
}
这种编程方式有什么不合理的地方?

每次喂食都要创建一次类。重复步骤多。

 引入继承

定义一个抽象基类Animal,其中定义一个抽象方法eat(),三个子类实现这个抽象方法。

Feeder类的三个喂养方法现在可以合并为一个feedAnimal()方法,注意它接收一个类型为Animal参数,而不是三个具体的动物类型。

依据多态特性,此方法将可以接收任何一个派生自Animal类的子类对象

public class Zoo
{
public static void main(String args[])
{
Feeder f = new Feeder("小李");
//饲养员小李喂养一只狮子
f.feedAnimal(new Lion());
//饲养员小李喂养十只猴子
for (int i = 0; i < 10; i++)
{
f.feedAnimal(new Monkey());
}
//饲养员小李喂养5只鸽子
for (int i = 0; i < 5; i++)
{
f.feedAnimal(new Pigeon());
}
}
}
class Feeder
{
public String name;
Feeder(String name)
{
this.name = name;
}
public void feedAnimal(Animal an)
{
an.eat();
}
}
abstract class Animal
{
public abstract void eat();
}
class Lion extends Animal
{
public void eat()
{
System.out.println("我不吃肉谁敢吃肉!");
}
}
class Monkey extends Animal
{
public void eat()
{
System.out.println("我什么都吃,尤其喜欢香蕉。");
}
}
class Pigeon extends Animal
{
public void eat()
{
System.out.println("我要减肥,所以每天只吃一点大米。");
}
}
进一步优化喂养一群动物

package zoo3;
public class Zoo
public static void main(String args[]) {
Feeder f = new Feeder("小李");
Animal[] ans = new Animal[16];
//饲养员小李喂养一只狮子
ans[0] = new Lion();
//饲养员小李喂养十只猴子
for (int i = 0; i < 10; i++) {
ans[1 + i] = new Monkey();
}
//饲养员小李喂养5只鸽子
for (int i = 0; i < 5; i++) {
ans[11 + i] = new Pigeon();
}
f.feedAnimals(ans);
}
}
class Feeder {
public String name;
Feeder(String name) {
this.name = name;
}
public void feedAnimals(Animal[] ans) {
for (Animal an : ans) {
an.eat();
}
}
}
abstract class Animal {
public abstract void eat();
}
class Lion extends Animal {
public void eat() {
System.out.println("我不吃肉谁敢吃肉!");
}
}
class Monkey extends Animal {
public void eat() {
System.out.println("我什么都吃,尤其喜欢香蕉。");
}
}
class Pigeon extends Animal {
public void eat() {
System.out.println("我要减肥,所以每天只吃一点大米。");
}
}
第二次重构之后,Feeder类的feedAnimals()方法接收的是一个Animal数组,这有一个限制,就是只能创建固定个数的数组,无法动态地增减动物个数。

想想以下场景:

(1)动物园新进了一些动物

(2)某动物生病不幸死亡

(3)……

我们的代码能否应付以上的场景

import java.util.Vector;
public class Zoo {
public static void main(String args[]) {
Feeder f = new Feeder("小李");
Vector<Animal> ans = new Vector<Animal>();
//饲养员小李喂养一只狮子
ans.add(new Lion());
//饲养员小李喂养十只猴子
for (int i = 0; i < 10; i++) {
ans.add(new Monkey());
}
//饲养员小李喂养5只鸽子
for (int i = 0; i < 5; i++) {
ans.add(new Pigeon());
}
f.feedAnimals(ans);
}
}
class Feeder {
public String name;
Feeder(String name) {
this.name = name;
}
//Vector<T>是JDK中提供的一个对象集合,可以随时向其中加入或移除对象
public void feedAnimals(Vector<Animal> ans) {
for (Animal an : ans) {
an.eat();
}
}
}
abstract class Animal {
public abstract void eat();
}
class Lion extends Animal {
public void eat() {
System.out.println("我不吃肉谁敢吃肉!");
}
}
class Monkey extends Animal {
public void eat() {
System.out.println("我什么都吃,尤其喜欢香蕉。");
}
}
class Pigeon extends Animal {
public void eat() {
System.out.println("我要减肥,所以每天只吃一点大米。");
}
}

多态编程有两种主要形式:

(1)继承多态:示例程序使用的方法

(2)接口多态:使用接口代替抽象基类。

使用多态最大的好处是,当你要修改程序并扩充系统时,你需要修改的地方较少,对其它部分代码的影响较小

相关文章
相关标签/搜索