Java - 抽象

63

抽象方法:

如果一个方法, 不需要实现体(函数内容), 就可以声明抽象方法

抽象方法:

没有方法体的方法, java 中使用 abstract 关键字声明的方法

访问修饰符 abstract 返回值类型 方法名称

抽象方法必须写在抽象类中

抽象类:

abstract 关键字声明的类, 不能直接实力化

访问修饰符 abstract class 类名

抽象父类不写抽象方法, 则子类需要写, 但抽象子类可以不写, 留给子类以后的孙类解决

注意: 抽象类中不一定有抽象方法, 有抽象方法就肯定是抽象类

如果一个类继承了抽象类, 就必须实现抽象方法, 如果一定不实现, 则这个子类也声明为抽象类

抽象类不可以创建示例, 原因: 调用抽象方法没有意义

存在的意义是为了继承给子类, 通过多态调用子类对抽象方法的实现

抽象关键字 abstract 不可以和哪些关键字共存?

  1. final: final修饰的类是无法被继承的, 而 abstract 修饰的类一定要有子类. final修饰的方法无法 被覆盖, 但是 abstract 修饰的方法必须要被子类去实现的
  2. static: 静态修饰的方法属于类的, 它存在与静态区中, 和对象就没关系了. 而抽象方法没有 方法体, 使用类名调用它没有任何意义
  3. private: 私有的方法子类是无法继承到的, 也不存在覆盖, 而 abstractprivate 一起使用修饰方法, abstract 需要子类去实现这个方法, 而private修饰子类根本无法得到父类这个方法. 互相矛盾

接口:

接口本质是特殊的类, 特殊抽象类

接口中所有方法都是没有实现的(抽象方法)

接口中的所有成员都是静态常量

在 jdk8 之前: 接口中的所有属性方法, 默认都是 public 的, 即使没有用 public 修饰

java 中使用 interface 关键字来定义接口

接口无法示例化, 必须使用子类, 以多态的形式完成实现

java 中, 接口可以多实现多继承

接口的定义和实现:

public interface TestInterface {
    public void say();

    void play();
}

public class MyInterface implements TestInterface {

    @Override
    public void say() {
        // 代码
    }

    @Override
    public void play() {
        // 代码
    }
}

在jdk8中接口可以定义普通方法, 但也只能通过多态的方式访问, 用 default 关键字修饰

public interface Test {
    void show();

    public default void func() {
        System.out.println("执行");
    }
}

也可定义静态方法, 相当于把接口做了工具类

public interface Test {
    void show();

    public static void func2() {
        System.out.println("执行");
    }
}

接口多实现多继承:

interface A {
    void show1();
}

interface B {
    void show2();
}

// 接口多实现
class test implements A, B {
    public void show1() {
    }

    public void show2() {
    }
}

// 接口多继承
interface C extends A, B {
    void show3();
}

default关键字:

在接口中可以使用 default 关键字来声明一个默认方法, 例如:

interface Test {
    int size();

    default isEmpty() {
        return size() == 0;
    }
}

实现了该接口的类都会继承这个默认方法, 就不需要再实现

default冲突:

一:

如果有两个接口定义了相同的 default 方法, 例如

interface Test1 {
    default String getName() {
        return null;
    }
}

interface Test2 {
    default String getName() {
        return null;
    }
}

如果此时有一个类同时实现上面接口就会产生冲突, 需要复盖冲突的方法

public class Main implements Test1, Test2 {

    @Override
    public String getName() {
        return Test2.super.getName(); // 或者 return Test1.super.getName();
    }
}
二:

一个接口中的 default 方法和另一个接口的抽象方法相同, 那么当一个类同时实现这两个接口时会实现抽象方法而放弃 default 方法

三:

一个父类的方法和另一个接口的抽象方法相同, 那么当一个类继承这个父类并实现这个接口时, 接口的默认方法会被忽略而只考虑超类, 这也称作类优先原则

接口与抽象类的区别

相同点:

  • 都位于继承的顶端, 用于被其他实现或继承
  • 都不能实例化
  • 都包含抽象方法, 其子类都必须覆写这些抽象方法

区别:

  • 抽象类为部分方法提供实现,避免子类重复实现这些方法, 提供代码重用性
  • 接口只能包含抽象方法; 一个类只能继承一个直接父类(可能是抽象类), 却可以实现多个接口(接口弥补了Java的单继承)

二者的选用:

  • 优先选用接口, 尽量少用抽象类
  • 需要定义子类的行为, 又要为子类提供共性功能时才选用抽象类

标记接口:

只有接口的名字, 但是没有任何方法, 是标记给 JVM 用

接口注意事项:

  • 不要让 default 方法与 Object 类中任何一个方法相同

静态导包:

针对于静态方法, 导入成功可以直接使用静态方法而不需要通过 className.x 的形式访问

例如:

import static java.util.Arrays.sort;

class Test {
    public static void main(String[] args) {
        int[] arr = {1, 2, 34, 1, 2, 5, 76, 4};
        sort(arr);
    }
}