多态概述: 同一个对象在不同时刻表现出来的不同形态,即简单理解为对象的不同形态
用猫举例如下就是猫对象的不同形态: 猫 cat = new 猫() => 此时猫是猫 动物 animal = new 猫() => 此时猫是动物
多态的前提: 1、有继承/实现关系 2、有方法重写 3、有父类引用指向子类对象
多态的练习
xxxxxxxxxxpackage ch8;
public class a_1_1Animal {
public void eat() { System.out.println("动物类的eat方法"); }}xxxxxxxxxxpackage ch8;
//使用多态的第一个前提, 继承public class a_1_2Cat extends a_1_1Animal {
//使用多态的第二个前提, 方法重写 public void eat() { System.out.println("我是猫类里面的方法重写"); }
//第三个前提写在测试类里面}xxxxxxxxxxpackage ch8;
public class a_1_3测试 {
public class AnimalDemo { public static void main(String[] args) { //使用多态的第三个前提, 父类引用指向子类对象 a_1_1Animal a = new a_1_2Cat(); //注意上面的a_1_1Animal是父类,a_1_2Cat是子类 } }}
多态中成员访问特点
例如
a_2_1Animal a = new a_2_2Cat(); 下面的介绍里面所说的"左边"指的是a_2_1Animal父类 下面的介绍里面所说的"有边"指的是a_2_2Cat子类 下面的介绍里面所说的"编译"可以理解为书写时是否报错 下面的介绍里面所说的"执行"可以理解为运行时以谁的类为准介绍
xxxxxxxxxx1、成员变量:编译看左边,即书写时是否报错取决于父类是否有这个变量执行看左边,即运行时父类的优先级高或理解为只输出父类里面的变量2、成员方法:编译看左边,即书写时是否报错取决于父类是否有这个方法执行看右边,即运行时父类的优先级高或理解为只输出父类里面的方法
思考: 造成成员变量和成员方法的访问不一样的原因是什么。答案: 因为成员方法有重写,而成员变量没有
多态中成员访问特点的练习
package ch8;
public class a_2_1Animal {
public int age = 40;
public void eat() { System.out.println("动物类的eat()方法"); }}xxxxxxxxxxpackage ch8;
//继承public class a_2_2Cat extends a_2_1Animal {
public int age = 20; public int weight = 10;
public void eat() { System.out.println("猫类中的重写方法-重写eat()"); }
public void playGame() { System.out.println("猫-playGame方法"); }}xxxxxxxxxxpackage ch8;
public class a_2_3测试 {
public static void main(String[] args) {
//先要有父类引用指向子类对象 a_2_1Animal a = new a_2_2Cat();
System.out.println(a.age); //下面那行会报错,因为父类a_2_1Animal里面没有weight变量 //System.out.println(a.weight);
//上面的age输出40,说明多态中访问的是父类中的成员变量
a.eat(); //下面那行会报错,因为父类a_2_1Animal里面没有playGame方法 //a.playGame();
//上面的eat输出的是子类a_2_2Cat重写之后的方法的输出,说明多态中访问的是子类中的成员方法 }}
多态的好处和弊端
多态的好处:提高了程序的扩展性 具体体现为:定义方法的时候,使用父类型作为参数,将来在使用的时候,使用具体的子类型参与操作即可
多态的弊端:不能使用子类的特有功能
好处和弊端的练习
x
package ch8;
public class a_3_1Animal {
public void eat() { System.out.println("动物类"); }}x
package ch8;
//继承public class a_3_2Cat extends a_3_1Animal {
public void eat() { System.out.println("猫类中的重写方法-重写父类的eat()"); }}x
package ch8;
//动物操作类public class a_3_3AnimalOperator {
//带参方法,参数是猫类的 public void useAnimal(a_3_2Cat c) { //相当于a_2_2Cat c = new a_2_2Cat(); c.eat(); }
//--------------------------------------------------------------------------------
//带参方法,参数是狗类的 public void useAnimal(a_3_5Dog d) { //相当于a_2_2Cat c = new a_2_2Cat(); d.eat(); }
//-----------------------------------------------------------------------------------
//上面的类每增加一个太麻烦了 。下面是优化写法(即可以把上面的猫类和狗类的代码全部注释,不影响),同时包含了上面的猫类和狗类的代码 //原理:父类型作为参数 public void useAnimal(a_3_1Animal a) { //相当于a_2_1Animal a = new a_3_2Cat() //也包含了a_2_1Animal a = new a_3_5Dog() //所以这里更少的代码完成了上面的猫类和狗类的同样的作用。原理是成员方法编译看左边,执行看右边 a.eat();
//如果此时再新建一个pig类文件,我们只需要在新建的pig类里面重写一次方法 //再去'a_3_4测试'里面创建pig对象就行了
//随便添加多少个类都行
//弊端:如果在这些动物子类里面定义一个特有方法,并且在这里调用,那么是不允许的,会报错 //比如在pig类里面写一个sleep()方法,在用如下的代码调用一下 //a.sleep(); //上面那行就会报错 //原理:不允许子类访问子类自身的特有方法 }}xxxxxxxxxxpackage ch8;
public class a_3_4测试 {
public static void main(String[] args) { //创建动物操作类的对象,调用方法 a_3_3AnimalOperator ao = new a_3_3AnimalOperator();
//先创建一个猫类对象,因为a_3_3AnimalOperator里面的useAnimal的c传的参数是猫类的 a_3_2Cat c = new a_3_2Cat(); ao.useAnimal(c);
//--------------------------------------------------------------------------------
//先创建一个狗类对象,因为a_3_3AnimalOperator里面的useAnimal的d传的参数是狗类的 a_3_5Dog d = new a_3_5Dog(); ao.useAnimal(d);
//创建pig对象 a_3_6pig p = new a_3_6pig(); ao.useAnimal(p);
}}xxxxxxxxxxpackage ch8;
//继承public class a_3_5Dog extends a_3_1Animal {
public void eat() { System.out.println("狗类中的重写方法-重写父类的eat()"); }}x
package ch8;
//别忘了继承public class a_3_6pig extends a_3_1Animal {
public void eat() { System.out.println("猪类中的重写方法-重写父类的eat()"); }
//探究弊端,先写一个特有方法 public void sleep() { System.out.println("睡"); }}
多态中的转型
向上转型: 1、从子到父 2、父类引用指向子类对象
向下转型: 1、从父到子 2、父类引用转为子类对象
转型的练习
xxxxxxxxxxpackage ch8;
public class a_4_1Animal {
public void eat() { System.out.println("动物类"); }}xxxxxxxxxxpackage ch8;
public class a_4_2Cat extends a_4_1Animal{
public void eat() { System.out.println("猫类中的重写方法-重写父类的eat()"); }
public void playGame() { System.out.println("猫类的playGame特有方法"); }}xxxxxxxxxxpackage ch8;
public class a_4_3测试 {
/*向上转型: 1、从子到父 2、父类引用指向子类对象
向下转型: 1、从父到子 2、父类引用转为子类对象*/
public static void main(String[] args) {
//按照多态的方式创建一个对象 //右边是创建子类对象,左边是父类引用。下面那行可以理解为父类引用指向子类对象(把子类对象赋值给父类的引用),即向上转型 a_4_1Animal a = new a_4_2Cat(); //调用方法 a.eat();
/*//调用猫类的特有方法,如下,会报错,原理是编译看左边,a_4_1Animal里面没有playGame方法,所以会红字报错 //a.playGame(); //如果此时我们就想使用猫类的特有方法,解决方法如下 //先创建猫类对象 a_4_2Cat c = new a_4_2Cat(); c.eat(); c.playGame(); //就可以使用猫类的特有方法playGame了 //弊端: 又新建了一个猫类对象,没有必要。思考如何在不建猫类对象的情况下,使用猫类的特有方法。如下使用向下转型*/
//父类引用转为子类对象(把父类引用a强转为子类对象a_4_2Cat c,再把值赋值给猫类),即向下转型 a_4_2Cat c = (a_4_2Cat)a; //就可以正常使用猫类的特有方法playGame了 c.eat(); c.playGame(); }}
猫和狗_多态版
需求:采用多态的思想实现猫和狗的案例,并测试
思路:
x
定义动物类1、成员变量: 姓名,年龄2、构造方法: 无参,带参3、成员方法: get和set方法,吃饭()
定义猫类,继承动物类1、构造方法: 无参,带参2、成员方法: 重写吃饭()
定义狗类,继承动物类1、构造方法: 无参,带参2、成员方法: 重写吃饭()
定义测试类,并进行测试
猫和狗_多态版的练习
xxxxxxxxxxpackage ch8;
public class a_5_1Animal {
//定义成员变量 private String name; private int age;
//无参构造方法 public a_5_1Animal() { }
//带参构造方法 public a_5_1Animal(String name, int age) { this.name = name; this.age = age; }
//get和set方法 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 void eat() { System.out.println("动物类的eat方法"); }}xxxxxxxxxxpackage ch8;
//继承动物类public class a_5_2Cat extends a_5_1Animal {
//无参构造方法 public a_5_2Cat() { }
//带参构造方法 public a_5_2Cat(String name, int age) { super(name, age); }
//重写动物类的eat方法
public void eat() { System.out.println("猫类中的重写方法-重写父类的eat()"); }}x
package ch8;
//继承动物类public class a_5_3Dog extends a_5_1Animal {
//无参构造方法 public a_5_3Dog() { }
//带参构造方法 public a_5_3Dog(String name, int age) { super(name, age); }
public void eat() { System.out.println("狗类中的重写方法-重写父类的eat()"); }}xxxxxxxxxxpackage ch8;
public class a_5_4测试 {
public static void main(String[] args) {
//多态的形式创建猫类对象。无参,a_5_2Cat() a_5_1Animal a = new a_5_2Cat(); a.setName("猫名-无参"); a.setAge(2); System.out.println(a.getName() + "," + a.getAge()); a.eat();
//多态的形式创建猫类对象。带参,a_5_2Cat("猫名-带参",4); a = new a_5_2Cat("猫名-带参", 4); System.out.println(a.getName() + "," + a.getAge()); a.eat();
}}