提示:以下是本篇文章正文内容,下面案例可供参考
1.概念:
在java的面向对象中,多态则是指同一个行为可以有多个不同表现形式的能力。也就是说,在父类中定义的属性和方法,在子类继承后,可以有不同的数据类型或表现出不同的行为。这可以使得同一个属性或方法
,在父类及其各个子类中,可能会有不同的表现或含义。
例如:龙生九子,每子行为和外貌上不相同。
2. 必要条件
我们要想实现多态,需要满足3个必要条件:
● 继承:多态发生在继承关系
中,必须存在有继承关系的父类和子类中,多态建立在封装和继承的基础之上;
● 重写:必须要有方法的重写
,子类对父类的某些方法重新定义;
● 向上转型:就是要将父类引用指向子类对象,只有这样该引用才既能调用父类的方法,又能调用子类的方法。
只有满足了以上3个条件才能实现多态,开发人员也才能在同一个继承结构中,使用统一的代码实现来处理不同的对象,从而执行不同的行为。
3. 实现方式
在Java中,多态的实现有如下几种方式:
● 方法重载
:重载可以根据实际参数的数据类型、个数和次序,在编译时确定执行重载方法中的哪一个。
● 方法重写
:这种方式是基于方法重写来实现的多态;
● 接口实现
:接口是一种无法被实例化但可以被实现的抽象类型,是对抽象方法的集合。定义一个接口可以有多个实现,这也是多态的一种实现形式,与继承中方法的重写类似。
一句话,如果我们在编译时就能确定要执行的方法属于哪个对象、执行的是哪个方法,这就是编译时多态,否则就是运行时多态!
代码如下(示例):
/**
* 定义一个“圆形”接口————————父类
*/
public interface Shape {
//绘制方法,接口中的方法一般没有实现,需要子类去实现
void draw();
}
分别定义其实现类——圆形
/**
* 实现Shape接口,并对接口中的方法进行实现——“圆形”类
*/
public class Circle implements Shape{
@Override
public void draw() {
System.out.println("绘制圆形");
}
//当父类引用指向子类对象时,父类只能调用执行那些在父类中声明,被子类覆盖的子类方法,不能执行子类独有的
public void scroll(){
System.out.println("圆形类独有的方法"); //子类独有的方法
}
}
分别定义其实现类——矩形
/**
* 实现Shape接口,并对接口中的方法进行实现————“矩形”类
*/
public class Traingle implements Shape{
@Override
public void draw() {
System.out.println("绘制矩形");
}
}
/**
* 实现Shape接口,并对接口中的方法进行实现————“三角形”类
*/
public class Square implements Shape{
@Override
public void draw() {
System.out.println("绘制三角形");
}
}
父子关系确定好之后,接下来我们再定义一个额外的测试类。在这个测试类中,我们创建出以上三个图形对象。注意,在=等号左侧,变量的类型都是Shape父类;=等号右侧,变量的值是具体的子类!
这种变量的定义过程,其实就是符合了多态的第三个必要条件,也就是所谓的”向上转型,父类引用指向子类对象“。
/**
- 注意,在=等号左侧,变量的类型都是Shape父类;=等号右侧,变量的值是具体的子类!
- 这种变量的定义过程,其实就是符合了多态的第三个必要条件,也就是所谓的”向上转型,父类引用指向子类对象“
*/
public class ShapeTest {
public static void main(String[] args) {
//多态测试
Shape shape01=new Circle();
shape01.draw();
Shape shape02=new Traingle();
shape02.draw();
Shape shape03=new Square();
shape03.draw();
}
}
3.多态——运行的结论:
Java实例方法的调用,是基于运行时实际类型的动态调用,而非声明的变量类型!通俗地说,就是我们调用的到底是哪个对象的方法,不是由=号左侧声明的引用变量来决定的,而是由=号右侧的实际对象类型来决定的!
/**
* 编译时多态——定义父类
*/
public class Father {
//父类中的成员变量
String name="老子";
public void eat(){
System.out.println("吃馒头");
}
//父类中的静态方法——静态方法不能重新被重写,只会被子类隐藏
public static void play(){
System.out.println("父亲玩球");
}
}
/**
* 编译时多态
*/
public class Son extends Father{
//当子类与父类的类型和名称相同时,父类的被隐藏
String name="儿子";
int age=12;
@Override
public void eat() {
//方法重写时,子类可以对父类的同名方法进行扩展,方法体的内容也可以跟父类的不一样
System.out.println("儿子吃肉");
}
public void drink(){
System.out.println("儿子喝水");
}
//子类中与父类同名的静态方法,这不是重写,而是子类对父类同名静态方法的隐藏
public static void play(){
System.out.println("儿子玩火");
}
public static void main(String[] args) {
//创建父类对象
// Father father=new Father();
// father.eat();
//创建子类对象
// Son son=new Son();
// son.eat();
//当前面引用与后面的实例类型不一致的时候,且子类和父类有共同属性的时候,父类会调用自己的先
Father son=new Son();
System.out.println("name="+son.name);
son.play();
}
}
根据上述代码的执行结果可知,当父类引用指向子类对象时,父类只能调用执行那些在父类中声明、被子类覆盖的子类方法,而不能执行子类独有的成员方法
。否则在编译阶段就会出现”The method drink() is undefined for the type Father“异常。
因篇幅问题不能全部显示,请点此查看更多更全内容
Copyright © 2019- how234.cn 版权所有 赣ICP备2023008801号-2
违法及侵权请联系:TEL:199 1889 7713 E-MAIL:2724546146@qq.com
本站由北京市万商天勤律师事务所王兴未律师提供法律服务