抽象类和接口

抽象类
抽象类必须使用abstract修饰,有抽象方法的类一定是抽象类,抽象类里可以没有抽象方法. 
抽象类有如下注意点:

抽象类和抽象方法必须使用abstract修饰,抽象方法不能有方法体.
抽象类不能被实例化,即无法new构造器来创建抽象类的实例,即使抽象类不包含抽象方法
抽象类不能使用final修饰符,抽象方法不能使用final,private,static修饰符,因为抽象方法被继承才有意义
抽象类可以不包含抽象方法
子类的抽象方法不能和父类的抽象方法重名.
实例

abstract class Shape {
    //定义一个计算周长的计算方法
    public abstract double getPerimeter();
}

class Triangle extends Shape {

    //定义三角形的三边
    private double a;
    private double b;
    private double c;

    public Triangle(double a, double b, double c) {
        this.setSides(a, b, c);
    }

    private void setSides(double a, double b, double c) {
        if (a >= b + c || b >= a + c || c >= a + b) {
            System.out.println("三角形两边之和必须大于第三边");
            return;
        }
        this.a = a;
        this.b = b;
        this.c = c;
    }

    //重写计算三角形周长的方法
    @Override
    public double getPerimeter() {
        return a + b + c;
    }
}

class Circle extends Shape{

    private double radius;

    public Circle(double r){
        this.radius =  r;
    }

    //重写计算周长的抽象方法
    @Override
    public double getPerimeter() {
        return 2 * Math.PI * radius;
    }
}

class test {
    public static void main(String[] args) {
        Shape a = new Triangle(3,4,5);
        Shape b = new Circle(5);

        System.out.println("三角形的周长: "+a.getPerimeter());
        System.out.println("圆的周长:"+b.getPerimeter());
    }
}



Shape包含一个计算周长的抽象方法所以是抽象类,不能创建实例,只能作为父类被其他类继承.Circle和Triangle类继承了Shape类且实现了其中的抽象方法,所以可以创建实例,而且可以把一个Shape类型的引用变量指向Circle和Triangle类创建的实例. 
利用抽象类和抽象方法的优势,可以更好地发挥多态的优势,使得程序更加的灵活.

从语意来说,抽象类是多个具体类中抽象出来的父类,它具有更高层次的抽象.抽象方法体现了一种模板模式的设计,抽象类作为多个子类的通用模板,子类在抽象类的基础上进行扩展,改造,但是子类总体上会暴露抽象类的行为方式.

接口
接口多用于描述各个类型的对象间所共有的行为,表示“所有实现了这个接口的类的对象都能这么干”.

在接口中包含成员变量(只能是静态常量)、方法(只能是抽象实例方法、类方法和默认方法)、内部类(包括内部接口、枚举).

接口不能被实例化
接口不包含初始化块和构造器
接口支持多继承.可以实现多个接口
接口里没有普通方法
实现接口相当股继承了一个抽象类,如果不能全部实现其中的抽象方法,则该类也必须定义成抽象类
接口主要由三个作用: 
1. 定义变量,也可用于进行强制类型转换 
2. 调用接口定义的常量 
3. 被实现

默认方法
在1.8以前,接口里只能有抽象方法,不支持默认方法和类方法

为什么有默认方法
在 java 8 之前,接口与其实现类之间的 耦合度 太高了(tightly coupled),当需要为一个接口添加方法时,所有的实现类都必须随之修改。默认方法解决了这个问题,它可以为接口添加新的方法,而不会破坏已有的接口的实现。这在 lambda 表达式作为 java 8 语言的重要特性而出现之际,为升级旧接口且保持向后兼容(backward compatibility)提供了途径。

String[] array = new String[] {
        "hello",
        ", ",
        "world",
};
List<String> list = Arrays.asList(array);
list.forEach(System.out::println); // 这是 jdk 1.8 新增的接口默认方法



这个 forEach 方法是 jdk 1.8 新增的接口默认方法,正是因为有了默认方法的引入,才不会因为 Iterable 接口中添加了 forEach 方法就需要修改所有 Iterable 接口的实现类。

默认方法的继承
接口默认方法的继承分三种情况(分别对应上面的 InterfaceB 接口、InterfaceC 接口和 InterfaceD 接口):

不覆写默认方法,直接从父接口中获取方法的默认实现。
覆写默认方法,这跟类与类之间的覆写规则相类似。
覆写默认方法并将它重新声明为抽象方法,这样新接口的子类必须再次覆写并实现这个抽象方法。
默认方法的多继承
默认方法在多继承是会遇到一个问题,当继承的两个父接口中两个相同的默认方法时,怎么解决冲突

interface InterfaceA {
    default void foo() {
        System.out.println("InterfaceA foo");
    }
}

interface InterfaceB {
    default void bar() {
        System.out.println("InterfaceB bar");
    }
}

interface InterfaceC {
    default void foo() {
        System.out.println("InterfaceC foo");
    }

    default void bar() {
        System.out.println("InterfaceC bar");
    }
}

class ClassA implements InterfaceA, InterfaceB {
}

// 错误
//class ClassB implements InterfaceB, InterfaceC {
//}

class ClassB implements InterfaceB, InterfaceC {
    @Override
    public void bar() {
        InterfaceB.super.bar(); // 调用 InterfaceB 的 bar 方法
        InterfaceC.super.bar(); // 调用 InterfaceC 的 bar 方法
        System.out.println("ClassB bar"); // 做其他的事
    }
}


在 ClassA 类中,它实现的 InterfaceA 接口和 InterfaceB 接口中的方法不存在歧义,可以直接多实现。

在 ClassB 类中,它实现的 InterfaceB 接口和 InterfaceC 接口中都存在相同签名的 foo 方法,需要手动解决冲突,必须重写存在歧义的方法,并可以使用 InterfaceName.super.methodName(); 的方式手动调用需要的接口默认方法。

抽象类和接口
相同点: 
- 都不能实例化,位于继承树的顶端,用于被其他类继承和实现 
- 都可以包含抽象方法,实现接口或者继承抽象类的普通类必选全部实现这些抽象方法

差别: 
1. 设计目的:接口体现的一种规范,类似于整个系统的总纲,制订了系统各模块应该遵循的标准,因此接口不应该经常改变,一旦改变对整个系统是辐射性的。抽象类作为多个子类的共同父类,体现的是一种模板式设计,可以当作系统实现过程中的中间产品,已经实现了系统部分功能。 
2. 使用不同: 
1. 接口只能包含抽象方法和默认方法和类方法,不能为普通方法提供实现,抽象类可以包含普通方法。 
2. 接口只能定义静态常量属性不能定义普通属性,抽象类可以。 
3. 接口不包含构造器,抽象类可以(不是用于创建对象而是让子类完成初始化)。 
4. 接口里不能包含初始化块,抽象类完全可以。 
5. 接口多继承,抽象类单继承(只能有一个直接父类)。

  在组成形式上抽象类除了包含抽象方法外与普通类无区别。


--------------------- 
原文:https://blog.csdn.net/dora_310/article/details/77248554 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值