1:接口回调
接口回调是指:可以把使用实现了某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称为对象功能的接口回调。看下面示例。
interface People {
void peopleList();
}
class Student implements People {
publicvoid peopleList() {
System.out.println("I’m a student.");
}
}
class Teacher implements People {
publicvoid peopleList() {
System.out.println("I’m a teacher.");
}
}
publicclass Example {
publicstaticvoid main(String args[]) {
People a; // 声明接口变量
a = new Student(); // 实例化,接口变量中存放对象的引用
a.peopleList(); // 接口回调
a = new Teacher(); // 实例化,接口变量中存放对象的引用
a.peopleList(); // 接口回调
}
}
I’m a student.
I’m a teacher.
再来看看向上转型(upcasting)的概念。
2.什么是向上转型?
Shape s=new Circle();
这里,创建了一个Circle对象,并把得到的引用立即赋值给Shape。通过继承,Circle就是一种Shape。
假设你调用基类方法(它已在导出类中被覆盖):
s.draw();
由于后期绑定(多态),将会正确调用Circle.draw()方法。
3.Java中的跨类引用
在java里面,关于跨类引用,有两条规则应该记住:
1)如果a是类A的一个引用,那么,a可以指向类A的一个实例。或者说指向类A的一个子类,这是向上转型的情形。
2)如果a是接口A的一个引用,那么,a必须指向实现了接口A的一个类的实例。这是接口回调的情形。
在java里面,向上转型是自动进行的,但是向下转型却不是,
需要我们自己定义强制进行.
class B extends A{}
publicclass A {
publicstaticvoid main(String[] argts){
A a1=new A();
A a2=new B();//Upcasting向上转型
B b1=new B();
B b2=(B) new A();//DownCasting向下转型,[注意]:此处(B)进行了强制转换!
}
}
4.向上转型与接口回调的区别
从实现了某接口的对象,得到对此接口的引用,与向上转型为这个对象的基类,实质上效果是一样的。这些对象都可以调用基类型提供的方法,对于接口来说就是回调接口中的方法,对于父类来说就是调用父类的方法。当然在向上转型的情况下,还牵涉到子类重写(Override)父类方法的情形。
5:java向上转型和向下转型
转型是在继承的基础上而言的,继承是面向对象语言中,代码复用的一种机制,通过继承,子类可以复用父类的功能,如果父类不能满足当前子类的需求,则子类可以重写父类中的方法来加以扩展。
向上转型:子类引用的对象转换为父类类型称为向上转型。通俗地说就是是将子类对象转为父类对象。此处父类对象可以是接口
向下转型:父类引用的对象转换为子类类型称为向下转型。
前者是一个向上转型,Animal dog 引用指向new Dog();子类对象当成父类对象,只能调用父类的成员,如果子类重写了父类的方法就根据这个引用指向调用子类重写的这个方法(这个方法就是覆盖override)。这个调用过程就称为“动态绑定”。
转型需要注意的问题:
向上转型时,父类指向子类引用对象会遗失除与父类对象共有的其他方法,也就是在转型过程中,子类的新有的方法都会遗失掉,在编译时,系统会提供找不到方法的错误。实例如下:
public class Animal {
public void eat(){
System.out.println("animal eatting...");
}
}
class Bird extends Animal{
public void eat(){
System.out.println("bird eatting...");
}
public void fly(){
System.out.println("bird flying...");
}
}
class Main{
public static void main(String[] args) {
Animal b=new Bird(); //向上转型
b.eat();
b.fly(); //此处提示在Animal中没有定义fly方法。
}
在向下转型过程中,分为两种情况:
情况一:如果父类引用的对象如果引用的是指向的子类对象,那么在向下转型的过程中是安全的。也就是编译是不会出错误的。
情况二:如果父类引用的对象是父类本身,那么在向下转型的过程中是不安全的,编译不会出错,但是运行时会出现java.lang.ClassCastException错误。它可以使用instanceof来避免出错此类错误。实例如下:
public class Girl {
public void smile(){
System.out.println("girl smile()...");
}
}
class MMGirl extends Girl{
@Override
public void smile() {
System.out.println("MMirl smile sounds sweet...");
}
public void c(){
System.out.println("MMirl c()...");
}
}
class main{
public static void main(String[] args) {
Girl g1=new MMGirl(); //向上转型
g1.smile();
MMGirl mmg=(MMGirl)g1; //向下转型,编译和运行皆不会出错
mmg.smile();
mmg.c();
Girl g2=new Girl();
//MMGirl mmg1=(MMGirl)g2; //不安全的向下转型,编译无错但会运行会出错
//mmg1.smile();
//mmg1.c();
if(g2 instanceof MMGirl){
MMGirl mmg1=(MMGirl)g2;
mmg1.smile();
mmg1.c();
}
}
总结:
1、父类引用可以指向子类对象,子类引用不能指向父类对象。
2、把子类对象直接赋给父类引用叫upcasting向上转型,向上转型不用强制转型。
如Father father = new Son();
3、把指向子类对象的父类引用赋给子类引用叫向下转型(downcasting),要强制转型。
如father就是一个指向子类对象的父类引用,把father赋给子类引用son 即Son son =(Son)father;
其中father前面的(Son)必须添加,进行强制转换。
4、upcasting 会丢失子类特有的方法,但是子类overriding 父类的方法,子类方法有效
5、向上转型的作用,减少重复代码,父类为参数,调有时用子类作为参数,就是利用了向上转型。这样使代码变得简洁。体现了JAVA的抽象编程思想。