多态概述
Java作为面向对象的语言,同样可以描述一个事物的多种形态。如Student类继承了Person类,
一个Student的对象便既是Student,又是Person。
Java中多态的代码体现在一个子类对象(实现类对象)既可以给这个子类(实现类对象)引用变量赋值,
又可以给这个子类(实现类对象)的父类(接口)变量赋值。
如Student类可以为Person类的子类。那么一个Student对象既可以赋值给一个Student类型的引用,
也可以赋值给一个Person类型的引用。
最终多态体现为父类引用变量可以指向子类对象。
多态的前提是必须有子父类关系或者类实现接口关系,否则无法完成多态。
在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。
多态的前提条件:
1.必须存在继承关系 (extends)
2.必须存在方法重写
子类需要覆盖父类的功能
Animal
eat():"动物都需要吃饭..."
Cat
eat() "猫吃鱼"
Dog
eat() "狗吃骨头"
3.必须有父类引用指向子类对象
class Fu{}
class Zi extends Fu{
//存在重写
}
格式: Fu fu = new Zi()
//动物类
class Animal{
int age = 10 ;
public void eat(){
System.out.println("动物饿了就需要吃饭...");
}
public Animal(){
System.out.println("Animal的无参构造方法");
}
//父类的静态show
public static void show(){
System.out.println("show animal...");
}
}
//动物类
class Animal{
int age = 10 ;
public void eat(){
System.out.println("动物饿了就需要吃饭...");
}
public Animal(){
System.out.println("Animal的无参构造方法");
}
//父类的静态show
public static void show(){
System.out.println("show animal...");
}
}
/测试类
public class DuoTaiDemo {
public static void main(String[] args) {
//使用多态来进行测试
//父类引用指向子类对象
// 格式: Fu fu = new Zi() ;
Animal a = new Cat() ;
System.out.println(a.age);
a.eat();
// a.show() ;//静态方法当然推荐这种访问
// Animal.show();
//Cat.show();
}
}
多态的好处:
-
1)提高代码的复用性:由继承保证
-
2)提高了代码的扩展性:由多态保证 (重点) Fu fu = new Zi() ; 父类引用可以指向子类对象
多态成员的访问特点:
-
Fu f = new Zi() ; 成员变量:编译看左(看Fu类是否存在变量,存在,编译不会报错!) 运行看左(使用Fu类的东西)
-
成员方法:(一般没有明确是静态方法的都是----->非静态) 编译看左(看Fu类是否存在这个方法,存在,编译不会报错!) 运行看右(存在方法重写,所以最终子类的功能将父类的该功能进行覆盖!)
-
静态的方法: 编译看左看Fu类是否存在这个静态方法,存在,编译不会报错!), 运行看左(静态方法:子类出现了父类一模一样的静态方法,算不上重写,跟类相关的---->类成员) 静态功能推荐的方式:类名.访问
-
构造方法: 即使多态的情况进行测试,多态的前提条件---->继承关系 当前执行子类的构造方法之前,需要让父类的先进行初始化,然后子类进行初始化(分层初始化!)
class Fu{
public Fu() {
System.out.println("class Fu(){}");
}
//父类的成员变量
int num = 100 ;
public void show(){
System.out.println("show Fu...");
}
public static void method(){
System.out.println("method Fu...");
}
}
class Zi extends Fu{
public Zi() {
System.out.println("class Zi(){}");
}
//子类的成员变量
int num = 200 ;
@Override
public void show() {
System.out.println("show Zi...");
}
public static void method(){
System.out.println("method Zi...");
}
}
//测试类
public class DuoTaiDemo {
public static void main(String[] args) {
//使用多态的格式:Fu f = new Zi() ;
Fu f = new Zi() ;
// Zi z = new Zi( ); //之前的写法 z.num:就近原则
System.out.println(f.num);
System.out.println("-------------------------");
f.show() ;
System.out.println("--------------------------");
f.method() ;
Fu.method();
Zi.method();
}
}
运行结果:
100
-------------------------
show Zi...
--------------------------
method Fu...
method Fu...
method Zi...
多态的弊端:
-
不能访问子类的特有功能 (Fu f = new Zi()) f.方法名() ;报错了. 父类中没有子类特有功能!
-
如何解决多态的弊端? 方案1: (不推荐) 具体的子类创建具体的子类对象 Zi z = new Zi() ; z.成员方法名() ; 本身Fu f = new Zi() ;已经在堆内存中开辟空间了 Zi z = new Zi() ;在堆内存中又开辟空间,从内存角度考虑,这种比较消耗内存空间,不太好! 方案2:(推荐使用:"向下转型") 多态的第三个前提条件:父类 引用指向子类对象 :"向上转型 "Fu f = new Zi() ; 能不能将父类的引用转换成子类的引用? 好处:不需要在堆内存开辟空间 可以------>"向下转型" Zi z = (Zi)f ; 还原成子类型 强转类型转换: 目标类型 变量名 =(目标类型)初始化值; 基本类型 : int num = 65 ; //num--->char类型 char ch = (char)num ; ====>'A'
父类
//父类
class Father2{
public void show(){
System.out.println("show father...");
}
}
子类
//子类
class Son2 extends Father2{
public void show(){
System.out.println("show son...");
}
//特有功能:
public void playGame(String gameName){
System.out.println("会玩"+gameName+"游戏");
}
}
测试类
//测试类
public class DuoTaiDemo4 {
public static void main(String[] args) {
//父类指向子类对象
Father2 father2 = new Son2() ;
father2.show(); //编译看左,运行看右,存在重写
//father2.playGame( "lol");//父类没有方法
System.out.println("------------------------------");
//方案1:创建具体的子类对象
Son2 son2 = new Son2() ;
son2.playGame("lol");
System.out.println("------------------------------");
/**
* "向下转型"
* Zi z = (Zi)f ; 还原成子类型
*/
Son2 s = (Son2) father2;
s.playGame("csgo");
}
}