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类)的训练。
上面的阐述特别的啰嗦,只是这让我比较清晰地理解了上面代码的意义。