面向对象的特征之一:多态性
面向对象的三大特征:继承性、封装性、多态性。
继承性
多态的形式和体现
-
多态性的理解:一个事物的多种形态。
-
多态性的体现
-
格式:(父类类型:指子类继承的父类类型,或者实现的接口类型)
//格式: 父类类型 变量名 = 子类对象; class Person{ String name; int age; public void eat(){ System.out.println("Person.eat"); } public void sleep(){ System.out.println("Person.sleep"); } } class Man extends Person{ boolean isSmoking; public void eat(){ System.out.println("Man,eat"); } public void sleep(){ System.out.println("Man.sleep"); } public void earnMoney(){ System.out.println("Man.earnMoney"); } } class Woman extends Person{ boolean isBeauty; public void eat(){ System.out.println("Woman.eat"); } public void sleep(){ System.out.println("Woman.sleep"); } public void goShopping(){ System.out.println("Woman.goShopping"); } } public class Test{ public static void main(String []args){ Person p1 = new Person(); Man m1 = new Man(); //多态性的体现 Person p2 = Man(); } }
-
-
多态性的应用:虚拟方法的调用
//省略类的定义,和上述代码块定义相同 class Person{/*省略*/} class Man extends Person{/*省略*/} class Woman extends Person{/*省略*/} public class Test{ public static void main(String []args){ Person p1 = new Man(); Person p2 = new Woman(); p1.eat(); p2.sleep(); } } //输出结果 //Man.eat //Woman.sleep
Java引用变量有两个类型:
编译时类型
和运行时类型
。- 编译时类型由
声明
该变量时使用的类型决定 - 运行时类型由
实际赋给该变量的对象
决定。 - 简称:编译时,看左边;运行时,看右边。
- 编译时类型由
-
多态性的使用前提
- 类的继承关系。要有类的继承关系
- 方法的重写。要有方法的重写
-
多态性的适用性
-
适用于方法
-
不适用于属性
-
//属性是否满足多态性? class Person{ String id = "Person"; } class Man extends Person{ String id = "Man"; } public class Test{ public static void main(String []args){ Person p1 = new Man(); System.out.println(p1.id); } } //输出结果:Person
多态性的应用,只适用于方法、不适用于属性
-
多态性的好处及弊端
class Animal{ //动物类
public void eat(){
System.out.println("Animal.eat");
}
public void jump(){
System.out.println("Animal.jump");
}
}
class Dog extends Animal{ //狗类
public void eat(){
System.out.println("Dog.eat");
}
public void jump(){
System.out.println("Dog.jump");
}
public void watchDoor(){
System.out.println("Dog.watchDoor"); //Dog类中特有的方法
}
}
class Cat extends Animal{ //猫类
public void eat(){
System.out.println("Cat.eat");
}
public void jump(){
System.out.println("Cat.jump");
}
public void catchMouse(){
System.out.println("Cat.catchMoues"); //猫类的特有方法
}
}
public class Test {
public void adopt(Animal animal){ //领养方法
animal.eat();
animal.jump();
//此时,调用的方法,只能调用Animal中声明的方法
}
public static void main(String []args){
Test t1 = new Test();
t1.adopt(new Dog());
}
}
//输出结果:
//Dog.eat
//Dog.jump
好处:变量引用的子类对象不同,执行的方法就不同,实现动态绑定。代码编写更灵活、功能更强大,可维护性和扩展性更好了。
可以减少了许多方法的声明,在上述代码中,只需要声明
public void adopt(Animal animal){}
方法,不需要单独为Dog、Cat等动物
单独声明public void adopt(Dog\Cat)
的方法
弊端:一个引用类型变量如果声明为父类的类型,但实际引用的是子类对象,那么该变量就不能再访问子类中添加的属性和方法。
在使用中,只能调用
Animal
类中存在的方法,不能使用Dog
类中特有的watchDoor()
方法,和Cat
类中特有的catchMouse()
方法
向下转型
class Person{
}
class Man extends Person{
}
class Woman extends Person{
}
public class Test{
public static void main(String []args){
Person p1 = new Man();
Man m1 = (Man)p1;//此时,m1和p1指向同一个堆空间,且m1可以使用Man类特有的方法
//错误转型
Person p2 = new Woman();
Man m2 = (Man)p2;//此时,m2不能使用Man类中特有的方法
}
}
instanceof关键字
使用类的向下转型之前可以通过调用instanceof进行判断。避免出现类型转换异常
class Person{
}
class Woman extends Person{
}
class Man extends Person{
}
public class Test{
public static void main(String []args){
Person p1 = new Man();
if(p1 instanceof Man){
Man m1 = (Man)p1;
}
//p1 instanceof Man 表达式值为boolean类型值
}
}
格式: a instanceof A
判断对象a是否是类A的实例
- 若是,返回true
- 若不是,返回false