• 零基础学习java------day9------多态,抽象类,接口


    1. 多态

    1.1  概述

    某一个事务,在不同环境下表现出来的不同状态

    如:中国人可以是人的类型,中国人 p = new  中国人();同时中国人也是人类的一份,也可以把中国人称为人类,人类  d  =  new  中国人()

    1.2 多态的前提和体现

      1. 有继承关系
      2. 父类的引用指向子类的对象
      3. 有方法的重写

    1 public class Test {
    2     public static void main() {
    3         Person p = new Teacher(); // 父类的引用指向子类的对象
    4     }
    5 }
    6 class Person{}
    7 class Teacher extends Person{}

    如前几天学习,创建对象应该是如下

    Person p = new Person();
    Teacher t = new Teacher();

    但是现在写成如下,便是父类的引用指向子类的对象

    Person p = new Teacher(); //按以前学习此处的p的引用指向应该为new Person

    1.3 两种转型

      向上转型:Person  p = new  Teacher();

      向下转型:Teacher t = (Teacher)p;

    1.4  调用关系

      1. 同名成员变量:  父类的

      2. 同名静态方法:  父类的(所以说静态方法不能叫重写,因为调用还是会调用父类的方法,子类中定义的方法不会被调用)

      3. 同名静态变量:  父类的

      4. 同名成员方法:  子类的

      5.子类独有:     不能调用

      6.父类独有:     调用父类

    案例

    class Animal {
        int num = 10;
        static int age = 20;
        public void eat() {
            System.out.println("动物吃饭");
        }
        public static void sleep() {
            System.out.println("动物在睡觉");
        }
        public void run(){
            System.out.println("动物在奔跑");
        }
    }
    class Cat extends Animal {
        int num = 80;
        static int age = 90;
        String name = "tomCat";
        public void eat() {
            System.out.println("猫吃饭");
        }
        public static void sleep() {
            System.out.println("猫在睡觉");
        }
        public void catchMouse() {
            System.out.println("猫在抓老鼠");
        }
    }
    
    class AnimalTest {
        public static void main(String[] args) {
            Animal am = new Cat();//向上转型
            am.eat(); // 猫吃饭
            Animal.sleep();// 动物在睡觉
            am.run();  //动物在跑步
            System.out.println(am.num);// 10
            System.out.println(Animal.age);// 20
            am.catchMouse();// 报错,可知子类独有的方法不能被调用
            System.out.println(am.name);// 报错,可知子类独有的变量不能被调用
            Cat ct = (Cat)am;  //向下转型,调用时就调用子类自己的属性或方法,若没有相关事务就去父类中找
            ct.eat();// 猫吃饭
            Cat.sleep(); // 猫在睡觉
            ct.run(); // 动物在跑步,可见子类中没有的方法会去父类中找
            ct.catchMouse(); // 猫在抓老鼠
        }
    }
    View Code

    练习,如何将三个不同类型的蛋放一个篮子里(如鸡蛋,鸭蛋,鹅蛋)

    创建3个蛋,分别为鸡蛋,鸭蛋,鹅蛋

     1 public class EggDemo {
     2     public static void main(String[] args) {
     3         HenEgg egg1 = new HenEgg();
     4         DuckEgg egg2 = new DuckEgg();
     5         GooseEgg egg3 = new GooseEgg();
     6     }
     7 }
     8 class HenEgg{String name;}
     9 class DuckEgg{String name;}
    10 class GooseEgg{String name;}

    比如,将3个蛋放进鸡蛋数组,发现并不能实现,如下图

    所以,若没有多态,就实现不了一个篮子放三个鸡蛋,下面是利用多态来解决这个放鸡蛋的问题

    public class EggDemo {
        public static void main(String[] args) {
            Egg egg1 = new HenEgg();
            Egg egg2 = new DuckEgg();
            Egg egg3 = new GooseEgg();
            Egg[] eggs = new Egg[]{egg1,egg2,egg3};
        }
    }
    class Egg{String name;}
    class HenEgg extends Egg{String name;}
    class DuckEgg extends Egg{String name;}
    class GooseEgg extends Egg{String name;}

    结合这个例子理解什么是多态?

    多态就是多种形态,有时候是蛋,有时候是鸡蛋,所以是多套

    Egg egg1 = new HenEgg();   等号左边是蛋右边是鸡蛋

    什么时候是鸡蛋,什么时候是蛋呢?

    在调用成员方法时,调用的是子类方法,这个时候就是鸡蛋,除了成员方法以外,调用的都是父类的事务,所以是蛋

     多态的应用(同样是这个例子)

     1 public class EggDemo {
     2     public static void main(String[] args) {
     3         Egg egg1 = new HenEgg();
     4         Egg egg2 = new DuckEgg();
     5         Egg egg3 = new GooseEgg();
     6         Egg[] eggs = new Egg[]{egg1,egg2,egg3};
     7 //        egg1.born();
     8 //        egg2.born();
     9 //        egg3.born();
    10         test(egg1);
    11     }
    12     public static void test(Egg e) { // 将参数类型定义为父类,传哪个子类就调用哪个子类方法,这样更加灵活,无多态的话每次就需要创建一个对象来实现
    13         e.born();
    14     }
    15 }
    16 class Egg{
    17     String name;
    18     public void born() {
    19         System.out.println("生小*");
    20     }
    21 }
    22 
    23 class HenEgg extends Egg{
    24     String name;
    25     public void born() {
    26         System.out.println("生小鸡");
    27     }
    28 }
    29 class DuckEgg extends Egg{
    30     String name;
    31     public void born() {
    32         System.out.println("生小鸭");
    33     }
    34 }
    35 class GooseEgg extends Egg{
    36     String name;
    37     public void born() {
    38         System.out.println("生小鹅");
    39     }
    40 }
    View Code

    1.5  多态的访问特点

     略

    面试题1

    子类独有的方法不能被调用

    面试题2

    结果是    我爱你

    1..6 多态的好处和弊端

     1.多态的好处 :

    提高了程序的维护性(由继承保证)

    提高了程序的扩展性(由多态保证)

     2. 多态的弊端

     不能访问子类特有的功能

     2.  抽象

    1.1  抽象类的概述:

     回想前面我们的猫狗案例,提取出了一个动物类。并且我们在前面也创建过了动物对象,其实思想是不对的。为什么呢?因为,我说动物,你知道我说的是什么动物嘛?只有看到了具体的动物,你才知道,这是什么动物。所以说,动物本身并不是一个具体的事物,而是一个抽象的事物。只有真正的猫,狗才是具体的动物。同理,我们也可以推想,不同的动物睡觉的方式应该是不一样的,所以,我们不应该在动物类中给出具体体现,而是应该给出一个声明即可。在java中,一个没哟方法体的方法应该定义为抽象方法,而类中如果有抽象方法,该类必须定义为抽象类

    1.2 细节

    用abstract 修饰的类:

    (1)抽象方法格式: 

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

    (2)抽象类的定义格式:

       abstract class 类名{}

     1. 抽象类中可以没有抽象方法,有抽向方法的类一定是抽象类
     2. 抽象类不能创建对象,需要使用子类向上转型
     3. 抽象的子类要么实现抽象类中所有的抽象方法,要么自己是一个抽象类
     4. 抽象类有构造方法(为了让子类能够调用,完成数据的初始化)
     5. abstract 不能和final 共存

     案例

    抽象类不能创建对象,下面第三行代码会报错

    1 public class AbstractDemo {
    2     public static void main(String[] args) {
    3         Animal a = new Animal();
    4     }
    5 }
    6 // 动物抽象类
    7 abstract class Animal{
    8     abstract public void sleep();
    9 }

    报错如下

    抽象类的子类不能有抽象方法,所以需要将这个抽象方法重写

     当在定义一个继承自Animal类的Cat类时,就需要重写Animal类中的抽象方法,如下

    1 // 定义猫类
    2 class Cat extends Animal{
    3     @Override
    4     public void sleep() {   //重写sleep方法
    5         System.out.println("猫站着睡觉");
    6     }
    7 }

     (3)抽象类的成员特点

      1. 成员变量:

        可以是变量,也可以是常量

      2. 构造方法

        有构造方法,但是不能实例化(即不能创建对象),起用于子类访问父类数据的初始化

      3. 成员方法

        可以有抽象方法,限定子类必须完成某些动作

        也可以有非抽象方法,用于提高代码的复用性(如抽象类中需要额外实现一个功能,若这个类中有很多子类,用抽象方法的话,其子类都要重写这个抽象方法,若代码量特别      大,将是毁灭性的,这个时候用非抽象方法就没这个问题)

     练习

     1. 定义一个抽象类形状(shape), 包含两个方法,求周长和面积

       定义一个类长方形,实现抽象类中的方法

       定义一个圆,实现抽象类中的方法

       在测试类中测试

     1 public class Exercise1 {
     2     public static void main(String[] args) {
     3         Shape s = new Rect(2,4);
     4         Shape c = new Circle(3);
     5         result(s);
     6         result(c);
     7     }
     8     public static void result(Shape s) {   
     9         System.out.println("面积为:"+s.getArea());
    10         System.out.println("周长为:"+s.getPerimeter());
    11     }
    12 }
    13 
    14 abstract class Shape{
    15      public abstract double getArea();
    16     
    17      public abstract double getPerimeter();      
    18 }
    19 
    20 class Rect extends Shape{  // 继承关系  Is a
    21     double length;
    22     double wide;
    23     public Rect(double length,double wide){
    24         this.length = length;
    25         this.wide = wide;
    26     }
    27     @Override
    28     public double getArea() { // 该重写方法的权限要比抽象类声明处的权限要高,声明处是public,所以此处只能是public
    29         return length*wide;
    30     }
    31     public double getPerimeter() {
    32         return 2*(length+wide);  
    33     }
    34 }
    35 class Circle extends Shape{
    36     double r;
    37     public static final double PI=3.14;
    38     public Circle(double r) {
    39         this.r = r;
    40     }
    41     public double getArea() {
    42         return PI*r*r;
    43     }
    44     public double getPerimeter() {
    45         return 2*PI*r;  
    46     }  
    47 }

    2. 定义一个人,张三,男,18岁  手机  其中手机的特性为苹果X ,白色,价格是8888

    此处注意点是自己定义一个手机类,当做手机的数据类型 ,即Mobile mobile;  此处为组合关系  has a

    public class PersonTest {
        public static void main(String[] args) {
            Mobile mobile = new Mobile("苹果X","白色",8888);
            Person p = new Person("张三",'男',18,mobile);
            System.out.println("我的名字叫"+p.name+",性别:"+p.gender+",年龄;"+p.age+"我的手机为:"+mobile.name+",颜色为"+mobile.color+",价格为"+mobile.price);
        }
    }
    // 定义一个Person类
    class Person{
        String name;
        char gender;
        int age;
        Mobile mobile;
        public Person(String name,char gender,int age,Mobile mobile) {
            this.name = name;
            this.gender = gender;
            this.age = age;
            this.mobile = mobile;
        }
    }
    // 定义一个手机类
    class Mobile{
        String name;
        String color;
        double price;
        public Mobile(String name,String color,double price) {
            this.name = name;
            this.color = color;
            this.price = price;
            
        }
    }
    View Code

    3.

    3. 接口

    接口不是类,但其与类是同一层次的事物。

    3.0 接口的概述:

    3.1 定义格式:

      interface  接口名{ }

    public class InterfaceDemo{}
    interface InterfaceA{}

    3.2 注意事项

    1. 接口中只能定义常量,默认public static final修饰,不能定义变量。

    如 

    interface InterfaceA{
        int a=10;//等价于public static final int a = 10
    }

    2. 接口中只能定义抽象方法(1.8之前)  默认是public abstract 修饰

     如下面代码

    interface InterfaceA{
        private void test(); // 报错
            void test();//正确,此外写publc和abstract二者之一都是正确的,如下
            //public void test(); 正确       
    }   

    注意:这种默认情况表明子类中的方法也只能用public修饰(子类重写父类中的方法,权限不能比父类中的方法低)

    3. 接口本身不能创建对象,使用子类向上转型(如练习三中)

      接口的子类:实现了接口的类

      格式:class 类名  implements 接口名{}

      一个类可以实现多个接口:class 类名  implements 接口1,,接口2......{}

    4.接口的子类要么实现接口中所有的抽象方法要么自己是一个抽象类

    1 public class InterfaceDemo {}
    2 interface InterfaceA{
    3     void test();
    4 }
    5 class Test implements InterfaceA{
    6     public void test() { //重写test()方法,此处是类,一定要加public
    7     }
    8 }

    5. 接口中没有构造方法

    6. 接口不能实现接口,只能继承接口,并且可以多继承(类实现接口,并且一个类可以实现多个接口)

    如,再定义一个接口B,让其继承自InterfaceA,里面不能重写接口InterfaceA中声明的test()方法(即不能实现InterfaceA接口),会报错,如下

    class 子类名  implements  接口1,接口2{ }

    public class InterfaceDemo {}
    interface InterfaceA{
        void test();
    }
    interface InterfaceB {
        void test1();
    
    }
    class Test implements InterfaceA,InterfaceB{// 接口的子类一定要去实现其继承接口的所有方法,否则报错
        public void test() { 
            System.out.println("实现接口A");
        }
        public void test1() {
            System.out.println("实现接口B");
        }
    }

    7.从jdk1.8以后,接口中可以定义非抽象的方法,但是必须使用static或者default(不能省略)修饰 

    8. 一个类可以继承一个类,并且同时实现多个接口(先继承,再实现)

    class 类1 extends 类2 implents 接口()//类中可以定义实现接口的方法

     3.3 面试题

     1.抽象类和接口的区别

     1. 一个类可以实现多个接口,但却只能继承最多一个抽象类

     2. 抽象类可以包含具体的方法,接口的所有方法都是抽象的(jdk1.8之前)

     3. 抽象类可以定义常量也可以定义变量,接口只能定义常量

     4. 接口的方法都是public的,抽象类的方法可以是public,protected,private或者默认的package

     5. 抽象类可以定义构造函数,但接口却不能

     2.什么时候定义抽象类,什么时候定义接口?

     接口是功能的扩展,抽象类是根源的扩展

    如门,开门,关门应该是其固有的功能,但报警的话就只有防盗门有这个功能,其他门没有,所以报警就可以被定义为接口

     1 // 定义抽象类,其中定义开门和关门的功能
     2 abstract class Door{
     3     public abstract void openDoor();
     4     public abstract void closeDoor();
     5 }
     6 //定义报警接口
     7 interface Alarm{
     8     public void alarm();
     9 }
    10 // 定义门的子类--防盗门,
    11 class FDoor extends Door implements Alarm{
    12     public void openDoor() {}
    13     public void closeDoor() {}
    14     public void alarm() {} // 实现接口中报警的方法

    3.  编写一个抽象类Animal,抽象类中包括属性:name(String类型),抽象方法:speak().

      编写一个宠物接口Pet,接口中包括方法:eat()。

      再编写一个Cat,实现该接口和抽象类中的所有方法

         在main中进行测试,输出:“miao,  my name is xxx”;  "I want to eat some fish"

    public class AnimalTest2 {
        public static void main(String[] args) {
            Cat1 c = new Cat1("小黑");
            c.speak();
            c.eat();
         //此处也可用接口创建对象,但其只能调用接口中的方法(其他方法相当于子类中独有的方法,如speak)
         //Pet p = new Cat1("小黑");此叫接口的多态,同抽象类一样
    //p.eat();
    } }
    abstract class Animal2{ String name; abstract void speak(); } interface Pet{ void eat(); } class Cat1 extends Animal2 implements Pet{ public Cat1(String name) { this.name = name; } public void speak() { System.out.print("my name is"+name); } public void eat() { System.out.println(" I want to eat some fish"); } }

     4. 

  • 相关阅读:
    vsCode_1.27.2
    前端图片压缩(纯js)
    chrome浏览器表单自动填充默认样式(背景变黄)-autofill
    前端Table数据导出Excel使用HSSFWorkbook(Java)
    linux下安装python3.6
    linux 下启动tomca慢问题
    linux下nginx配置ssl证书(https)
    spring+mybatis多数据源
    css3实现小箭头,各种图形
    Windows 环境搭建Redis集群(win 64位)
  • 原文地址:https://www.cnblogs.com/jj1106/p/11337314.html
Copyright © 2020-2023  润新知