继承和多态

画了两张图来说明继承和多态

在创建子类对象的时候,先创建父类对象,再创建子类对象,子类对象拥有父类对象的非私有方法和属性,所以我在图中把父类对象画在了子类的里面

  1. 继承

    继承.png
    我们可以把父类和子类的方法分为四类:

    • 子类独有的方法
    • 子类重写的父类的方法
    • 父类被重写的方法
    • 父类没有被重写的方法
    1. 在这里我们将这四类方法和属性近似的看作整体
    2. 继承中,由于子类在父类后创建,当重写发生时,子类重写的方法名和参数与父类一模一样,可以看作子类重写的方法覆盖了父类的方法,所以当调用这个方法的时候,方法实际指向的是子类的方法,因此,调用的是子类的属性;父类被重写的方法没有被子类的对象引用(被子类重写的方法拦截了),所以不会被子类的对象调用。
    3. 当父类的方法没有被重写时,子类对象获得父类没有被重写的方法的引用,调用时,指向的是父类的方法,所以使用的是父类的属性
    4. 子类使用自己独有的发方法时,当然是使用自己的方法~
  2. 多态

在多态里面,实际上是将子类的对象传入了一个父类类型的变量中。怎么理解,先看一个式子

Son 类继承于 Father 类

Father father = new Son();

初看时,我心中也有一句:迈迈批,这是啥!

我们拆开来看

Son son = new Son();
Father father = son;

实际上就是创建了一个子类的对象,然后赋值给了父类的变量 father.

再看看多态,我们也是用的父类类型的变量接收的子类的对象。那么为什么要这么做呢?

这里我们看图多态.png

可以这样理解,父类类型的变量只会接收父类本身拥有的方法类型,在接收子类对象后,被重写的方法实际指向子类的方法,所以会调用子类的属性,所以在接收不同的子类对象时,调用相同的方法,会有不同的功能。

而子类独有的方法,父类类型的变量没有地方接收,所以不能访问。

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);
	}
}

  1. 最后在来一个抄来的经典案例(来源)
    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.

总结:又一次体会到了赋值的威力,任何程序都是在各种各样的赋值操作中写出来的。

  • Java
    15 引用 • 169 回帖 • 3 关注
回帖
请输入回帖内容 ...