多态、抽象类、接口_DAY09

1:多态(掌握)

   (1)多态概念:一种事物的多种形态

   (2)体现:父类的引用指向其子类的实例对象;接口的引用指向其实现类的实例对象

   (3)特点:

          成员方法:编译看左边,运行看右边

                运行:子类重写的方法运行

                编译:父类的引用类型必须有该方法

          成员变量:编译看左边,运行看左边

              运行:访问的为父类的属性

               编译:父类的引用类型必须有该属性

             总结:只有在方法调用的时候,才会判断子类是否重写,重写调用子类方法。其他情况均看父类类型

             记忆方法:方法运行看右边,其他看左边

           例子:

/*
    多态:
        一种事物的多种形态
    前提:
        具有继承关系
    特点:
        方法:编译看左边,运行看右边
            运行:子类重写的方法运行
            编译:父类的引用类型必须有该方法        
        变量:编译看左边,运行看左边
            运行:访问的为父类的属性
            编译:父类的引用类型必须有该属性
        只有在方法调用的时候,才会判断子类是否重写,重写调用子类方法。其他情况均看父类类型
                一句话总结:方法运行看右边,其他看左边
*/
class Demo5
{
    public static void main(String[] args) 
    {
        Animal animal = new Animal();      //动物是一种动物
        Animal animal2 = new Cat();           //猫是一种动物,多态:猫的实例对象,父类动物的引用

        //Cat cat2 = new Animal();           //动物是猫,不可以
        Cat cat = new Cat();               //猫是猫

        Animal a = new Cat();
        //成员方法:
        a.eat();   //喵吃了
        System.out.println(a.name);  //巴马
        System.out.println(a.age);   //80
    }
}

class Animal
{
    String name = "巴马";
    int age = 80;
    public void eat(){
        System.out.println("吃了");
    }    
}

class Cat extends Animal
{    
    String name = "加菲";
    int age = 40;
    public void eat(){
        System.out.println("喵吃了");
    }    
}
View Code

               多太内存图:

        

    (4)前提:

         A:有继承或者实现关系。

         B:有方法重写。  (重要)

/**
 * 多态的前提条件之一:必须要有方法的覆盖(即重写)
 */
public class Test {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.eat();
        // animal.sleep();  //报错,找不到符号,接口中没有sleep()抽象方法
    }
}

//接口
interface Animal {
    public abstract void eat();
}

class Dog implements Animal {
    //继承的方法的重写
    public void eat() {
        System.out.println("狗吃");
    }
    //自己的方法
    public void sleep() {
        System.out.println("夹着尾巴睡");
    }
}
View Code

         C:有父类引用指向子类对象, 或者接口的应用指向实现类的对象

    (3)好处和弊端:

         A:好处

             扩展性和维护性(是由继承和实现保证)。

/*
    有两个类猪,狗继承动物,均有吃的动作。
    创建多个猪与狗,调用他们吃的功能。
    再来一个猫,创建多个猫的对象,调用猫的吃的功能
*/
class Demo8_4
{
    public static void main(String[] args) 
    {
        
        Pig pig = new Pig();
        Pig pig2 = new Pig();
        Pig pig3 = new Pig();

        Dog dog = new Dog();
        Dog dog2 = new Dog();
        Dog dog3 = new Dog();
        /*
        Animal pig = new Pig();
        Animal pig2 = new Pig();
        Animal pig3 = new Pig();

        Animal dog = new Dog();
        Animal dog2 = new Dog();
        Animal dog3 = new Dog();
        */
        //不需要调用不同的方法,只需要调用同一个animalEat的方法即可
        /*
        MyAnimalTool.pigEat(pig);
        MyAnimalTool.pigEat(pig2);
        MyAnimalTool.pigEat(pig3);

        MyAnimalTool.dogEat(dog);
        MyAnimalTool.dogEat(dog2);
        MyAnimalTool.dogEat(dog3);
        */

        MyAnimalTool.animalEat(pig);
        MyAnimalTool.animalEat(pig2);
        MyAnimalTool.animalEat(pig3);
        MyAnimalTool.animalEat(dog);
        MyAnimalTool.animalEat(dog2);
        MyAnimalTool.animalEat(dog3);

        
        Cat cat = new Cat();
        Cat cat2 = new Cat();
        Cat cat3 = new Cat();
        /*
        Animal cat = new Cat(); 
        Animal cat2 = new Cat(); 
        Animal cat3 = new Cat(); 
        */
        /*
        MyAnimalTool.catEat(cat);
        MyAnimalTool.catEat(cat2);
        MyAnimalTool.catEat(cat3);
        */
        MyAnimalTool.animalEat(cat);
        MyAnimalTool.animalEat(cat2);
        MyAnimalTool.animalEat(cat3);
    }
    /*
    public static void pigEat(Pig p) {
        p.eat();
    }

    public static void dogEat(Dog d) {
        d.eat();
    }

    public static void catEat(Cat c) {
        c.eat();
    }
    */
}
//定义动物类作为父类
class Animal
{
    public void eat(){
        System.out.println("吃");
    }
}
//定义猪与狗作为子类
class Pig extends Animal
{
    public void eat(){
        System.out.println("拱着吃");
    }
}

class Dog extends Animal
{
    public void eat(){
        System.out.println("摇着尾巴吃");
    }
}

class MyAnimalTool
{
    //多个动物均是Animal的子类,所以只需要定义一个方法接受Animal类型即可。从而加入新的动物时,该类代码不需要改动!
    /*
    public static void pigEat(Pig p) {
        p.eat();
    }

    public static void dogEat(Dog d) {
        d.eat();
    }

    public static void catEat(Cat c) {
        c.eat();
    }
    */

    public static void animalEat(Animal a) {
        a.eat();
    }
}
//添加猫类
class Cat extends Animal
{
    public void eat(){
        System.out.println("舔着吃");
    }
}
View Code

          B:弊端

               不能使用子类的特有功能。

/**
 * 多态的前提条件之一:必须要有方法的覆盖(即重写)
 */
public class Test {
    public static void main(String[] args) {
        Animal animal = new Dog();
        animal.eat();
        // animal.sleep();  //报错,找不到符号,接口中没有sleep()抽象方法
    }
}

//接口
interface Animal {
    public abstract void eat();
}

class Dog implements Animal {
    //继承的方法的重写
    public void eat() {
        System.out.println("狗吃");
    }
    //自己的方法
    public void sleep() {
        System.out.println("夹着尾巴睡");
    }
}
View Code

    (4)向上转型和向下转型

         A:向上转型

             把子类对象赋值给父类或者接口引用 ,例子:

/*
    向上转型:
        引用变量为父类时,子类实例对象可以自动提升为父类类型。即引用为父类型,可以赋值子类实例对象。
*/
class Demo6 
{
    public static void main(String[] args) 
    {
        Animal a = new Cat();   //多态本身的赋值就是向上转型。
        Cat c = new Cat();

        //method(c);
        //method(new Animal());  不可以
        //method(a);   不可以

        method2(a);
        method2(c);  //向上转型

        Cat c2 = method3();
        Animal a2 = method3();  //向上转型

        //Cat c3 = method4();
        Animal a3 = method4(); 
    }

    public static void method(Cat c) {
        System.out.println(c);
    }

    public static void method2(Animal animal) {
        System.out.println(animal);
    }

    public static Cat method3(){
        //return new Animal();
        return new Cat();
    }

    public static Animal method4(){
        //return new Animal();
        return new Cat();  //向上转型
    }
}
class Animal
{
    String name = "巴马";
    int age = 80;
    
    public void eat(){
        System.out.println("吃了");
    }
    
}

class Cat extends Animal
{    
    String name = "加菲";
    int age = 40;

    public void eat(){
        System.out.println("喵吃了");
    }
    
}
View Code

         B:向下转型

               把父类或者父接口引用强制转换为子类,例子:

/*
    向下转型:
        将父类强转成子类,前期父类引用指向的对象为子类对象,即必须是多态的引用。
*/
class Demo7
{
    public static void main(String[] args) 
    {
        Animal a = new Cat();
        Animal a2 = new Animal();

        Cat c = (Cat)a;
        //Cat c2 = (Cat)a2;   不可以
    }
}

class Animal
{
    String name = "巴马";
    int age = 80;
    
    public void eat(){
        System.out.println("吃了");
    }
    
}

class Cat extends Animal
{    
    String name = "加菲";
    int age = 40;

    public void eat(){
        System.out.println("喵吃了");
    }
    
}
View Code

    (5)多态中的使用成员特点

         A:成员变量

               编译运行都看左边

         B:成员方法

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

        总结: 全部看父类类型,只是在调用该方法时,检查子类是否重写,如果重写,调用之类方法,如果没有重写,调用父类的方法。

      (6)多态的体现形式

         A:具体类多态(几乎不用)

         B:抽象类多态

         C:接口多态

2:抽象类(掌握)

      (1)多个具体的事物具备相同的方法声明,而方法体不同,我们就只抽取方法声明,然后定义到一个类中。

           而一个没有方法体的方法是一个抽象方法,一个类中有抽象方法,该类必须定义为抽象类。

      (2)抽象类的特点:

           A:抽象类或者抽象方法用abstract修饰。

           B:抽象类中不一定有抽象方法,有抽象方法的类一定是抽象类。

           C:抽象类不能被实例化。

           D:子类继承抽象类,要么是抽象类,要么重写所有父类抽象方法。

        例子:

/*
    抽象类:包含抽象方法的类
*/
class Demo9 
{
    public static void main(String[] args) 
    {
        //Animal a = new Animal();
        Animal a2 = new Pig();
        System.out.println("Hello World!");
    }
}
//定义动物类作为抽象父类
abstract class Animal
{
    public abstract void eat();
    public abstract void sleep();
    //public void sleep(){
    //    System.out.println();
    //}
}
//定义猪与狗作为子类
class Pig extends Animal
{
    public void eat(){
        System.out.println("拱着吃");
    }

    public void sleep(){
        System.out.println("躺着睡");
    }
}
/*
abstract class Dog extends Animal
{
    public void eat(){
        System.out.println("摇着尾巴吃");
    }
}
*/
class Dog extends Animal
{
    public void eat(){
        System.out.println("摇着尾巴吃");
    }
    public void sleep(){
        System.out.println("压着尾巴睡");
    }
}
View Code

    (3)抽象类的几个小问题

         A:不能被实例化,要构造方法干啥?

              给抽象类的成员变量赋值

         B:一个类中没有抽象方法,居然定义抽象类,有什么意义?

              强制不让该类创建对象

         C:abstract抽象关键字不能和哪些关键字共存

               a:private  抽象类的方法需要被覆盖,如果private修饰的话,子类无法访问

               b:final   抽象类需要继承,final修饰的无法继承

               c:static   抽象类抽象方法无方法体,调用无意义

    (4)抽象类的成员:

         A:成员变量 有变量,也有常量

         B:构造方法 有构造方法,用于子类访问父类数据的初始化

         C:成员方法 有抽象方法,也有非抽象的方法

    (5)抽象类的案例

       A:老师案例

       例子:

/*
    老师示例
        具体事物:基础班老师,就业班老师
        共性:姓名,年龄,讲课。
*/
class Test 
{
    public static void main(String[] args) 
    {
        BaseTeacher bt = new BaseTeacher("刘正风",28);
        bt.setName("曲阳");
        bt.teach();
        System.out.println(bt.getName());
        bt.teach();

        WorkTeacher wt = new WorkTeacher("唐嫣",28);
        wt.teach();

        Teacher t = new BaseTeacher("刘正风",28);
        t.setName("曲阳");
        t.teach();
        System.out.println(t.getName());

        Teacher t2 = new WorkTeacher("唐嫣",28);
        t2.teach();
    }
}
//设计抽象概念老师类
abstract class Teacher
{
    private String name;
    private int age;

    public Teacher(){}
    public Teacher(String name,int age){
        this.name = name;
        this.age = age;
    }

    public abstract void teach();

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }
}

//定义基础班老师
class BaseTeacher extends Teacher
{
    public BaseTeacher(){}
    public BaseTeacher(String name,int age){
        super(name,age);
    }

    public void teach() {
        System.out.println("讲JavaSE");
    }
}

//定义就业班老师
class WorkTeacher extends Teacher
{
    public WorkTeacher(){}
    public WorkTeacher(String name,int age){
        super(name,age);
    }

    public void teach() {
        System.out.println("讲JavaEE/Android");
    }
}
View Code

3:接口(掌握)

    (1)当一个抽象类中的方法都是抽象的时候,java就提供了一种更抽象的表达方式,叫接口。(接口里面的方法都是抽象的)

            a.定义接口:interface XX {}

            b.使用接口:class YY implements XX{}

          例子:

/*
    比抽象类更为抽象的表现形式
    格式:
    定义接口:interface XX {}
    使用接口:class YY implements XX{}
    
*/
class Demo11
{
    public static void main(String[] args) 
    {
        //Cat cat = new Cat();
        Cat cat2 = new Student();
        Cat cat3 = new Person();
        System.out.println("Hello World!");
    }
}

interface Cat 
{
    public abstract void climb();
}

interface Dog
{
    public abstract void guanxianshi();
}


class Animal
{
}

class Person extends Animal implements Cat,Dog
{
    public void climb(){
        System.out.println("我爬了");
    }

    public void guanxianshi(){
        System.out.println("我就管了");
    }
}

class Student extends Animal implements Cat
{
    public void climb(){
        System.out.println("我爬了");
    }

    public void guanxianshi(){
        System.out.println("我就管了");
    }
}
View Code

    (2)接口的成员特点:

         A:成员变量 是常量 默认修饰符 public static final

         B:成员方法 抽象方法 默认修饰符 public abstract

         c: 没有构造方法 (接口不能创建对象)

        例子:

/*
    接口的成员有固定修饰符:
        变量:public static final 将变量变为常量,所以必须显示初始化
        方法:public abstract    一定为公共的抽象方法
*/
class Demo12 
{
    public static void main(String[] args) 
    {
        Computer c = new Person();
        c.play();

        System.out.println(Computer.NO1);
    }
}

interface Computer
{
    //public static final String NO1 = "艾尼阿克";
    String NO1 = "艾尼阿克";
    //public abstract void play();
    //public void play();
    void play();
    //private void play(); 不能使用其他访问权限修饰符

}

class Person implements Computer
{
    
    public void play(){
        System.out.println("敲个猜数字");
    }
    /*  不能使用默认的访问权限覆盖公共的访问权限
    void play(){
        System.out.println("敲个猜数字");
    }
    */
}
View Code

    (3)接口的特点:

         A:接口用interface定义

         B:实现类实现接口用implements标识

         C:接口不能被实例化

         D:子类实现接口的时候,要么是抽象类,要么全部实现接口方法

    (4)接口和类的关系

         A:类与类的关系

               继承关系,只能单继承,可以多层继承。

         B:类与接口的关系

               实现关系,可以单实现,也可以多实现。

               还可以在继承一个类的同时,实现多个接口。 class A extends B implements C,D

         C:接口与接口的关系

               继承关系,可以单继承,也可以多继承。

    (5)接口的思想特点(理解)

         A:对外暴露的规则(USB接口)

         B:程序的扩展功能(多态)

         C:降低程序的耦合性(多态)

         D:让类可以多实现

    (6)接口和抽象类的区别

         共性:都是不断抽取出来的抽象的内容。都不能创建实例对象。

         不同:

              A:成员特点

                抽象类:

                      成员变量 可以变量,也可以常量

                      成员方法 可以抽象,也可以非抽象

                      构造方法 有

                接口:

                      成员变量 只能是常量, 固定修饰符public static final

                      成员方法 只能是抽象,固定修饰符public abstract

                      构造方法 无

            B:继承或者实现关系特点

                  a:类与类的关系(继承 extends)

                      继承关系,只能单继承,可以多层继承。

                  b:类与接口的关系(实现 implements)

                      实现关系,可以单实现,也可以多实现。

                      还可以在继承一个类的同时,实现多个接口。

                  c:接口与接口的关系(继承 extends)

                      继承关系,可以单继承,也可以多继承。

           C:设计区别

                抽象类中定义的是体系的共性内容。表达的是:is a的关系。

                接口中定义的是体系的扩展功能。表达的是:like a的关系。       

       简单总结:

               均为抽取出的相同概念的抽象。都不能创建实例对象。

                类为单继承,接口为多实现。

                继承为”is a”的关系,接口为“like a”的关系。

                抽象类中可以定义非抽象方法,共子类直接使用。接口均为抽象方法,因为固定修饰符。

    (7)如何实现一个继承体系

       分析:由具体到抽象

       实现:由抽象到具体

       

原文地址:https://www.cnblogs.com/hezhiyao/p/7487736.html