面向对象(12-1):多态
面向对象(12-1):多态
1、多态的概述
多态概述:
某一个事物,在不同时刻表现出来的不同状态。
举例:
动物(狗,猫,鸡...)
水(气态,液态,固态)
class Animal{
}
class Dog extends Animal{
String name;
String type;
}
2、多态的前提
(同时满足)
1、要有继承关系
2、要有方法重写
(可以不去重写,但是如果不重写,从常理来说,就无法体现子类的特性)
3、要有父类引用指向子类对象
父 f = new 子();
动物 d = new 狗(); //读法:从右往左去读 狗是动物
水 s = new 冰(); //读法:从右往左去读 冰是是水
案例:多态的写法
class Animal666{
String name;
String type;
public void eat(){
System.out.println("吃饭");
}
}
//多态的第一个前提:继承关系
class Dog extends Animal666{
//多态的第二个前提:方法重写
@Override
public void eat() {
System.out.println("狗吃肉");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
//多态的第三个前提:父类引用指向子类对象
//多态创建对象
Animal666 x = new Dog();
}
}
3、多态访问成员的特点
(1)访问成员变量:编译看左边,运行也看左边
编译看左边,指的是看父类中有没有该成员变量,如果有说明编译不报错,可以进行访问
运行看左边,指的是编译不报错的前提下,去访问父类中变量值
(2)访问构造方法
创建子类对象的时候,先初始化子类(先调用子类的构造方法),
再初始化父类(子类中的构造方法第一句默认有一个super())
(3)访问成员方法:编译看左边,运行看右边
编译看左边,指的是看父类中有没有该成员变量,如果有说明编译不报错,可以进行访问
运行看右边,指的是编译不报错的前提下,去访问子类中变量值
(4)访问静态方法:编译看左边,运行也看左边
算不上重写了,访问的是类本身的东西
案例1:多态访问成员变量:编译看左边,运行也看左边
class Animal666{
String name;
String type;
int a =10;
public void eat(){
System.out.println("吃饭");
}
}
class Dog extends Animal666{//多态的第一个前提:继承关系
int a =20;
@Override//多态的第二个前提:方法重写
public void eat() {
System.out.println("狗吃肉");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
//多态创建对象
Animal666 x = new Dog();//多态的第三个前提:父类引用指向子类对象
System.out.println(x.a);
}
}
执行结果是:
10
Process finished with exit code 0
案例2:多态访问构造方法
class Animal666{
String name;
String type;
Animal666(){
System.out.println("这是父类的无参构造方法");
}
public void eat(){
System.out.println("吃饭");
}
}
class Dog extends Animal666{//多态的第一个前提:继承关系
Dog(){
System.out.println("这是子类的无参构造方法");
}
@Override//多态的第二个前提:方法重写
public void eat() {
System.out.println("狗吃肉");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
//多态创建对象
Animal666 x = new Dog();//多态的第三个前提:父类引用指向子类对象
}
}
执行结果如下:
这是父类的无参构造方法
这是子类的无参构造方法
Process finished with exit code 0
/*
当创建子类对象的时候,
会先初始化子类(先调用子类的构造方法),再初始化父类;
但是,子类中的构造方法第一句默认有一个super()
所以会先访问父类的构造方法
也就是我们所说的:要想初始化子类 ,必须先初始化父类
*/
案例3:多态访问成员方法:编译看左边,运行看右边
class Animal666{
String name;
String type;
public void eat(){
System.out.println("吃饭");
}
}
class Dog extends Animal666{//多态的第一个前提:继承关系
@Override//多态的第二个前提:方法重写
public void eat() {
System.out.println("狗吃肉");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
//多态创建对象
Animal666 x = new Dog();//多态的第三个前提:父类引用指向子类对象
x.eat();
}
}
执行结果如下:
狗吃肉
Process finished with exit code 0
案例4:多态访问静态方法:编译看左边,运行也看左边(算不上重写)
class Animal666{
String name;
String type;
public void eat(){
System.out.println("吃饭");
}
public static void sleep(){
System.out.println("睡觉");
}
}
class Dog extends Animal666{//多态的第一个前提:继承关系
@Override//多态的第二个前提:方法重写
public void eat() {
System.out.println("狗吃肉");
}
public static void sleep(){
System.out.println("侧着睡");
}
}
public class PolymorphicDemo1 {
public static void main(String[] args) {
//多态创建对象
Animal666 x = new Dog();//多态的第三个前提:父类引用指向子类对象
x.sleep();
}
}
执行结果如下:
睡觉
Process finished with exit code 0
4、多态的好处
1、多态有什么好处:
(1)代码扩展性很好(由继承所带来的好处)
(2)代码的维护性很好(由多态所带来的好处)
案例:
class Animal2{
String name;
int age;
Animal2(){
}
Animal2(String name,int age){
this.name = name;
this.age = age;
}
public void eat(){
System.out.println("吃饭");
}
public void sleep(){
System.out.println("睡觉");
}
}
class Dog2 extends Animal2{
Dog2(String name,int age){
this.name = name;
this.age = age;
}
@Override
public void eat() {
System.out.println("狗吃肉");
}
@Override
public void sleep() {
System.out.println("狗侧着睡");
}
}
class Alpaca extends Animal2{
Alpaca(String name,int age){
this.name = name;
this.age = age;
}
@Override
public void eat() {
System.out.println("羊驼吃草");
}
@Override
public void sleep() {
System.out.println("羊驼卧着睡");
}
}
class Panda extends Animal2{
Panda(String name,int age){
this.name = name;
this.age = age;
}
@Override
public void eat() {
System.out.println("熊猫吃竹子");
}
@Override
public void sleep() {
System.out.println("熊猫随便睡");
}
}
//用工具类改进
class AnimalTool{
//构造方法私有化
private AnimalTool(){
}
/*
将来再想养新的动物,只要在工具类中添加一个新的动物方法就可以了
//访问狗的方法
public static void useDog(Dog2 dog2){
dog2.eat();
dog2.sleep();
}
//访问羊驼的方法
public static void useAlpaca(Alpaca alpaca){
alpaca.eat();
alpaca.sleep();
}
//访问熊猫的方法
//访问老虎的方法
//...
但是呢,工具理论上是不允许修改的,所以我们需要再次改进
因为AnimalTool中的狗、羊驼、熊猫、老虎等等都属于动物,使用多态改进。
*/
public static void useAnimal(Animal2 animal){ // Animal2 animal2 = new Panda("团团", 2);//多态
animal.eat();
animal.sleep();
}
}
public class CatDogDemo {
public static void main(String[] args) {
// 现在我想养一只狗
Dog2 d1 = new Dog2("小花", 3);
// d1.eat();
// d1.sleep();
//使用方法改进后
// useDog(d1);
//使用工具类改进后
// AnimalTool.useDog(d1);
//使用多态改进之后
AnimalTool.useAnimal(d1);
//我想再养一条狗
Dog2 d2 = new Dog2("奶糖", 4);
// d2.eat();
// d2.sleep();
//使用方法改进后
// useDog(d2);
//使用工具类改进后
// AnimalTool.useDog(d2);
//使用多态改进之后
AnimalTool.useAnimal(d2);
//我还想养一条狗
Dog2 d3 = new Dog2("旺财", 2);
// d3.eat();
// d3.sleep();
//使用方法改进后
// useDog(d3);
//使用工具类改进后
// AnimalTool.useDog(d3);
//使用多态改进之后
AnimalTool.useAnimal(d3);
//你不觉得每次调用方法都需要写一遍eat()和sleep有重复的吗?
//使用方法改进
//我又想养羊驼
Alpaca a1 = new Alpaca("小白", 2);
// a1.eat();
// a1.sleep();
//使用方法改进后
// useAlpaca(a1);
//使用工具类改进后
// AnimalTool.useAlpaca(a1);
//使用多态改进之后
AnimalTool.useAnimal(a1);
//再养只羊驼
Alpaca a2 = new Alpaca("小黄", 3);
// a2.eat();
// a2.sleep();
//使用方法改进后
// useAlpaca(a2);
//使用工具类改进后
// AnimalTool.useAlpaca(a2);
//使用多态改进之后
AnimalTool.useAnimal(a2);
//再养只羊驼
Alpaca a3 = new Alpaca("小黑", 3);
// a3.eat();
// a3.sleep();
//使用方法改进后
// useAlpaca(a3);
//使用工具类改进后
// AnimalTool.useAlpaca(a3);
//使用多态改进之后
AnimalTool.useAnimal(a3);
//有重复的和狗一样也使用方法改进
/*
如果我现在不想养羊驼了,想养熊猫
是不是养n只熊猫,要new出n次
每个熊猫也有吃和睡的方法
按照上面的写代码的习惯,再额外新增一个熊猫的方法
但是,将来我还有可能养老虎,狮子,豹子等等。。。
这些动物按照上面的写代码的习惯,是不是应该都需要写一个方法,最后会发现这个程序非常臃肿杂乱
回想一下,我们之前将多个方法操作同一类型的时候,我们用工具类进行改进的
用工具类改进之后,将来再想养新的动物,只要在工具类中添加一个新的动物方法就可以
但是呢,工具理论上不允许修改的
所以我们需要再次改进
怎么改进呢?使用多态改进
*/
//使用多态改进之后
//利用的是多态访问成员变量的特点:编译看左,运行看右
Panda p1 = new Panda("团团", 2);
AnimalTool.useAnimal(p1);
Panda p2 = new Panda("圆圆", 3);
AnimalTool.useAnimal(p2);
Panda p3 = new Panda("平平", 4);
AnimalTool.useAnimal(p3);
}
// //访问狗的方法
// public static void useDog(Dog2 dog2){
// dog2.eat();
// dog2.sleep();
// }
//
// //访问羊驼的方法
// public static void useAlpaca(Alpaca alpaca){
// alpaca.eat();
// alpaca.sleep();
// }
//
// //访问熊猫的方法
//
// //访问老虎的方法
// //...
}

浙公网安备 33010602011771号