zoukankan      html  css  js  c++  java
  • 多态

    1.多态概述

    1. 多态是继封装、继承之后,面向对象的第三大特性。
    2. 多态*现实意义*理解:
    • 现实事物经常会体现出多种形态,如学生,学生是人的一种,则一个具体的同学张三既是学生也是,即出现两种形态

    • Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,一个Student的对象便既是Student,又是Person。

    • 3.多态体现为父类引用变量可以指向子类对象

      4.前提条件:必须有子父类关系。

      *注意:在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。*

      5.多态的定义与使用格式

    ​ 定义格式:父类类型 变量名=new 子类类型();

    2.多态中成员的特点

    1. 多态成员变量:编译运行看左边

    ​ Fu f=new Zi();

    ​ System.out.println(f.num);//f是Fu中的值,只能取到父中的值

    2.多态成员方法:编译看左边,运行看右边

    ​ Fu f1=new Zi();

    ​ System.out.println(f1.show());//f1的门面类型是Fu,但实际类型是Zi,所以调用的是重写后的方法。

    public class Person {
        public void run(){
            System.out.println("run");
        }
    
        public void eat() {
            System.out.println("eat");
        }
    }
    
    public class Student extends Person{
        public void run(){
            System.out.println("son");
        }
    
        public void eat(){
            System.out.println("eat");
        }
    }
    
    public class Application {
        public static void main(String[] args) {
    
            //一个对象的实际类型是确定的
            //new Student();
            //new Person();
    
            //可以指向的引用类型就不确定了:父类的引用指向子类
    
            //Student能调用的方法都是自己或者继承父类的
            Student s1 = new Student();
            //可以指向子类,但是不能调用子类独有的方法
            Person s2 = new Student();//Student也是Person
            Object s3 = new Student();
    
            s2.run();//子类重写了父类的方法,执行子类的方fa
            s1.run();
    
            //对象能执行哪些方法,主要看对象左边的类型,和右边关系不大
            s2.eat();
            s1.eat();
        }
    }
    /*
    输出结果
    son
    son
    eat
    eat
    */
    

    注意事项:

    1. 多态是方法的多态,没有属性的多态:父可以吃,你也可以吃。但你和父的名字不一样
    2. 父类和子类有联系 类型转换异常!ClassCastException
    3. 存在的条件:继承关系,方法需要重写,父类引用指向子类对象!

    static 方法:属于类,它不属于实例

    final常量:无法重写

    private方法:

    3.多态性

    java引用类型有两个

      编译时类型

      编译时类型由声明该变量时使用的类型决定

      运行时类型

      运行时类型由实际赋给该变量的对象决定

    例:

     1 class Animal{
     2     public int month = 2;
     3     public void eat(){
     4         System.out.println("动物吃东西");
     5     }
     6     
     7 }
     8 
     9 class Dog extends Animal{
    10     public int month = 3;
    11     
    12     public void eat() {
    13         System.out.println("小狗吃肉");
    14     }
    15     
    16     public void sleep() {
    17         System.out.println("小狗睡午觉");
    18     }
    19 }
    20 
    21 class Cat extends Animal{
    22     public int month = 4;
    23     
    24     public void eat() {
    25         System.out.println("小猫吃鱼");
    26     }
    27 }
    28 
    29 public class Test {
    30     public static void main(String[] args){
    31         Animal a = new Dog();
    32         Animal b = new Cat();
    33         a.eat();
    34         System.out.println(a.month);
    35         //下面代码编译时会出错
    36 //        a.sleep();
    37         b.eat();
    38         System.out.println(b.month);
    39         
    40     }
    41 }
    

    a对象编译时类型是Animal,运行时类型是Dog;

    b对象编译时类型是Animal,运行时类型是Cat。

    当运行时调用引用变量的方法时,其方法行为总是表现出子类方法的行为特征,而不是父类方法的行为特征,这就表现出:相同类型的变量调用同一个方法时表现出不同的行为特征,这就是多态。

    该例中:当他们调用eat方法时,实际调用的是父类Animal中被覆盖的eat方法。

    运行结果:

    小狗吃肉
    2
    小猫吃鱼
    2
    

    上例中main方法中注释了a.sleep(),由于a的编译时类型为Animal,而Animal类中没有sleep方法,因此无法在编译时调用sleep方法。

    对象的实例变量不具备多态性

    上例中a,b对象分别调用了month,可以看到,其输出结果都是2

    总的来说:

    引用变量在编译阶段只能调用编译时类型所具有的方法,但运行时则执行他运行时类型所具有的方法。

    4.多态的转型

    • 多态的转型分为向上转型和向下转型两种
    • 向上转型:多态本身就是向上转型过的过程

    ​ 使用格式:父类类型 变量名=new 子类类型();

    ​ 适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。

    • 向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用类型转为子类引用各类型

    ​ 使用格式:子类类型 变量名=(子类类型) 父类类型的变量;

    ​ 适用场景:当要使用子类特有功能时。

    java中向上转型的意义

    首先了解多态

    • 使用父类类型的引用指向子类的对象;
    • 该引用只能调用父类中定义的非private方法和变量;
    • 如果子类中重写了父类中的一个方法,那么调用这个方法的时候,将会调用子类中的方法(动态绑定);
    • 变量不可以被重写,重写只针对方法,不重写变量;
    • 重写就是相同的方法,得到的结果和表现的形式不同;
    //父类
    
    public class Father{
    
    	//父类有一个打孩子方法
    
    	public void hitChild(){
    
    	}
    }
    
    //子类1
    
    public class Son1 extends Father{
    
    	//重写父类打孩子方法
    
    	public void hitChild(){
    
    		System.out.println("为什么打我?我做错什么了!");
    
    	}
    
    }
    
    
    //子类2
    
    public class Son2 extends Father{
    
    	//重写父类打孩子方法
    
    	public void hitChild(){
    
    		System.out.println("我知道错了,别打了!");
    
    	}
    
    }
    
    
    //子类3
    
    public class Son3 extends Father{
    
    	//重写父类打孩子方法
    
    	public void hitChild(){
    
    		System.out.println("我跑,你打不着!");
    
    	}
    
    }
    
    
    //测试类
    
    public class Test{
    
    	public static void main(String args[]){
    
    		Father father;
    
    		father = new Son1();
    
    		father.hitChild();
    
    		father = new Son2();
    
    		father.hitChild();
    
    		father = new Son3();
    
    		father.hitChild();
    
    
    	}
    
    
    
    }
    

    如果是Son1 a = new Son1();如果要改为son2那就很麻烦了,而father = new Son1();只需要改动一处。但是后面做大程序的时候,往往好几十个方法,如果你不用father,而用了son,那你一旦在写程序的时候发现这里应该用son2而不是son1,而你又没用father,那你这里一改就要改N多的地方,而且一改动很有可能会引发其他的错误,而且你这些方法很有可能又被其他的类所调用,那其他的类肯定也要跟着改啊,那这个改动量就非常大了。

    向上转型的意义:程序开始的时候确定有一个father型对象,但是要根据用户的选择来决定他要被实例化成哪种类型的。但如果你要分开来声明的话,那你就因为不确定性必须要声明两个变量,分别来等待实例化。就是实例化的时候可以根据不同的需求实例化不同的对象,这也就是多态的意义。

    5.多态案例:

    例1:

    package day0524;
    
    public class demo04 {
    
        public static void main(String[] args) {
    
    
            People p=new Stu();
    
            p.eat();
    
            //调用特有的方法
    
            Stu s=(Stu)p;
    
            s.study();
    
            //((Stu) p).study();
    
        }
    
    }
    
    class People{
    
        public void eat(){
    
            System.out.println("吃饭");
    
        }
    
    }
    
    class Stu extends People{
    
        @Override
    
        public void eat(){
    
            System.out.println("吃水煮肉片");
    
        }
    
        public void study(){
    
            System.out.println("好好学习");
    
        }
    
    }
    
    class Teachers extends People{
    
        @Override
    
        public void eat(){
    
            System.out.println("吃樱桃");
    
        }
    
        public void teach(){
    
            System.out.println("认真授课");
    
        }
    
    }
    

    例2:

    请问题目运行结果是什么?

    package day0524;
    
    
    public class demo1 {
    
    
        public static void main(String[] args) {
    
    
            A a=new A();
    
    
            a.show();
    
    
            B b=new B();
    
    
            b.show();
    
    
        }
    
    
    }
    
    
    class A{
    
    
        public void show(){
    
    
            show2();
    
    
        }
    
        public void show2(){
    
    
            System.out.println("A");
    
    
        }
    
    
    }
    
    
    class B extends A{
    
    
        public void show2(){
    
            System.out.println("B");
    
        }
    
    }
    
    class C extends B{
    
        public void show(){
    
           super.show();
    
        }
    
        public void show2(){
    
            System.out.println("C");
    
    
        }
    
    
    }
    

    答案:A B

  • 相关阅读:
    机器学习(04)——常用专业术语
    C# 线程同步的三类情景
    线程同步的情景之三
    线程同步的情景之二
    线程同步的情景之一
    Thread.Sleep(0) vs Sleep(1) vs Yeild
    Visual Studio 实用扩展推荐
    为革命保护视力 --- 给 Visual Studio 换颜色
    免费的精品: Productivity Power Tools 动画演示
    如何扩展 Visual Studio 编辑器
  • 原文地址:https://www.cnblogs.com/FettersLove/p/13741531.html
Copyright © 2011-2022 走看看