• {Java初级系列四}---继承、接口和抽象类


    本人为自学Java系列,内容来自于中国大学mooc华东师范大学陈育良教授《Java核心技术》,在此感谢老师!

    一:继承

    • 面向对象和面向过程编程语言最大的特点就是变量类型的继承,通过extend去继承父类
    • 继承能够解决很多类型的重复定义,类别内的对象属性和方法都具有一定的共同点。将共同点提取出来,即形成父类/基类/超类—Parent class/Base class/Super class
    • 其他类型则自动生成子类/派生类-----Child class/Derived class

      Human类把Man和Woman的height、weight成员属性和eat方法写成一个父类,两个子类就能继承Human,从而节约很多重复定义。

       

    • 子类会继承父类所有的属性和方法,但是不能访问private成员。
    • 子类会继承父类的父类所有的属性和方法,但是不能访问private成员
    • 单根继承原则:每个类都只能继承一个类,如果不写extends,Java类都默认继承java.lang.object,Objecvt里面默认有clone equlas finalize getcalss hashCode toString等方法
    • 同样方法名和参数情况下,本类的方法会比父类的方法优先级更高

    父类:

    1. public class Base {  
    2.  private int num = 10;  
    3.   public int getNum() {  
    4.       return this.num;  
    5.   }  
    6. }  

    子类:

    1. public class Derived extends Base{  
    2.     private int num = 20;     
    3.         
    4.     public int getNum() {  
    5.         return this.num;  
    6.     }     
    7.         
    8.     public static void main(String[] args) {  
    9.         Derived foo = new Derived();  
    10.         System.out.println(foo.getNum());  
    11.     }  
    12. }  

    程序返回值为20。子程序会选择本类的方法进行执行。

     

    解释下上章节的继承函数

    1. public class A {  
    2.  public A() {  
    3.      System.out.println("11111");  
    4.  }  
    5.  public A(int a) {  
    6.      System.out.println("22222");  
    7.  }  
    8. }  

     

    1. public class B extends A {  
    2.  public B() {  
    3.      //super();  
    4.      System.out.println("333333");  
    5.  }  
    6.  public B(int b) {  
    7.      //super(b);  
    8.      System.out.println("444444");  
    9.  }  
    10.     public static void main(String[] args) {  
    11.         // TODO Auto-generated method stub  
    12.          B obj = new B();  
    13.          System.out.println("==========");  
    14.          B obj1 = new B(10);  
    15.     }  
    16.     
    17. }  

    输出结果:

    1. 11111  
    2. 333333  
    3. ==========  
    4. 11111  
    5. 444444  

    两个构造器都会默认调用父类的无参构造函数,输入11111.

    当我们在每个构造器前面加上super函数,而且super语句必须放在第一条。

    当去掉第二行super(b)注释,输出值:

    1. 11111  
    2. 333333  
    3. ==========  
    4. 22222  
    5. 444444  

    二:抽象类

    抽象类:属性+方法组成,完整的类所有的方法都有实现(方法体),一个完整的类才可以被实例化,如果一个类暂时没有方法实现,就定义为抽象类,抽象类是无法被实例化的。

    • 抽象类关键字abstract声明;
    • 抽象类的组成

    --optional 成员变量,个数不限

    --optional具体方法,方式有实现,个数不限

    -- optional 抽象方法,加abstract关键字,个数不限

    同时对于抽象类我们还要遵循以下的规则

    • 抽象类也是类,同样要满足单根继承原则。一个类只能继承一个抽象类
    • 完整类要继承抽象类必须实现其所有的方法,否则只能定义为抽象类

    抽象类:

    1. public abstract class Shape {  
    2.     int area;  
    3.     public abstract void calArea();  
    4.     
    5. }  

    完整类继承于抽象类,并实现抽象类中的方法体。

    1. public class Rectangle extends Shape {  
    2.   int width;  
    3.   int length;  
    4.   public void set(int length, int width) {  
    5.       this.width = width;  
    6.       this.length = length;  
    7.   }  
    8.   public void calArea() {  
    9.       System.out.println(this.length *this.width);  
    10.   }  
    11.     public static void main(String[] args) {  
    12.         // TODO Auto-generated method stub  
    13.          Rectangle obj = new Rectangle();  
    14.          obj.set(10,5);  
    15.          obj.calArea();  
    16.     }  
    17.     
    18. }  

    三:接口

    • 紧接继承的定义,如果类的所有方法都没有实现,那么这个类就是接口interface。类只可以继承-extends一个类,但是可以实现-implements多个接口,继承和实现可以同时进行
    • 类可以继承多个接口,没有实现的方法将会叠加,即A继承与B C两个接口,B C两个接口所有方法体将会叠加,如果类没有实现接口所有方法,只能定义为抽象类
    • 接口里可以定义变量,但是一般是常量,详情可以参考final节

      这里给大家写几个简单的例子来描述: 类-抽象类-接口之间的关系

     

    定义三个接口:

    1. public interface Aninmal {  
    2.     public void eat();  
    3.     public void move();  
    4. }  

    接口2:

    1. public interface ClassTree {  
    2.   public void climb();  
    3. }  

    接口3

    1. public interface CatFamliy extends ClassTree, Aninmal {  
    2. // 继承多个接口相当于将没有实现的方法全部叠加  
    3.     // eat()  
    4.     // move()  
    5.     //climb()  
    6. }  

    Cat类是实现与Animanl接口的,必须实现它所有的方法体

    1. public class Cat implements Aninmal {  
    2.     public void eat() {  
    3.         System.out.println("Cat can eat");  
    4.     }  
    5.     public void move() {  
    6.         System.out.println("Cat can move");  
    7.     }  
    8. }  

    类LandAnimal由于只实现Animal中的move方法,没有实现eat方法,定义为abstract类

    1. public abstract class LandAnimal implements Aninmal {  
    2.     public void move() {  
    3.         System.out.println("LandAnimal cat move");  
    4.             
    5.     }  
    6.     //public abstract void eat();  
    7. }  

    Rabbit类是先继承LandAnimal抽象类再实现ClassTree接口

    1. public class Rabbit extends LandAnimal implements ClassTree {  
    2. // 必须先继承再实现  
    3.     public void eat() {  
    4.         System.out.println("Rabbit cat eat");  
    5.     }  
    6.     public void climb () {  
    7.         System.out.println("Rabbit can climb");  
    8.     }  
    9. }  

    Tiger类是实现CatFamily接口,所以要实现这个接口所有方法

    1. public class Tiger implements CatFamliy {  
    2.     public void move() {  
    3.         System.out.println("Tiger can move");  
    4.     }  
    5.     public void eat() {  
    6.         System.out.println("Tiger can move");  
    7.     }  
    8.     public void climb() {  
    9.         System.out.println("Tiger can move");  
    10.     }  
    11. }  

    四:转型

    1. 基本类型转型

    2. 变量支持相互转化。比如 int a = (int)3.5 这里进行变量的强转换

      基本类型转换:

      从高精度往低精度转化,会损失信息,称为收缩变换。这种情况我们需要声明类型转化

      从低精度往高精度转化,不损失信息,称为宽松变换。这种情况Java会自动转化。

      1. public class Test{  
      2.     public static void main(String[] args) {  
      3.         int  a;  
      4.         a = (int)3.5;  // 收缩变换
      5.         System.out.println(a);  
      6.         double b = 3;  // 宽松变换
      7.         System.out.println(b);  
      8.          }  

      结果:

      1. 3  
      2. 3.0  
    3. 类转型

    类型之间可以互相转型,但是只限制于有继承关系的类

    ---子类可以转化为父类,但是父类不能转化为子类。因为子类有更多的方法和变量

    ---子类继承父类所有的财产,子类转化为父类(从大到小,即向上转型);从父类直接变成子类(从小变大,即向下转型)

    1. public class Man extends Human {  
    2.     public void eat() {  
    3.         System.out.println("i cat eat more");  
    4.     }  
    5.     public void plough() {  
    6.             
    7.     }  
    8.   public static void main(String[] arsg) {  
    9.       Man obj1 = new Man();  
    10.       obj1.eat();  
    11.       Human obj2 =  new Man();// upcast向上转换  
    12.       obj2.eat();  
    13.         Man obj3 = (Man)obj2;  
    14.         obj3.eat();  
    15. //    Man obj3 = new Human();  Human是父类,Man拥有父类不具有的成员变量与方法。  
    16. //     所以Human对象内存无法转型为Man  
    17.   }  
    18. }  

    父类:

    package service;

     

    public class Human {

    int height;

    int weight;

    public void eat() {

         System.out.println("I cat eat");

    }

    }

    输出结果:

    i cat eat more

    i cat eat more

    i cat eat more

     

    如上序程序就有类转型,Man类转为Human类,即衍生类引用转为基类引用。类型转换的作用就是带来多态

    程序中有一个eat方法,和父类中的eat方法方法名和参数一致,我们把这个称为方法重写。(不同于重载,重载是方法名一致但是形参类型或者个数不一致)。且子类方法的优先级高于父类。

    五:多态

    多态拥有三个必要条件:

    1. 继承 extends
    2. 重写 overwrite
    3. 父类引用指向子类对象 Father obj = new Son()

      当我们使用多态调用方法时,对象会检查父类是否有此方法,如果没有就会编译错误。如果有的话,就会调用子类同名方法。

       

      多态的作用到底有什么呢:

      1. 以统一的接口来操纵某一类中不同对象的动态行为
      2. 对象之间的解耦

    代码实例:

    public interface Aninmal {

    public void eat();

    public void move();

    }

     

     

    public class Dog implements Aninmal {

        public void eat() {

            System.out.println("Dog can eat");

        }

    public void move() {

            System.out.println("Dog can move");

        }

    }

     

     

    public class Cat implements Aninmal {

        public void eat() {

            System.out.println("Cat can eat");

        }

    public void move() {

            System.out.println("Cat can move");

        }

    }

    1. public class AnimalTest {  
    2.   public static  void  haveLunch(Aninmal a) {  
    3.       a.eat();  
    4.   }  
    5.   Aninmal a;  
    6.   AnimalTest c = new AnimalTest();  
    7.   public static void main(String[] args) {  
    8.      haveLunch(new Cat()); // 此处等于转型  Aninaml a = new Cat(); haveLunch(a)  
    9.      haveLunch(new Dog());  
    10.      haveLunch(new Aninmal() {  
    11.             
    12.         @Override  
    13.         public void move() {  
    14.             // TODO Auto-generated method stub  
    15.             System.out.println("move Test");  
    16.         }  
    17.             
    18.         @Override  
    19.         public void eat() {  
    20.             // TODO Auto-generated method stub  
    21.             System.out.println(" eat Test");  
    22.         }  
    23.     });  
    24.   }  
    25. }  

    输出结果:

    1. Cat can eat  
    2. Dog can eat  
    3.  eat Test  

     

    我们通过Animal接口,完成对于Dog和class两个不同对象的自己各自独有的行为。第三个是匿名类,重写补全Animal接口的方法,调用补全的方法。

    我们haveLunch方法形参可以传入不同对象,这个称为对象的解耦。

     

    六:契约设计

    契约:通过接口定义了方法的名称,参数和返回值。规范了派生类的行为

    基于接口,利用转型和多态,不影响真正方法调用,成功地将调用类和被调用类解耦。

    • 被调用类:

    • 调用类:

    两个方法之间已经解耦设计,havelunch已经定义其方法名 参数名和方法体,调用类可以利用多态的功能实现多个对象的不同行为方法。

  • 相关阅读:
    linux之shell综合例子之定时任务
    linux之shell流程控制
    C#之抛异常
    C# 日期帮助类
    Aspose Excel 单元格合并后边框显示不全
    Microsoft Compatibility telemetry占cpu资源高
    js 获取年、月、周、当前日期第几周、这月有那几周
    JS 延迟加载
    EasyUI DataGrid 多级表头设置
    C#关于日期 月 天数 和一年有多少周及根据某年某周获取时间段的计算
  • 原文地址:https://www.cnblogs.com/yblecs/p/12272740.html
Copyright © 2020-2023  润新知