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();//报错
}
}
如果非要转换成功,则可以这样:
((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
}
}
解释:
-
s1.run();
:s1
是Student
类型的引用,指向一个Student
对象。- 当调用
s1.run();
时,会直接调用Student
类中重写的run
方法,所以输出"son"
。
-
s2.run();
:s2
是Person
类型的引用,但实际指向一个Student
对象。- 由于 Java 的多态性,在运行时会根据实际对象的类型来决定调用哪个方法。虽然
s2
的声明类型是Person
,但实际指向的是Student
对象,而Student
类重写了Person
类的run
方法,所以也会调用Student
类中的run
方法,输出"son"
。
-
s4.run();
:s4
是Person
类型的引用,且指向一个新创建的Person
对象。- 当调用
s4.run();
时,会调用Person
类中定义的run
方法,输出"run"
。
在 Java 中,多态是面向对象编程的三大特性之一,它允许不同类的对象对同一消息作出不同的响应。具体来说:
一、概念定义
多态,即“同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果”。在 Java 中主要表现为方法的多态,属性没有多态性。
二、实现条件
-
继承关系:多态通常基于类的继承关系。存在一个父类和一个或多个子类,子类继承父类的属性和方法。
- 例如:
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."); } }
-
子类重写父类方法:子类可以对父类中的方法进行重写,以实现不同的行为。
- 在上面的例子中,
Student
类重写了Person
类的sayHello
方法。
- 在上面的例子中,
-
父类引用指向子类对象:使用父类的引用变量来引用子类的对象。
- 例如:
Person person = new Student();
,这里创建了一个Student
对象,但用Person
类型的引用person
来指向它。
- 例如:
三、多态的作用
- 提高代码的可扩展性和可维护性:当需要增加新的子类时,只需要在子类中实现相应的方法,而不需要修改现有的代码。例如,如果有一个新的子类
Teacher
继承自Person
,并且重写了sayHello
方法,那么可以直接使用Person
类型的引用指向Teacher
对象,而不需要修改调用sayHello
方法的其他代码。 - 增强代码的灵活性:可以根据实际情况动态地决定调用哪个具体的方法。例如,在一个方法中接收一个
Person
类型的参数,可以传入Person
的任何子类对象,根据实际传入的对象类型,在运行时会自动调用相应子类的重写方法。
四、多态的表现形式
- 方法重写实现多态:如前面的例子所示,子类通过重写父类的方法来实现多态。在运行时,根据对象的实际类型来决定调用哪个方法。
- 方法重载也可视为一种多态形式:方法重载是在同一个类中,有多个方法具有相同的名称,但参数列表不同。虽然这不是严格意义上基于继承关系的多态,但它也体现了根据不同的参数调用不同的方法,从而产生不同的行为这一多态的特点。
总之,多态是 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();
}
}