多态的含义顾名思义,一种事物的多种表现形态。
多态的定义格式:就是父类的引用变量指向子类对象 父类类型 变量名 = new 子类类型(); 变量名.方法名();
A:普通类多态定义的格式
父类 变量名 = new 子类();
如:
class Fu {}
class Zi extends Fu {}
Fu f = new Zi();//类的多态使用
B:抽象类多态定义的格式
抽象类 变量名 = new 抽象类子类();
如:
abstract class Fu {
public abstract void method();
}
class Zi extends Fu {
public void method(){
System.out.println(“重写父类抽象方法”);
}
}
//类的多态使用
Fu fu= new Zi();
C:接口多态定义的格式
接口 变量名 = new 接口实现类();
如: interface Fu {
public abstract void method();
}
class Zi implements Fu {
public void method(){
System.out.println(“重写接口抽象方法”);
}
}
//接口的多态使用
Fu fu = new Zi();
实现多态的前提是:
- 1. 具有子父类的继承关系(或者是子类实现了父类的接口)
- 2. 子类重写了父类的方法
- 3. 父类引用指向子类对象(最重要的特点,具体的说就是创建一个子类对象,用父类接收)
(左边指的是父类,右边指的是子类)
-
父类调用子类共有的方法,调用的是子类的方法.(编译看左边,运行看右边)
-
父类调用子类共有的成员变量,调用的是父类的成员变量(编译看左边,运行也看左边)
-
父类调用子类共有的静态方法,调用的是父类的静态方法(编译看左边,运行也看左边. 使用变量调用静态方法,相当于用变量类型的类名调用方法)
编译都看的是左边,是因为右边创建的子类对象,只有在程序运行时创建的对象才生效.如果左边父类没有子类的特有的成员,在编译时都会出错
验证的代码如下:
父类:
public class Fu {
String s = "我是父类的成员变量";
public void speak() {
System.out.println("我是父类方法");
}
public static void method() {
System.out.println("我是父类的静态方法");
}
}
子类:
public class Zi extends Fu {
String s = "我是子类的成员变量";
//子类重写父类方法,加上重写的符号,保证重写成功
@Override
public void speak() {
System.out.println("我是子类方法");
}
public static void method() {
System.out.println("我是子类的静态方法");
}
}
测试类:
public class Test_01 {
public static void main(String[] args) {
Fu f = new Zi();// 多态的方式创建对象,父类引用指向子类对象
f.speak();// 调用成员方法
System.out.println(f.s);// 调用成员变量
f.method();// 调用静态方法
Fu.method();// 使用变量调用静态方法,相当于用变量类型的类名调用方法
}
}
运行的结果如下图:
运行结果表明,在成员方法方面,由于动态绑定,父类调用了子类方法. 成员变量和静态方法调用的都是父类的.
多态的优缺点:多态的优点体现在方法中,参数的传递上,如果将参数类型定义为父类,那么继承了该父类的所有子类,或者实现了该父类的所有子类,都可以往该方法中传递参数,极大的提高了代码的复用性.
多态的缺点是父类无法调用子类的特有方法,如果必须要调用,得向下转型,类似于基本数据类型的强制转换. 向下转型的风险是,可能会出现类型转换异常.
该异常出现的情况是:父类引用指向的子类对象,与向下转型的子类不是同一个子类.为了避免这种异常,可以使用instanceof 关键字, 用来判断父类到底指向的是个什么类型的子类对象. 举例代码:
定义一个Animal的抽象类,在抽象类中,写了一个抽象的eat()方法
public abstract class Animal {
public abstract void eat();
}
定义一个Cat类,继承了Anima类,重写了eat()方法 ,并且有其特有的抓老鼠的方法
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
public void catchMouse() {
System.out.println("猫抓老鼠");
}
}
定义了一个Dog类继承了动物类, 重写了eat()方法 ,并且有其特有的看家的方法
public class Dog extends Animal {
@Override
public void eat() {
System.out.println("狗啃骨头");
}
public void watchHome(){
System.out.println("狗看家");
}
}
建一个测试类,测试其功能:
public class Test_1{
public static void main(String[] args) {
//使用匿名对象的方式,将子类对象传进方法的参数中
method(new Cat());
method(new Dog());
}
//定义一个方法 ,其参数类型为父类Animal,多态的方式,其子类都可以传递进该方法中
public static void method(Animal a) {
a.eat();//调用子父类共有的成员方法,并且运行的是子类的方法
/*
* 要调用子类的特有的成员方法,就必须向下转型,转型之前,为了避免类型转换异常
* 用instanceof判断父类指向的是哪种类型的子类对象,匹配成功了再转型
*/
if (a instanceof Cat) {
Cat c1 = (Cat) a;//向下转型,
c1.catchMouse();//使用子类特有的方法
} else if (a instanceof Dog) {
Dog d2 = (Dog) a;
d2.watchHome();
}
}
}
运行结果:
结果表明了,通过多态的方式,父类成功的调用了子类的方法.并且通过向下转型的方式,成功调用了子类的特有的成员方法.
欢迎关注我的微信公众号,第一时间获取最新博文: