(一)语法层面的区别:

抽象类:

1.用abstract表示

2.里面有一个或多个抽象方法,在方法前加abstract,抽象类中也可以没有抽象方法,如静态方法,静态代码块

3.抽象类用extends继承,并且必须重写抽象方法,如果不重写的话则子类也会成为抽象类

接口

1.用implement表示

2.接口是极度抽象的类,所有方法都是抽象的,都需要进行重写

3.接口中默认的修饰符为public abstract(如果非要自己加访问符号,jdk1.8之前只能是public,而不能是private,static这些。jdk1.8新特性后面会有介绍)

接口的作用:解决java中的单继承问题,一个类可以实现多个接口,但只能有一个父类

(二)设计模式上的区别

抽象类:

1.面向类的整体进行一个抽象。比如对飞机或者鸟抽象出这两个类都具有的特点

2.是一种模板式设计,抽象出这个类的共同点。如果对抽象类新增了实现方法,则子类将不会发生发生改变,新增抽象方法则将发生改变

接口:

1.面向行为进行一个抽象。如鸟和飞机都会飞是一个行为,则可以将其设计为一个接口,然后让鸟类和飞机类都实现它们各自飞的特性

2.是一种辐射式设计模式,修改了接口,则实现了接口的类则需要发生改变

共同点:都不能被实例化

java8接口新特性:

java8使用两个概念扩展了接口的含义:默认方法和静态方法。

1)默认方法

默认方法使得开发者可以在不破坏二进制兼容包的情况下,默认实现接口中的方法。即不强制那些实现了该类的接口的类也实现这个方法。默认方法会被接口的实现类继承或者覆盖。默认方法需要被default修饰。

举个例子:

接口:TestJava8Interface

public interface TestJava8Interface {
    default String hello() {
        return "hello";
    }
}

实现类:TestInterface8.java

public class TestInterface8 implements TestJava8Interface{
    @org.junit.Test
    public void Test() {
        TestJava8Interface t = new TestInterface8();
        System.out.println(t.hello());
    }
}

运行结果:

hello

对接口中的方法进行覆盖

实现类:TestInterface8.java

public class TestInterface8 implements TestJava8Interface{
    @Override
    public String hello () {
        return "override hello";
    }

    @org.junit.Test
    public void Test() {
        TestJava8Interface t = new TestInterface8();
        System.out.println(t.hello());
    }
}

运行结果:

override hello

2)静态方法

接口:TestJava8Interface

public interface TestJava8Interface {
     static String  helloWorld() {
        return "hello world";
     }
}

实现类:TestInterface8.java

public class TestInterface8 implements TestJava8Interface{
    @Test
    public void test () {
        System.out.println(TestJava8Interface.helloWorld());
    }
}

运行结果:

hello world

由于JVM上的默认方法的实现在字节码层面提供了支持,因此效率非常高。默认方法允许在不打破现有继承体系的基础上改进接口。该特性在官方库中的应用是:给java.util.Collection接口添加新方法,如stream()parallelStream()forEach()removeIf()等等。

尽管默认方法有这么多好处,但在实际开发中应该谨慎使用:在复杂的继承体系中,默认方法可能引起歧义和编译错误。如果你想了解更多细节,可以参考官方文档