Day34--什么是多态

Day34--什么是多态

多态

多态是面向对象编程的三大特性之一

即同一方法可以根据发送对象的不同而采用多种不同的行为方式。

一个对象的实际类型是确定的,但可以指向对象的引用的类型有很多。

多态存在的条件:

​ 有继承关系、

​ 子类重写父类方法、

​ 父类引用指向子类对象。

注意:多态是方法的多态,属性没有多态性。

instanceof。

示例:

创建了下面3个文件,其中,Person是Student的父类

package com.liu.oop.demo06;

public class Person {
}

package com.liu.oop.demo06;

public class Student extends Person{
}

package com.liu.oop;
import com.liu.oop.demo06.Student;
import com.liu.oop.demo06.Person;

public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型不确定------父类的引用指向子类的类型
        Student s1 = new Student();

        Person s2 = new Student();

        Object s3 = new Student();

    }
}

我们可以看到,

//一个对象的实际类型是确定的
//new Student();
//new Person();

    //可以指向的引用类型不确定------父类的引用指向子类的类型
    Student s1 = new Student();

    Person s2 = new Student();
    
    
     Object s3 = new Student();

三种初始化,要掌握!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

这时,在Person类里创建了run方法

package com.liu.oop.demo06;

public class Person {
    public void run(){
        System.out.println("run");
    }
}

在Application里面,引用run方法

package com.liu.oop;
import com.liu.oop.demo06.Student;
import com.liu.oop.demo06.Person;

public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型不确定------父类的引用指向子类的类型
        Student s1 = new Student();

        Person s2 = new Student();

        Object s3 = new Student();



        s2.run();//run


    }
}

s2虽然是Student类型,但是子类继承了父类的方法

这个时候,对Student重写方法

package com.liu.oop.demo06;

public class Student extends Person{
    @Override
    public void run() {
        System.out.println("son");
    }
}

package com.liu.oop;
import com.liu.oop.demo06.Student;
import com.liu.oop.demo06.Person;

public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型不确定------父类的引用指向子类的类型
        Student s1 = new Student();

        Person s2 = new Student();

        Object s3 = new Student();

        s2.run();
        s1.run();


    }
}

那么,Application输出的结果是什么?

package com.liu.oop;
import com.liu.oop.demo06.Student;
import com.liu.oop.demo06.Person;

public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型不确定------父类的引用指向子类的类型
        Student s1 = new Student();

        Person s2 = new Student();

        Object s3 = new Student();

        s2.run();//son
        s1.run();//son


    }
}

这是怎么回事?父类的输出结果是run,子类的输出结果是son。这两个输出的结果都是son

对象能执行的方法,要看对象的引用类型

//Student 子类能调用的方法都是自己的或者继承父类的!

Student s1 = new Student();

//Person 父类型,可以指向子类,但是不能调用子类独有的方法 。如果子类重写了父类的方法,执行子类的方法

Person s2 = new Student();

再比如,在Student里面写方法eat

package com.liu.oop.demo06;

public class Student extends Person{
    @Override
    public void run() {
        System.out.println("son");
    }
    public void eat(){
        System.out.println("eat");
    }
}

在Application里面,用s2引用该方法,就不行了

package com.liu.oop;
import com.liu.oop.demo06.Student;
import com.liu.oop.demo06.Person;

public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型不确定------父类的引用指向子类的类型
        Student s1 = new Student();

        Person s2 = new Student();

        Object s3 = new Student();

        s2.run();//son
        s1.run();//son

        s2.eat();//报错


    }
}

image-20241120205129115

如果非要转换成功,则可以这样:

((Student)s2).eat();

强制转换,将s2的Person类型强制转换为Student类型

多态注意事项:
1.多态是方法的多态,属性没有多态。
2.父类和子类,有联系,类型转换异常!ClassCastException!
3.存在条件:继承关系,方法需要重写,父类引用指向子类对象!Father f1 = new Son();

不能被方法重写的情况:

1.static 方法,属于类,它不属于实例。
2.final 常量。
3.private 方法。

下面的情况,输出的结果分别是什么?

package com.liu.oop;
import com.liu.oop.demo06.Student;
import com.liu.oop.demo06.Person;

public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型不确定------父类的引用指向子类的类型
        Student s1 = new Student();

        Person s2 = new Student();

        Object s3 = new Student();
        Person s4 = new Person();

        s1.run();
        s2.run();
        s4.run();

    }
}

答案:

package com.liu.oop;
import com.liu.oop.demo06.Student;
import com.liu.oop.demo06.Person;

public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型不确定------父类的引用指向子类的类型
        Student s1 = new Student();

        Person s2 = new Student();

        Object s3 = new Student();
        Person s4 = new Person();

        s1.run();//son
        s2.run();//son
        s4.run();//run

    }
}

解释:

  1. s1.run();

    • s1Student类型的引用,指向一个Student对象。
    • 当调用s1.run();时,会直接调用Student类中重写的run方法,所以输出"son"
  2. s2.run();

    • s2Person类型的引用,但实际指向一个Student对象。
    • 由于 Java 的多态性,在运行时会根据实际对象的类型来决定调用哪个方法。虽然s2的声明类型是Person,但实际指向的是Student对象,而Student类重写了Person类的run方法,所以也会调用Student类中的run方法,输出"son"
  3. s4.run();

    • s4Person类型的引用,且指向一个新创建的Person对象。
    • 当调用s4.run();时,会调用Person类中定义的run方法,输出"run"

在 Java 中,多态是面向对象编程的三大特性之一,它允许不同类的对象对同一消息作出不同的响应。具体来说:

一、概念定义

多态,即“同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果”。在 Java 中主要表现为方法的多态,属性没有多态性。

二、实现条件

  1. 继承关系:多态通常基于类的继承关系。存在一个父类和一个或多个子类,子类继承父类的属性和方法。

    • 例如:
    public class Person {
        // 父类的方法
        public void sayHello() {
            System.out.println("Hello, I am a person.");
        }
    }
    
    public class Student extends Person {
        // 子类重写父类方法
        @Override
        public void sayHello() {
            System.out.println("Hello, I am a student.");
        }
    }
    
  2. 子类重写父类方法:子类可以对父类中的方法进行重写,以实现不同的行为。

    • 在上面的例子中,Student 类重写了 Person 类的 sayHello 方法。
  3. 父类引用指向子类对象:使用父类的引用变量来引用子类的对象。

    • 例如:Person person = new Student();,这里创建了一个 Student 对象,但用 Person 类型的引用 person 来指向它。

三、多态的作用

  1. 提高代码的可扩展性和可维护性:当需要增加新的子类时,只需要在子类中实现相应的方法,而不需要修改现有的代码。例如,如果有一个新的子类 Teacher 继承自 Person,并且重写了 sayHello 方法,那么可以直接使用 Person 类型的引用指向 Teacher 对象,而不需要修改调用 sayHello 方法的其他代码。
  2. 增强代码的灵活性:可以根据实际情况动态地决定调用哪个具体的方法。例如,在一个方法中接收一个 Person 类型的参数,可以传入 Person 的任何子类对象,根据实际传入的对象类型,在运行时会自动调用相应子类的重写方法。

四、多态的表现形式

  1. 方法重写实现多态:如前面的例子所示,子类通过重写父类的方法来实现多态。在运行时,根据对象的实际类型来决定调用哪个方法。
  2. 方法重载也可视为一种多态形式:方法重载是在同一个类中,有多个方法具有相同的名称,但参数列表不同。虽然这不是严格意义上基于继承关系的多态,但它也体现了根据不同的参数调用不同的方法,从而产生不同的行为这一多态的特点。

总之,多态是 Java 中非常重要的特性,它使得代码更加灵活、可扩展和易于维护。

小插曲:

为什么下面的代码,没有问题但是报错了?

package com.liu.oop.demo06;

public class Person {
}
package com.liu.oop.demo06;

public class Student extends Person{
}

package com.liu.oop;

import com.liu.oop.demo05.A;
import com.liu.oop.demo05.B;
import com.liu.oop.demo05.Student;
import com.liu.oop.demo06.Person;

public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型不确定------父类的引用指向子类的类型
        Student s1 = new Student();

        Person s2 = new Student();//-------------------------------为什么报错了?

    }
}

后经过检查发现,导入的包错误,正确的应该是:

package com.liu.oop;
import com.liu.oop.demo06.Student;
import com.liu.oop.demo06.Person;

public class Application {
    public static void main(String[] args) {

        //一个对象的实际类型是确定的
        //new Student();
        //new Person();

        //可以指向的引用类型不确定------父类的引用指向子类的类型
        Student s1 = new Student();

        Person s2 = new Student();

    }
}

posted @ 2024-11-20 21:08  1hahahahahahahaha  阅读(1)  评论(0编辑  收藏  举报