继承和多态

发布于 更新于

技术文章测试开发

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

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

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

  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.

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

来源:testingpai

继续阅读