Java面向对象六之多态
学习笔记,仅供参考
本文重点:多态 | 匿名内部类
🎈 多态
经过一段时间的学习,终于到了面向对象的最后一个特性 – 多态 指代不同数据类型的实体提供统一的接口,或者用一个单一的符号来表示多个不同的类型。说白了多态就是具有多种形态,在不同的场合表现出的形态不同,从而做出相应的动作。比如:电脑在学习时是学习的工具,在娱乐时又是电视机或者游戏机,在通讯交流时又是聊天通讯的工具。
本节以花木兰替父从军的例子来展现多态在 Java 中的使用情形。
我们都知道花木兰替父从军的故事,在故事中花木兰扮演着两种身份,分别是打仗时的将士形象和归来时的女儿形象。将士形象指的就是她爹花胡,女儿形象就是花木兰自己,所以先创建两个类来表示花胡和花木兰。
/**
* 姓名:花胡
* 年龄:45
* 行为:自我介绍、打仗
*/
public class HuaHu {
public String name = "花胡" ;
public int age = 45;
public static void sayMe() {
System.out.println("大家好!我叫花胡,今年45岁");
}
public void fight() {
System.out.println("打仗...");
}
}
/***************分割线*********************/
/**
* 姓名:花木兰
* 年龄:19
* 行为:自我介绍、化妆
* 因为要替父从军,所以要继承花胡
*/
public class HuaMuLan extends HuaHu {
public String name = "花木兰";
public int age = 19;
public static void sayMe() {
System.out.println("大家好!我叫花木兰,今年19岁");
}
public void dressing() {
System.out.println("梳妆打扮...");
}
}
接着在测试类中模拟这两种情形:
public class Test {
public static void main(String args[]) {
// 替父从军,向上转型,父类 new 子类
// 此时的实例对象可以使用父类的属性和子类未重写的方法
HuaHu huaHu = new HuaMuLan();
System.out.println(huaHu.name);
System.out.println(huaHu.age);
HuaHu.sayMe();
HuaHu.fight();
// 输出如下:
// 花胡 | 45 | 大家好!我家花木兰今年19岁 | 打仗!
// 因为在 HuaMuLan 类中重写了 sayMe(); 方法,所以这里是花木兰的自我介绍。
// 要想用花胡的自我介绍,就要删除 HuaMuLan 类的sayMe(); 方法
/**********************分割线********************/
//胜利归来,重返女儿身,向下转型, 父类对象强制转换为子类对象
HuaMuLan huaMuLan = (HuaMuLan) huaHu;
System.out.println(huaMuLan.name);
System.out.println(huaMuLan.age);
huaMuLan.sayMe();
huaMuLan.dressing();
// 输出如下:
// 花木兰 | 19 大家好!我家花木兰今年19岁 | 梳妆打扮...
}
}
经过验证,向上转型的变量既是父类的实例也是子类的实例,如下图所示。之所以如此,我认为是多态对象既可以使用父类中的属性和未被子类重写的方法,如上例中的 huaHu.name; huaHu.age; huaHu.fight();
也可以使用子类中重写的方法, 如 huaHu.sayMe();
就像儿子冒充老子一样,但有一定的风险,那就是不能重写父类的方法,不然就会暴露身份。
🚀 匿名内部类
所谓的匿名内部类中的 匿名
指没有名字,内部类
指在类的内部还有类。正因为没有名字,所以匿名内部类只能使用一次,通常用来简化代码编写。但是前提条件是:必须继承一个父类或者实现一个接口
接下来就对比一下匿名内部类和常规的子类继承父类并实例化:
/**
* 先创建一个接口(父类)
* 记住:接口的方法没有意义(内容)
*/
public interface Human {
public void eat();
public void sleep();
}
/*****************分割线************************/
/**
* 常规的形式是再创建一个实现类(子类)
* 实现类要重写接口的所有方法
*/
public class Chinese implements Human {
@Override
public void eat() {
System.out.println("eating...");
}
@Override
public void sleep() {
System.out.println("sleeping");
}
}
/*********************分割线**********************/
/**
* 测试两者的不同
*/
public class Test {
public static void main(String args[]) {
// 常规方法
Chinese chinese = new Chinese();
chinese.eat();
chinese.sleep();
// 匿名内部类
Human chinese1 = new Human() {
@Override
public void eat() {
System.out.println("eating...");
}
@Override
public void sleep() {
System.out.println("sleeping");
}
}
chinese1.eat();
chinese1.sleep()
}
}
从上面的代码可以知道,匿名内部类就相当于把子类的重写和对象的实例化两步并作一步,从而省去了中间创建子类的过程。