2020.7.23Java基础总结8_面向对象4_多态

Java基础总结8

一、面向对象4

1. 多态

1.1 概述

​ 某一个事物,在不同时刻表现出来的不同状态。

  • 多态的前提:
    • 继承或者实现【二选一】
    • 方法的重写【意义体现:不重写,无意义】
    • 父类引用指向子类对象【格式体现】
1.2 多态的体现

多态体现的格式:

父类类型 变量名 = new 子类对象; 
变量名.方法名();

​ 父类类型:指子类对象继承的父类类型,或者实现的父接口类型。

代码演示:

Fu f = new Zi(); 
f.method();

当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误;如果有,执行的是子类重写 后方法。

代码演示:

定义父类:

public abstract class Animal {       
    public abstract void eat();   
} 

定义子类:

class Cat extends Animal {       
    public void eat() {           
        System.out.println("吃鱼");       
    }   
}     
class Dog extends Animal {       
    public void eat() {           
        System.out.println("吃骨头");       
    }   
}

定义测试类:

public class Test {     
    public static void main(String[] args) {         
        // 多态形式,创建对象         
        Animal a1 = new Cat();           
        // 调用的是 Cat 的 eat         
        a1.eat();                     
        // 多态形式,创建对象         
        Animal a2 = new Dog();          
        // 调用的是 Dog 的 eat         
        a2.eat();                    
    }   
}
1.3 多态中成员访问的特点
  • 成员变量:

    ​ 编译看左边,运行看左边。

  • 构造方法:

    ​ 创建子类对象的时候,会访问父类的构造方法,对父类的数据进行初始化。

  • 成员方法:

    ​ 编译看左边,运行看右边。

  • 静态方法:

    ​ 编译看左边,运行看左边。

1.4 多态的利弊
  • 好处:
    • 提高了代码的维护性(继承保证)
    • 提高了代码的扩展性(由多态保证)
  • 弊端:
    • 不能使用子类特有的功能
    • 解决办法:把父类的引用强制转换为子类的引用。(向下转型)
1.5 多态的内存图解

1.6 引用类型转换

​ 多态的转型分为向上转型和向下转型两种。

  • 向上转型:多态本身是子类类型向父类类型向上转换的过程,这个过程是默认的。

    • 当父类引用指向一个子类对象时,便是向上转型。

    • 使用格式:

      父类类型  变量名 = new 子类类型();
      如:Animal a = new Cat();
      
  • 向下转型:父类类型向子类类型向下转换的过程,这个过程是强制的。

    • 一个已经向上转型的子类对象,将父类引用转为子类引用,可以使用强制类型转换的格式,便是向下转型。

    • 使用格式:

      子类类型 变量名 = (子类类型) 父类变量名;:Cat c =(Cat) a; 
      
  • 为什么要转型

    ​ 当使用多态方式调用方法时,首先检查父类中是否有该方法,如果没有,则编译错误。也就是说,不能调用子类拥 有,而父类没有的方法。编译都错误,更别说运行了。这也是多态给我们带来的一点"小麻烦"。所以,想要调用子 类特有的方法,必须做向下转型。

    转型演示代码:

    定义类:

    abstract class Animal {       
        abstract void eat();   
    }     
    class Cat extends Animal {       
        public void eat() {           
            System.out.println("吃鱼");       
        }       
        public void catchMouse() {           
            System.out.println("抓老鼠");       
        }   
    }     
    class Dog extends Animal {       
        public void eat() {           
            System.out.println("吃骨头");       
        }       
        public void watchHouse() {           
            System.out.println("看家");       
        }   
    }
    

    定义测试类:

    public class Test {     
        public static void main(String[] args) {         
            // 向上转型           
            Animal a = new Cat();           
            a.eat();  // 调用的是 Cat 的 eat    
            // 向下转型           
            Cat c = (Cat)a;                
            c.catchMouse();  // 调用的是 Cat 的 catchMouse        
        }  
    }
    
  • 转型异常

    转型过程中,不注意就会出现这样的问题,代码如下:

    public class Test {     
        public static void main(String[] args) {         
            // 向上转型           
            Animal a = new Cat();   
            a.eat();            // 调用的是 Cat 的 eat  
            // 向下转型           
            Dog d = (Dog)a;        
            d.watchHouse();    // 调用的是 Dog 的 watchHouse 【运行报错】 
         }   
    }
    

    ​ 这段代码可以通过编译,但是运行时,却报出了 ClassCastException ,类型转换异常!这是因为,明明创建了 Cat类型对象,运行时,当然不能转换成Dog对象的。这两个类型并没有任何继承关系,不符合类型转换的定义。

    应new一个Dog类赋给对象a,这样a就可以直接调用Dog类的成员了。

2. 抽象类

2.1 概述

​ 把没有方法主体的方法称为抽象方法。Java语法规定,包含抽象方法的类就是抽象类。

  • 抽象方法 : 没有方法体的方法。
  • 抽象类:包含抽象方法的类。
2.2 abstract使用格式
  • 抽象方法:使用 abstract 关键字修饰方法,该方法就成了抽象方法,抽象方法只包含一个方法名,而没有方法体。

    定义格式:

    修饰符 abstract 返回值类型 方法名 (参数列表);
    

    代码举例:

    public abstract void eat()
    
  • 抽象类:如果一个类包含抽象方法,那么该类必须是抽象类。

    定义格式:

    abstract class 类名 {     
    
    }
    

    代码举例:

    public abstract class Animal {     
        public abstract void eat()}
    
  • 抽象的使用

    ​ 继承抽象类的子类必须重写父类所有的抽象方法。否则,该子类也必须声明为抽象类。最终,必须有子类实现该父 类的抽象方法,否则,从最初的父类到最终的子类都不能创建对象,失去意义。

    代码举例:

    public class Cat extends Animal {     
        public void eat(){        
            System.out.println("小猫吃鱼")} 
    }   
    public class CatTest {    
        public static void main(String[] args) {             
            // 创建子类对象         
            Cat c = new Cat();                  
            // 调用eat方法         
            c.eat();    
        }    
    } 
    输出结果: 
    小猫吃鱼
    

    此时的方法重写,是子类对父类抽象方法的完成实现,我们将这种方法重写的操作,也叫做实现方法。

2.3 抽象类的成员特点
  • 抽象类的成员特点:
    • 成员变量:既可以是变量,也可以是常量。
    • 构造方法:有。用于子类访问父类数据的初始化。
    • 成员方法:既可以是抽象的,也可以是非抽象的。
  • 抽象类的成员特性:
    • 抽象方法 :强制要求子类做的事情。
    • 非抽象方法:子类继承的事情,提高代码复用性。
2.4 注意事项
  1. 抽象类不能创建对象,如果创建,编译无法通过而报错。只能创建其非抽象子类的对象。
  2. 抽象类中,可以有构造方法,是供子类创建对象时,初始化父类成员使用的。
  3. 抽象类中,不一定包含抽象方法,但是有抽象方法的类必定是抽象类。
  4. 抽象类的子类,必须重写抽象父类中所有的抽象方法,否则,编译无法通过而报错。除非该子类也是抽象类。
2.5 练习

​ 假如我们在开发一个系统时需要对员工(Employee)类进行设计,员工包含3个属性:姓名、工号以及工资(salary)。
​ 经理(Manager)也是员工,除了含有员工的属性外,另为还有一个奖金(bonus)属性。
​ 然后定义工作的方法。

代码演示:

定义类

人类:

abstract class Person {
    String name;
    String jobNumberID;
    int salary;
    public abstract void work();
}

员工类:

public class Employee extends Person{
    @Override
    public void work() {
        System.out.println("朝九晚九");
    }
}

经理类:

public  class Manager extends Person{
    int bonus=10000;//奖金
    public void supervise(){
            System.out.println("监管");
    }
    @Override
    public void work() {
        System.out.println("朝九晚五");
    }
}

测试类:

public class MyTest {
    public static void main(String[] args) {
        Person p=new Employee();
        p.name="张三";
        p.jobNumberID="001";
        p.salary=5000;
        System.out.println(p.name);
        System.out.println(p.jobNumberID);
        System.out.println(p.salary);
        p.work();
        System.out.println("=====================================");
        p=new Manager();
        p.name="王五";
        p.jobNumberID="002";
        p.salary=10000;
        System.out.println(p.name);
        System.out.println(p.jobNumberID);
        System.out.println(p.salary);
        p.work();
        Manager manager=(Manager) p;
        manager.supervise();
        System.out.println(manager.bonus);
    }
}

3. 接口

3.1 概述
  • 接口:是Java语言中一种引用类型,是方法的集合,如果说类的内部封装了成员变量、构造方法和成员方法,那么 接口的内部主要就是封装了方法。包含抽象方法,默认方法和静态方法,私有方法。

  • 定义:它与定义类方式相似,但是使用 interface 关键字。它也会被编译成.class文件,但一定要明确它并 不是类,而是另外一种引用数据类型。

  • 使用:,它不能创建对象,但是可以被实现( implements ,类似于被继承)。一个实现接口的类(可以看做 是接口的子类),需要实现接口中所有的抽象方法,创建该类对象,就可以调用方法了,否则它必须是一个抽象类。

3.2 定义格式
public interface 接口名称 {     
    // 抽象方法     
    // 默认方法     
    // 静态方法     
    // 私有方法 
}
3.3 接口的实现
  • 格式:

    class 类名 [extends 父类名] implements 接口名1,接口名2,接口名3... { 
        // 重写接口中抽象方法【必须】    
        // 重写接口中默认方法【不重名时可选】    
    } 
    
3.4 接口的成员特点
  • 成员变量:
    • 只能是常量,并且是静态的。
    • 默认修饰符:public static final
    • 建议:自己手动给出。
  • 构造方法:
    • 接口没有构造方法。
  • 成员方法:
    • 只能是抽象方法。
    • 默认修饰符:public abstract
    • 建议:自己手动给出。
3.5 类与接口的关系
  • 类与类:
    • 继承关系,只能单继承,可以多层继承。
  • 类与接口:
    • 实现关系,可以单实现,也可以多实现。
    • 并且还可以在继承一个类的同时实现多个接口。
  • 接口与接口:
    • 继承关系,可以单继承,也可以多继承。
3.6 抽象类与接口的关系
  • 成员区别:
    • 抽象类:
      • 成员变量:可以变量,也可以常量
      • 构造方法:有
      • 成员方法:可以抽象,也可以非抽象
    • 接口:
      • 成员变量:只能是常量
      • 成员方法:只可以抽象
  • 关系区别:
    • 类与类:
      • 继承,单继承
    • 类与接口:
      • 实现,单实现,多实现
    • 接口与接口
      • 继承,单继承,多继承
  • 设计理念区别:
    • 抽象类:抽象类中定义的是该继承体系的共性功能。
      己手动给出。
3.5 类与接口的关系
  • 类与类:
    • 继承关系,只能单继承,可以多层继承。
  • 类与接口:
    • 实现关系,可以单实现,也可以多实现。
    • 并且还可以在继承一个类的同时实现多个接口。
  • 接口与接口:
    • 继承关系,可以单继承,也可以多继承。
3.6 抽象类与接口的关系
  • 成员区别:
    • 抽象类:
      • 成员变量:可以变量,也可以常量
      • 构造方法:有
      • 成员方法:可以抽象,也可以非抽象
    • 接口:
      • 成员变量:只能是常量
      • 成员方法:只可以抽象
  • 关系区别:
    • 类与类:
      • 继承,单继承
    • 类与接口:
      • 实现,单实现,多实现
    • 接口与接口
      • 继承,单继承,多继承
  • 设计理念区别:
    • 抽象类:抽象类中定义的是该继承体系的共性功能。
    • 接口:接口中定义的是该继承体系的扩展功能。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值