接口的多种不同的实现方式即为多态
。换句话,允许将子类类型的指针赋值给父类类型的指针,把不同的子类对象都当作父类来看。运行期间才确定具体调用的对象。
-
多态的条件
1、有继承或者实现关系。
2、子类重写(实现)父类(父接口)的方法。
3、有父类或者父接口引用指向子类对象。 -
多态的分类
1、具体类多态
class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
2、抽象类多态
abstract class Fu {}
class Zi extends Fu {}
Fu f = new Zi();
3、接口多态
interface Fu {}
class Zi implements Fu {}
Fu f = new Zi();
- 多态中的成员访问
1、成员变量:编译看左边,运行看左边。
2、构造方法:创建子类对象的时候,访问父类的构造方法,对父类的数据进行初始化。
3、成员方法:编译看左边,运行看右边。
4、静态方法:编译看左边,运行看左边。
父类的静态方法不能被重写,虽然被static修饰的父类方法,子类也可以取相同的方法名、相同的修饰符、相同的返回值类型,但实际上已经不是同一个方法了。
class Fu {
public int num = 100;
public void show() {
System.out.println("show Fu");
}
public static void function() {
System.out.println("static function Fu");
}
}
class Zi extends Fu {
public int num = 1000;
public int num2 = 200;
public void show() {
System.out.println("show Zi");
}
public void method() {
System.out.println("method zi");
}
public static void function() {
System.out.println("static function Zi");
}
}
class DuoTaiDemo {
public static void main(String[] args) {
Fu f = new Zi();
System.out.println(f.num);
//找不到符号
//System.out.println(f.num2);
f.show();
//找不到符号
//f.method();
f.function();
//强制转换
Zi z = (Zi) f;
System.out.println(z.num2);
z.method();
z.function();
}
}
输出:
100
show Zi
static function Fu
200
method zi
static function Zi
35、39行父类引用访问不到子类的成员变量、成员方法。
37行父类引用调用是子类的方法(多态)。
40行父类引用调用是父类的静态方法。
-
多态的优点
1、提高代码的维护性(继承体现)
2、提高代码的扩展性(多态体现) -
多态的缺点
1、父类不能使用子类的特有功能。比如上面代码,访问不到类Zi的成员变量num2、成员方法method()。
如果想使用子类的特有功能,怎么办? 把父类的引用强制转换为子类的引用。
//强制转换
Zi z = (Zi) f;
System.out.println(z.num2);
z.method();
z.function();
43-46行,将把父类的引用 f 强制转换为子类的引用 z,然后子类引用 z 就可以调用特有成员变量、方法。
但是注意:要求该 f 必须是能够转换为 Zi,不然报错ClassCastException:类型转换异常。比如,类 Dog、Cat 均继承类 Animal,Animal a = new Cat(); Cat c = (Cat)a;
没有问题,但是Dog dd = (Dog)a;
就会报错 ClassCastException,因为引用 a 内存中是类 Cat。
- 多态中的转型
1、向上转型
:从子到父。(多态 Fu f = new Zi(); )
2、向下转型
:从父到子。(强制转换 Zi z = (Zi)f; )
思考题
class A {
public void show() {
show2();
}
public void show2() {
System.out.println("我");
}
}
class B extends A {
//默认继承类A 的show方法
/*
public void show() {
show2();
}
*/
public void show2() {
System.out.println("爱");
}
}
class C extends B {
public void show2() {
System.out.println("你");
}
}
public class DuoTaiTest4 {
public static void main(String[] args) {
A a = new B();
a.show();
B b = new C();
b.show();
}
}
结果:
爱
你
继承的时候:
子类中有和父类中一样的方法,叫重写
。
子类中没有父亲中出现过的方法,方法默认被继承过来了。
所以,类 B 默认继承类 A 的show()
方法,执行a.show()
,因为多态,会执行类 B 的show()
方法,进而执行 B 的show2()
方法,打印输出 “爱”。
类 C 重新类 B 的show()
方法,执行父类的show()
方法,进而执行父类 B 的show2()
方法,因为多态,会执行类 C 的show2()
方法,打印输出“你”。