day12 面向对象(下) PQ
一、三大特性之多态(polymorphism)
1、多态的简介
(1)概念
单态:这个对象只有唯一的一种状态
Student s = new Student();
多态:这个对象存在多种状态。 是指同一行为,具有多个不同表现形式。
(2)多态实现的前提
1)要有继承或者实现的关系
2)方法的重写(如果没有方法重写,格式不会报错,这样的多态是没有任何意义)
3)父类的引用指向子类对象(父new子)或者父接口的引用指向实现类对象(父接口new实现类)
2、多态的体现
(1)多态体现的格式
父类类型 变量名 = new 子类对象();
变量名.方法名();
eg:
Animal dog = new Dog();
dog.eat();
(2)多态思想下成员的特点
1)实例变量
对象被什么数据类型所修饰,这个变量就会调用谁的实例变量
//父类:SuperClass
public class SuperClass {
int num = 10;
}
//子类:SubClass
public class SubClass extends SuperClass {
int num = 20;
}
//测试类:PolyDemo02
public class PolyDemo02 {
public static void main(String[] args) {
//父new父
SuperClass superC = new SuperClass();
System.out.println(superC.num);//10
//子new子
SubClass subC = new SubClass();
System.out.println(subC.num);//20
System.out.println("===================");
//利用多态创建对象
SuperClass sc = new SubClass();
System.out.println(sc);//com.atguigu.poly.demo02.SubClass@15db9742 子类地址值
System.out.println(sc.num);//10
}
}
2)实例方法
先看父类中是否有这个方法,如果有,执行子类重写后的方法;如果没有,编译报错
//父类:SuperClass
public class SuperClass {
public void method () {
System.out.println("父类的实例方法");
}
}
//子类:SubClass
public class SubClass extends SuperClass {
public void method () {
System.out.println("子类重写后的实例方法");
}
}
//测试类:PolyDemo04
public class PolyDemo04 {
public static void main(String[] args) {
//父new父
SuperClass superC = new SuperClass();
System.out.println(superC); //com.atguigu.poly.demo04.SuperClass@15db9742
superC.method();//父类的实例方法
System.out.println("==============");
//子new子
SubClass subC = new SubClass();
System.out.println(subC);//com.atguigu.poly.demo04.SubClass@6d06d69c
subC.method();//父类的实例方法
System.out.println("==============");
//父new子
SuperClass sc = new SubClass();
System.out.println(sc);//com.atguigu.poly.demo04.SubClass@7852e922
sc.method();//父类的实例方法
}
}
3)构造器
和原来一样
//父类:SuperClass
public class SuperClass {
public SuperClass () {
System.out.println("父类的构造器");
}
}
//子类:SubClass
public class SubClass extends SuperClass {
public SubClass(){
//super(); 此处隐藏了JVM提供的super()
System.out.println("子类的构造器");
}
}
//测试类PolyDemo03
public class PolyDemo03 {
public static void main(String[] args) {
//父new父
SuperClass superC = new SuperClass();//父类的构造器
System.out.println("================");
//子new子
SubClass subC = new SubClass();//父类的构造器 子类的构造器
System.out.println("================");
// 父new子
SuperClass sc = new SubClass();//父类的构造器 子类的构造器
System.out.println(sc); //com.atguigu.poly.demo03.SubClass@15db9742
}
}
3、多态的好处和弊端
(1)多态的好处
- 声明方法时,不再将形参写具体的引用数据类型,直接写父类的类型或者父类接口的类型
- 对象数组的应用
//Student类
public class Student {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//设置满参构造器
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
//重写系统中自带的toString方法
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + "]";
}
}
//测试类:PolyDemo05
public class PolyDemo05 {
public static void main(String[] args) {
Student s1 = new Student("张三",18);
Student s2 = new Student("李四",23);
Student s3 = new Student("钱五",43);
Student s4 = new Student("孙六",23);
//对象数组
Student[] arr = {s1,s2,s3,s4};
printArr(arr);
}
//object为顶级父类,将其放置形参
private static void printArr(Object[] arr) {
for (int i = 0; i < arr.length; i++) {
Object obj = arr[i];
System.out.println(obj);
}
}
}
//运行结果
Student [name=张三, age=18]
Student [name=李四, age=23]
Student [name=钱五, age=43]
Student [name=孙六, age=23]
(2)多态的弊端及解决办法
1)多态的弊端
在多态的情况下,对象无法调用自己的特有方法,只能调用子类改写父类的方法。
2)多态的解决方法
解决多态的弊端,引用数据类型的类型转换
类型转换名称 | 类型转换方向 |
---|---|
向上转型(默认转换方式) | 将子类的对象或者实现类的对象转换为父类的类型或者父接口类型(多态) |
向下转型(强制类型转换) | 将父类类型或者父接口类型转换为子类类型或者实现类类型 |
- 向下转型(强制类型转换)格式:
子类类型 对象名 = (子类类型)父类类型的对象;
eg:
Animal cat = new Cat(); //多态
Dog dog = (Dog)cat; //强转
-
引用数据类型强制类型转换时注意事项:
可能会发生ClassCastException:类型转换异常
3)instanceof关键字的引入
强制转换时易发生类型转换异常,使用instanceof给引用变量做类型的校验
- instanceof使用格式
变量名 instanceof 数据类型
eg:
c instanceof Cat
-
instanceof返回值
instanceof为关系运算符,如果变量属于该数据类型,返回true;如果变量不属于该数据类型,返回false。
4、练习题:猫狗
1.定义动物类
属性:年龄,颜色
行为:eat(String something)方法(无具体行为,不同动物吃的方式和东西不一样,
something表示吃的东西)生成空参有参构造,set和get方法
2.定义狗类继承动物类
行为:eat(String something)方法,看家lookHome方法(无参数)
3.定义猫类继承动物类
行为:eat(String something)方法,逮老鼠catchMouse方法(无参数)
4.定义Person类
属性:姓名,年龄
行为:keepPet(Dog dog,String something)方法
功能:喂养宠物狗,something表示喂养的东西
行为:keepPet(Cat cat,String something)方法
功能:喂养宠物猫,something表示喂养的东西
实现以上两种行为,思考如何只写一个方法?
生成空参有参构造,set和get方法
5.测试以上方法
使用多态、强转、instanceof等
//Animal类
public abstract class Animal {
private int age;
private String color;
//设置set()、get()方法
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
//设置无参构造器和满参构造器
public Animal(int age, String color) {
super();
this.age = age;
this.color = color;
}
public Animal() {
super();
}
//设置动物类的抽象方法
public abstract void eat(String something);
}
//Cat类 继承 Animal类
public class Cat extends Animal{
//重写父类eat方法
public void eat(String something) {
System.out.println(getAge() + "岁" + getColor() + "色的小猫正在吃" + something);
}
//逮老鼠方法
public void catchMouse () {
System.out.println(getAge() + "岁" + getColor() + "色的小猫正在逮老鼠");
}
//设置构造器
public Cat() {
super();
}
public Cat(int age, String color) {
super(age, color);
}
}
//Dog类 继承 Animal类
public class Dog extends Animal{
//重写父类抽象方法
@Override
public void eat(String something) {
System.out.println(getAge() + "岁" + getColor() + "色的小狗正在吃" + something);
}
public void lookHome(){
System.out.println(getAge() + "岁" + getColor() + "色的小狗正在看家");
}
//设置构造器
public Dog() {
super();
}
public Dog(int age, String color) {
super(age, color);
}
}
//Person类
public class Person {
//喂养狗和喂养猫的方法为方法的重载,可以直接使用多态的好处一:声明方法时,不再将形参写具体的引用数据类型,直接写父类的类型或者父类接口的类型
/*// 喂养狗的方法
public void keepPet(Dog dog,String something) {
dog.eat(something);
}
// 喂养猫的方法
public void keepPet(Cat cat,String something) {
cat.eat(something);
}*/
public void keepPet (Animal a,String something) {
a.eat(something);
}
}
//测试类:
public class PolyDemo06 {
public static void main(String[] args) {
//创建猫对象
Animal cat = new Cat(2,"白");
//创建狗的对象
Animal dog = new Dog(3,"黑");
//创建人对象
Person p = new Person();
// 调用饲养员的喂养猫的方法
p.keepPet(cat, "鱼");
// 将多态形式的对象进行向下转型
if (cat instanceof Cat) {
Cat c = (Cat)cat;
c.catchMouse();
}
//cat对象不属于Dog,判断返回false
if (cat instanceof Dog) {
Dog d = (Dog)cat;
d.lookHome();
}
//Cat c = (Cat)dog;
//c.catchMouse();
System.out.println("==================");
// 调用饲养员喂养狗的方法
p.keepPet(dog, "骨头");
}
}