面向对象的三大特性:封装、继承、多态。从一定角度来看,封装和继承几乎都是为多态而准备的。这是我们最后一个概念,也是最重要的知识点
1.什么是多态?
一种事物的多种形态
举个例子
比方说按下 F1键这个动作,如果当前在 Flash 界面下弹出的就是 AS 3 的帮助文档;如果当前在 Word 下弹出的就是 Word 帮助;在Windows 下弹出的就是 Windows 帮助和支持。同一个事件发生在不同的对象上会产生不同的结果。
2.多态的规则
1.类与类要建立关系 建立继承关系
2.必须要有方法的重写
3.父类的引用(指针)要指向子类的空间
例如:
class Animal{
public void eat() {
System.out.println("动物吃饭");
}
}
class Cat extends Animal{
public void eat() {
System.out.println("猫吃鱼");
}
}
大家思考一下
3.多态时 如何访问 成员变量 和 成员方法?
我们来看一下代码
// 需求 人 姓名 年龄 会吃饭
// 老师 姓名 年龄 会教书
public class Test1 {
public static void main(String[] args) {
Person p = new Teather(); // 父类的引用指向子类的引用
p.xingWei();
System.out.println(p.age);
}
}
// 人类
class Person{
String name = "李四";
int age = 28;
public Person11(){
}
public Person(String name,int age){
this.name = name;
this.age = age;
}
public void xingWei(){
System.out.println("我会吃饭");
}
}
// 老师类 继承人类
class Teather extends Person{
String name = "张三";
int age = 20;
public Teather(){
}
public Teather(String name,int age){
super(name,age);
}
// 方法的重写
public void xingWei(){
System.out.println("我会教书");
}
}
结果
我会教书
28
从编译结果来看
编译需要看父类有没有成员变量 没有编译不会通过 运行 访问就是父类中的成员变量
多态时 父类访问成员变量时 编译 和 运行(看父类)
多态调用成员方法时
编译时 看父类中有没有这个方法 没有就报错
运行时 运行子类的方法
口诀:
编译看父类
运行看子类
我们之间学过 强转 看一下
int num = 12;
byte b = 6;
num = b; // 自动类型 转换
// 强制转换
int a = (int)b;
趁热打铁 再看个例子:
// 需求 好人 可以聊天 吃饭
// 小偷 说谎话 可以偷东西
public class Demo03 {
public static void main(String[] args) {
// 父类引用指向子类
Person person = new Lie(); // 小偷 向上转型
// 小偷调用自己的方法 说谎话
person.speak();
// person 能不能调用 打人方法
// 用一个 向下转型就行了
// 注意: 如果你要想下转型 之前必须有过 向上转型
Thief thief = (Thief)person;
thief.XingWei();
}
}
class Person{
public void speak() {
System.out.println("聊天");
}
public void XingWei() {
System.out.println("会吃饭");
}
}
class Thief extends Person{
public void speak() {
System.out.println("说谎话");
}
public void XingWei (){
System.out.println("可以偷东西");
}
}
4.多态的好处:
1.增强了代码的可维护性(建立在继承的基础上)
2.增强方法的可扩展性(核心)(体现在方法上)
5.多态的弊端:
不能直接调用子类的特殊(不是重写父类的)方法
解决方法: 可以向下转型
6.instanceof运算符:
java语言的多态机制导致了引用变量的声明类型和其实际引用对象的类型可能不一致,再结合虚方法调用规则可以得出结论:声明为同种类型的两个引用变量调用同一个方法时也可能会有不同的行为。这里就引入了instanceof运算符。
那么如果我声明了person p=new student();我想将p转为student的可不可以?当然可以,但是就得强制转换了(儿子想成为父亲直接来,父亲想成为儿子你就强来)。
通常在强制转换时加上instanceof来判断对象到底属于哪个类?
if(p instanceof student) {
student s=(student)p;
}