1.多态概述
多态是面向对象程序设计的三大支柱之一,其余两个是封装和继承
· 多态定义:同一个行为具有多个不同的表现形式或形态的能力
· 多态类型:多态分为编译时多态性和运行时多态性
· 前提条件:必须有子父类关系。
·多态体现为父类引用变量可以指向子类对象。
多态的定义与使用格式
定义格式:父类类型 变量名=new 子类类型();
例如:
Object o = new GeometricObject();
继承关系使一个子类能够继承父类的特征,并且附加一些新特征。子类是它的父类的特殊化,每个子类的实例都是其父类的实例,但是反过来不成立。例如:每个圆都是一个几何对象,但并非每个几何对象都是圆。因此,总可以将子类的实例传给需要父类型的参数。
使用父类对象的地方都可以使用子类的对象,这就是通常所说的多态。
举例:
public class PolymorphismDemo{
public static void main(String[] args){
displayObject(new Circle(1,"red",false));
displayObject(new Rectangle(1,1,"black",true));
}
public static void displayObject(GeometricObject object){
System.out.println("Created on " + object.getdateCreated() +
". Color is " + object.getColor());
}
}
上述代码中,方法 displayObject 具有 GeometriObject 类型的参数。可以通过传递任何一个GeometriObject类型的实例来调用 displayObject。
2.instanceof关键字
作用:判断某个对象是否属于某种数据类型 (返回对象为布尔类型)
用法:
x instanceof y
例如
Fu f1=new Zi();
Fu f2=new Son();
if(f1 instanceof Zi){
System.out.println("f1是Zi的类型");
}
else{
System.out.println("f1是Son的类型");
}
3.多态的转型
多态的转型分为向上转型和向下转型两种
向上转型:多态本身就是向上转型过的过程
使用格式:父类类型 变量名=new 子类类型();
适用场景:当不需要面对子类类型时,通过提高扩展性,或者使用父类的功能就能完成相应的操作。
向下转型:一个已经向上转型的子类对象可以使用强制类型转换的格式,将父类引用类型转为子类引用各类型
使用格式:子类类型 变量名=(子类类型) 父类类型的变量;
适用场景:当要使用子类特有功能时。
4.多态的实现
实现条件
实现多态有3个必要条件:继承、重写、向上转型
- 继承:多态中必须有存在继承关系的子类和父类
- 重写:子类对父类的某些方法进行重新定义,调用这些方法时就会调用子类的方法
- 向上转型:在多态中需要将子类的引用赋给父类对象,只有这样引用才能具备技能调用父类方法和子类方法
只有满足了上述三个条件,我们才能够在同一个继承结构中使用统一的逻辑实现代码处理不同的对象,从而达到执行不同的行为。
多态调用一般原则
:对于引用子类对象的父类引用对象,如果子类重写了父类的方法,则运行时父类引用对象会调用子类的方法;如果子类继承了父类的方法(未重写),则运行时父类引用对象会调用父类的方法。
实现形式
在Java中有两种形式可以实现多态:继承和接口。
基于继承实现的多态:
实例:摘自Java多态的介绍_newchitu的博客-CSDN博客_java多态
public class Wine {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Wine(){
}
public String drink(){
return "喝的是 " + getName();
}
/**
* 重写toString()
*/
public String toString(){
return null;
}
}
public class JNC extends Wine{
public JNC(){
setName("JNC");
}
/**
* 重写父类方法,实现多态
*/
public String drink(){
return "喝的是 " + getName();
}
/**
* 重写toString()
*/
public String toString(){
return "Wine : " + getName();
}
}
public class JGJ extends Wine{
public JGJ(){
setName("JGJ");
}
/**
* 重写父类方法,实现多态
*/
public String drink(){
return "喝的是 " + getName();
}
/**
* 重写toString()
*/
public String toString(){
return "Wine : " + getName();
}
}
public class Test {
public static void main(String[] args) {
//定义父类数组
Wine[] wines = new Wine[2];
//定义两个子类
JNC jnc = new JNC();
JGJ jgj = new JGJ();
//父类引用子类对象
wines[0] = jnc;
wines[1] = jgj;
for(int i = 0 ; i < 2 ; i++){
System.out.println(wines[i].toString() + "--" + wines[i].drink());
}
System.out.println("-------------------------------");
}
}
OUTPUT:
Wine : JNC--喝的是 JNC
Wine : JGJ--喝的是 JGJ
-------------------------------
在上面的代码中JNC、JGJ继承Wine,并且重写了drink()、toString()方法,程序运行结果是调用子类中方法,输出JNC、JGJ的名称,这就是多态的表现。不同的对象可以执行相同的行为,但是他们都需要通过自己的实现方式来执行,这就要得益于向上转型了。
基于接口实现的多态
实例:摘自深入理解java多态性_thinkGhoster的专栏-CSDN博客
public class A {
public String show(D obj) {
return ("A and D");
}
public String show(A obj) {
return ("A and A");
}
}
public class B extends A{
public String show(B obj){
return ("B and B");
}
public String show(A obj){
return ("B and A");
}
}
public class C extends B{
}
public class D extends B{
}
public class Test {
public static void main(String[] args) {
A a1 = new A();
A a2 = new B();
B b = new B();
C c = new C();
D d = new D();
System.out.println("1--" + a1.show(b));
System.out.println("2--" + a1.show(c));
System.out.println("3--" + a1.show(d));
System.out.println("4--" + a2.show(b));
System.out.println("5--" + a2.show(c));
System.out.println("6--" + a2.show(d));
System.out.println("7--" + b.show(b));
System.out.println("8--" + b.show(c));
System.out.println("9--" + b.show(d));
}
}
输出结果:
1--A and A
2--A and A
3--A and D
4--B and A
5--B and A
6--A and D
7--B and B
8--B and B
9--A and D
多态机制遵循的原则为:在满足多态的3个必要条件:继承、重写、向上转型后,对于被子类对象赋值的父类引用对象,如果子类重写了父类的方法,则运行时父类引用对象会调用子类的方法;如果子类继承了父类的方法(未重写),则运行时父类引用对象会调用父类的方法。但是父类引用对象依旧要根据继承链中方法调用的优先级来确认具体引用的方法,优先级为:this.show(O)、super.show(O)、this.show((super)O)、super.show((super)O)。