1、接口的转换(向下)
子类对向和父类对象可以进行类型转化。接口也一样可以。
package com.test;// 接口Animal
public interface Animal {void bark(); //等价于public abstract void bark();void move(); //等价于public abstract void move();
}package com.test;// 通过接口Animal实现的Dog类
public class Dog implements Animal{public void bark() {System.out.println("狗在叫.");}public void move() {System.out.println("狗在奔跑。");}
}// 通过接口Animal实现的Cat类
public class Cat implements Animal{public void bark() {System.out.println("猫在喵。");}public void move() {System.out.println("猫在跳。");}
}// 通过实现两个接口,包括Animal接口的类Bird
public class Bird implements Animal,Flyable{public void bark() {System.out.println("鸟在唱歌。");}public void move() {System.out.println("鸟在蹦蹦跳跳。");}public void fly() {System.out.println("鸟在飞翔。");}
}//
public class Zoo {public static void main(String[] args) {Animal[] animals = {new Dog(),new Cat(),new Bird()};for (Animal an : animals) {an.bark();an.move();}((Flyable)animals[2]).fly();}
}
上面代码有两个接口Animal和Flyable,类Dog、Cat分别实现了Animal接口,类Bird同时实现了Animal和Flyable两个接口。
因为类Dog、Cat、Bird都实现了接口Animal,上面代码中定义的Animal类型的数组animals中的成员可以包含Dog、Cat、Bird类的实例对象。即下面一行代码是被Java允许的:
Animal[] animals = {new Dog(),new Cat(),new Bird()};
这样,数组中animals的元素(Animal类型变量)可以执行Animal接口中定义的,并在Dog、Cat、Bird类中实现的方法(bark()和move())。
animals[2]是Bird类的实例对象,但是它被声明成父接口Animal类型,要使用Bird类中实现的Flyable接口中的fly()方法,需要“向下转换”,即使用一对括号(子类/子接口)把animals[2]转换为Flyable接口类型,然后就可以调用Flyable接口中定义的,在Bird类中实现的fly()方法,如下代码:
((Flyable)animals[2]).fly();
需要明白的是:经过(Flyable) 进行转化后的animals[2](Bird类的实例),仅有接口Flyable定义的Bird类中实现的fly()方法。
可以这样理解:
(1)Bird类实现了Animal接口和Flyable接口;
(2)变量animals 被声明成Animal接口类型,但是通过Bird类创建的实例对象animals[2],这个变量animals[2]就像是被封印了非Animal接口中定义的其它方法,仅能使用Animal接口中定义的在Bird类中实现的方法。
(3)通过Flyable接口进行强制转化通过Bird类创建的实例对象animals[2],就像是解封了Bird类中实现的Flyable接口中的方法(fly()方法),但是也同时封印了非Flyable接口中定义的其它方法(bark()和move()方法)。
2、接口的转换(向下)
package com.test;public class Trainer {// 定义一个属性,类型是Animal接口private Animal animal;// 动物园里的驯兽师类Trainer构造方法public Trainer(Animal an) {this.animal = an;}// 驯兽师的进行驯兽方法public void train() {animal.bark();animal.move();}
}
package com.test;public class Zoo {public static void main(String[] args) {// 使用Animal接口类型声明animals数组// 数组animals的成员分别是实现了Animal接口的Dog、Cat、Bird类Animal[] animals = {new Dog(),new Cat(),new Bird()};// 创建动物园驯兽师类的实例对象Trainer trainer;for (Animal an : animals) {trainer = new Trainer(an);trainer.train();}}
}
前一部分的代码建立了类Dog、Cat、Bird都实现了Animal接口。
在驯兽师Trainer类中定义了Animal接口类型变量animal,通过构造函数Trainer(Animal an),传入的Animal接口类型变量animal,赋值给Trainer类中定义的私有变量animal(是Animal接口类型),在Tainer类的训练方法train()方法中执行Animal接口中定义的方法(bark()和move())。
在Zoo类中的main()函数中:
(1)定义了animals数组,数组类型是Animal,但是数组中的元素是都实现了Aniaml接口的Dog、Cat、Bird类的实例对象。这些对象都具有Animal接口中定义的方法(bark()和move())。
(2)创建驯兽师类Trainer的实例,传入给Trainer的实例的方法train()的实参是animals数组,其中的元素分别是Dog、Cat、Bird类的实例对象。根据传入的实参不同,执行不同的类的实例对象的方法(bark()和move())。
通过设计Trainer类,就不需要针对每个动物去创建对应的驯兽师类(DogTrainer、CatTrainer、BirdTrainer)了。
为了再增加其他动物,只要这个动物实现了Animal接口,就可以在Zoo类中创建相应的实例对象,加入到声明为Animal类型的数组animals中。Trainer类不用做任何修改,即可训练这个动物了,当然只能训练Animal接口中定义的、在该类中实现的动作(bark()和move())。
这样,未来仅需要修改Animal接口(丰富训练内容),及创建实现Animal接口的更多动物类,Trainer类和Zoo类中的代码不用做任何修改,动物园的动物们都可以得到驯兽师(Trainer类)的训练。
上面的阐述特别的啰嗦,只是这让我比较清晰地理解了上面代码的意义。