day12 面向对象(下)

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, "骨头");
	}
}

二、匿名内部类

你可能感兴趣的:(day12 面向对象(下))