Java抽象方法、抽象类以及接口

1.抽象方法

由于多态的存在,每个子类都可以覆写父类的方法。

class Person {
    public void run() { … }
}

class Student extends Person {
    @Override
    public void run() { … }
}

class Teacher extends Person {
    @Override
    public void run() { … }
}

从Person类派生的Student和Teacher都可以覆写run()方法。

如果父类的方法本身不需要实现任何功能,仅仅是为了定义方法签名,
目的是让子类覆写它,那么可以把父类的方法声明为抽象方法。

class Person {
    public abstract void run();
}

把一个方法声明为abstract,表示它是一个抽象方法,本身没有实现任何方法语句。
因为这个抽象方法本身是无法执行的,所以,Person类也无法被实例化,无法编译Person类,因为它包含抽象方法。

必须把Person类本身也声明为abstract,才能正确编译它,其实这就是下面要说的抽象类:

abstract class Person {
    public abstract void run();
}

 

2.抽象类

如果一个class定义了方法,但没有具体执行代码,这个方法就是抽象方法,抽象方法用abstract修饰。
因为无法执行抽象方法,因此这个类也必须声明为抽象类(abstract class).
使用abstract修饰的类就是抽象类。我们无法实例化一个抽象类。

抽象类本身被设计成只能被用于被继承。因此,抽象类可以强迫子类实现其定义的抽象方法,
否则编译会报错。因此,抽象方法实际上相当于定义了“规范”。

package com.imooc.objectoriented;

abstract class Person {
    public abstract void run();
}

class Student extends Person {
    public void run() {
        System.out.println("Student run");

    }}
public class ObjectMethod2 {
    public static void main(String[] args) {
        Person p = new Student();
        p.run();
    }
}

 

 

3.接口

在抽象类中,抽象方法本质上是定义接口规范:即规定高层类的接口,从而保证所有子类都有相同的接口实现。

如果一个抽象类没有字段,所有方法全部都是抽象方法:

abstract class Person {
    public abstract void run();
    public abstract String getName();
}

就可以把该抽象类改写为接口:interface。

在Java中,使用interface可以声明一个接口:

interface Person {
    void run();
    String getName();
}

所谓interface,就是比抽象类还要抽象的纯抽象接口,因为它连字段都不能有。
因为接口定义的所有方法默认都是public abstract(抽象方法)的。

当一个具体的class去实现一个interface时,需要使用implements关键字。

package com.imooc.objectoriented;

interface Person {
    void run();
    String getName();
}

class Student implements Person {
    private String name;
    public Student(String name) {
        this.name =name;
    }

    public void run() {
        System.out.println(this.name + "run");
    }
    public String getName() {
        return this.name
    }
}
public class ObjectMethod2 {
    public static void main(String[] args) {
        Student s = new Student("mao");
    }
}

接口类中定义的方法,子类中必须实现。

在Java中,一个类只能继承自另一个类,不能从多个类继承。
但是,一个类可以实现多个interface。

class Student implements Person,Hello {
    //  实现了两个interface
}

一个interface可以继承另一个interface。

interface Hello {
    void hello();
}

interface Person extends Hello {
    void run();
    String getName();
}

此时,Person接口继承自Hello接口,因此,Person接口现在实际上3个抽象方法签名,
其中一个来自继承的Hello接口。

合理设计interface和abstract class的继承关系,可以充分复用代码。
一般来说,公共逻辑适合放在abstract class中,具体逻辑放到各个子类,
而接口层次代表抽象程度。


4.接口中的default方法

(1)实现类会继承接口中的default方法

如果接口A中有default方法:

public interface A {
    public default void a(){
        System.out.println("这是A");
    }
}

Test类实现接口A:

public class Test implements A{
    
}

那么Test类将会继承接口A中的a方法:

public class Test2 {
    public static void main(String[] args) {
        Test t = new Test();
        t.a();
    }
}

 

2)如果一个类同时实现接口A和B,接口A和B中有相同的default方法,这时,该类必须重写接口中的default方法

类在继承接口中的default方法时,不知道应该继承哪一个接口中的default方法。

接口A:

public interface A {
    public default void a(){
        System.out.println("这是A");
    }
}

接口B:

public interface B {
    public default void a(){
        System.out.println("这是B");
    }
}

Test类:

 

(3)如果子类继承父类,父类中有b方法,该子类同时实现的接口中也有b方法(被default修饰),那么子类会继承父类的b方法而不是继承接口中的b方法。

接口A:

public interface A {
    public default void b(){
        System.out.println("AAA");
    }
}

类C:

public class C {
    public void b(){
        System.out.println("CCC");
    }
}

子类:

public class Test extends C implements A{
    
}

测试:

说明子类继承的b方法为父类C中的b方法,而不是接口中的default b()方法。


实现类可以不必覆写default方法。
default方法的目的是,当我们需要给接口新增一个方法时,会涉及到修改全部子类。
如果新增的是default方法,那么子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。

default方法和抽象类的普通方法是有所不同的。
因为interface没有字段,default方法无法访问字段,而抽象类的普通方法可以访问实例字段。

posted @ 2020-03-15 22:46  明王不动心  阅读(1068)  评论(0编辑  收藏  举报