画了两张图来说明继承和多态
在创建子类对象的时候,先创建父类对象,再创建子类对象,子类对象拥有父类对象的非私有方法和属性,所以我在图中把父类对象画在了子类的里面
-
继承
我们可以把父类和子类的方法分为四类:- 子类独有的方法
- 子类重写的父类的方法
- 父类被重写的方法
- 父类没有被重写的方法
- 在这里我们将这四类方法和属性近似的看作整体
- 继承中,由于子类在父类后创建,当重写发生时,子类重写的方法名和参数与父类一模一样,可以看作子类重写的方法覆盖了父类的方法,所以当调用这个方法的时候,方法实际指向的是子类的方法,因此,调用的是子类的属性;父类被重写的方法没有被子类的对象引用(被子类重写的方法拦截了),所以不会被子类的对象调用.
- 当父类的方法没有被重写时,子类对象获得父类没有被重写的方法的引用,调用时,指向的是父类的方法,所以使用的是父类的属性
- 子类使用自己独有的发方法时,当然是使用自己的方法~
-
多态
在多态里面,实际上是将子类的对象传入了一个父类类型的变量中.怎么理解,先看一个式子
Son类继承于Father类
Father father = new Son();
初看时,我心中也有一句:迈迈批,这是啥!
我们拆开来看
Son son = new Son();
Father father = son;
实际上就是创建了一个子类的对象,然后赋值给了父类的变量father.
再看看多态,我们也是用的父类类型的变量接收的子类的对象.那么为什么要这么做呢?
这里我们看图
可以这样理解,父类类型的变量只会接收父类本身拥有的方法类型,在接收子类对象后,被重写的方法实际指向子类的方法,所以会调用子类的属性,所以在接收不同的子类对象时,调用相同的方法,会有不同的功能.
而子类独有的方法,父类类型的变量没有地方接收,所以不能访问.
class Father{
public void show(){
System.out.println("Fathershow!");
}
}
class Son_1 extends Father{
public void show(){
System.out.println("Son_1show!");
}
}
class Son_2 extends Father{
public void show(){
System.out.println("Son_2show!");
}
}
class GrandSon extends Son_1{
public void show(){
System.out.println("GrandSonshow!");
}
}
class Test{
//子类都继承于父类,子类的对象既是子类的类型又是父类的类型,这里使用父类的类型类接受对象
public void myshow(Father father){
//传入不同的对象调用方法,结果当然是不同的啦
father.show();
}
public static void main(String[] args){
//准备对象
Test test = new Test();
Father father = new Father();
Son_1 son_1 = new Son_1();
Son_2 son_2 = new Son_2();
GrandSon grandson = new GrandSon();
//使用test对象调用方法,传入我们想使用的对象
test.myshow(father);
test.myshow(son_1);
test.myshow(son_2);
test.myshow(grandson);
}
}
- 最后在来一个抄来的经典案例(来源)
class Father{ public void func1(){ func2(); } //这是父类中的func2()方法,因为下面的子类中重写(又称:覆写)了该方法 //所以在父类类型的引用中调用时,这个方法将不再有效 //取而代之的是将调用子类中重写的func2()方法 public void func2(){ System.out.println("AAA"); } } class Child extends Father{ //func1(int i)是对func1()方法的一个重载,主要不是重写! //由于在父类中没有定义这个方法,所以它不能被父类类型的引用调用 //所以在下面的main方法中child.func1(68)是不对的 public void func1(int i){ System.out.println("BBB"); } //func2()重写了父类Father中的func2()方法 //如果父类类型的引用中调用了func2()方法,那么必然是子类中重写的这个方法 public void func2(){ System.out.println("CCC"); } } class PolymorphismTest { public static void main(String[] args) { Father child = new Child(); child.func1();//打印结果将会是什么? //child.func1(68); } }
为什么结果是CCC呢?因为在赋值的过程中Father类型的child变量指向的是子类的对象
当调用fun1的时候使用的是子类的方法,然而子类并没有无参的fun1,所以使用的是重父类继承过来的fun1方法,父类的fun1方法调用的是父类的fun2方法,有人就会问既然是父类的fun2方法为是结果是CCC而不是AAA呢?
前面说过,用父类的变量接收子类的对象时,如果存在相同的方法,那么父类的这个方法'会被覆盖.那么现在父类的这个方法名指向的实际上是子类的方法实现
绕了一圈这里执行的居然还是子类的fun2,所以显示CCC.
总结:又一次体会到了赋值的威力,任何程序都是在各种各样的赋值操作中写出来的.
欢迎来到testingpai.com!
注册 关于