在jdk8之前,interface之中可以定义变量和方法,变量必须是public、static、final的,方法必须是public、abstract的。由于这些修饰符都是默认的以下写法等价
public interface JDK8BeforeInterface {
public static final int field1 = 0;
int field2 = 0;
public abstract void method1(int a) throws Exception;
void method2(int a) throws Exception;
}
JDK8及以后,允许我们在接口中定义static方法和default方法。
public interface JDK8Interface {
// static修饰符定义静态方法
static void staticMethod() {
System.out.println("接口中的静态方法");
}
// default修饰符定义默认方法
default void defaultMethod() {
System.out.println("接口中的默认方法");
}
}
public class JDK8InterfaceImpl implements JDK8Interface {
//实现接口后,因为默认方法不是抽象方法,所以可以不重写,但是如果开发需要,也可以重写
}
public class Main {
public static void main(String[] args) {
// static方法必须通过接口类调用
JDK8Interface.staticMethod();
//default方法必须通过实现类的对象调用
new JDK8InterfaceImpl().defaultMethod();
}
}
当然如果接口中的默认方法不能满足某个实现类需要,那么实现类可以覆盖默认方法。
public class AnotherJDK8InterfaceImpl implements JDK8Interface {
// 签名跟接口default方法一致,但是不能再加default修饰符
@Override
public void defaultMethod() {
System.out.println("接口实现类覆盖了接口中的default");
}
}
由于java支持一个实现类可以实现多个接口,如果多个接口中存在同样的static和default方法会怎么样呢?如果有两个接口中的静态方法一模一样,并且一个实现类同时实现了这两个接口,此时并不会产生错误,因为jdk8只能通过接口类调用接口中的静态方法,所以对编译器来说是可以区分的。但是如果两个接口中定义了一模一样的默认方法,并且一个实现类同时实现了这两个接口,那么必须在实现类中重写默认方法,否则编译失败。
也就是说继承两个接口如果有相同的默认方法类,就需要去重写默认方法。
好处
这样实现的好处:可以对于解决某些情况下,接口中的某些方法在子类之中的实现是一样的,这样就能减少重复代码,完成代码的复用;
Java9 的接口私有方法
抽象方法和接口的比较
接口方法默认修饰符是public。在java9以后可以用private定义私有方法,私有方法必须包含方法体。
通过以上对比抽象类的使用场景被削减,那么什么时候还需要使用抽象类
1、需要构造方法。
2、独立运行。
3、定义final方法防止子类篡改。
在使用接口过程中需要注意如下几个问题:
1、Interface的所有方法访问权限自动被声明为public。在java9以后可以定义私有方法,但是必须有方法体不能是抽象方法。
2、接口中可以定义“成员变量”,或者说是不可变的常量,因为接口中的“成员变量”会自动变为为public static final。可以通过类命名直接访问:ImplementClass.name。
3、不能使用new操作符实例化一个接口,但可以声明一个接口变量,该变量必须引用(refer to)一个实现该接口的类的对象。可以使用 instanceof 检查一个对象是否实现了某个特定的接口。例如:if(anObject instanceof Comparable){}。
4、在实现多接口的时候一定要避免方法名的重复,尤其是default方法。
5、接口里的方法不能用final修饰
在使用抽象类时需要注意几点:
1、抽象类不能被实例化,实例化的工作应该交由它的子类来完成,它只需要有一个引用即可。
2、抽象方法必须由子类来进行重写。
3、只要包含一个抽象方法的抽象类,该类必须要定义成抽象类。
4、抽象类中可以包含具体的方法,当然也可以不包含抽象方法。
5、子类中的抽象方法不能与父类的抽象方法同名。
6、abstract不能与final并列修饰同一个类。
7、abstract 不能与private、static、final或native并列修饰同一个方法。
参数 | 抽象类 | 接口 |
---|---|---|
默认的方法实现 | 它可以有默认的方法实现 | jdk1.8之前没有,现在可以使用default关键字创在interface中创建一个default方法,该方法包含了具体的实现代码,一个接口中可以有多个default方法 |
实现 | 子类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有抽象的方法的实现。 | 子类使用关键字implements来实现接口。它需要提供接口中所有声明的非default方法的实现 |
构造器 | 抽象类可以有构造器 | 接口没有构造器 |
实例化 | 不能 | 不能 |
访问修饰符 | 抽象方法可以有public、protected和default这些修饰符 | 接口方法默认修饰符是public。在java9以后可以用private定义私有方法,私有方法必须包含方法体。 私有方法体只能自己接口内使用 |
main方法 | 抽象方法可以有main方法并且我们可以运行它 | 接口没有main方法,因此我们不能运行它。 |
继承 | 单一继承 | 多继承 |
访问速度 | 它比接口速度要快 | 接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。 |
添加新方法 | 如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 | jdk1.8以后可以添加了,也就是说有一些在接口设计上的顽疾现在有了完美解决的方法 |
public interface SimpleInterface {
public void doSomeWork();
//A default method in the interface created using "default" keyword
//使用default关键字创在interface中直接创建一个default方法,该方法包含了具体的实现代码
default public void doSomeOtherWork(){
getStu();
System.out.println("DoSomeOtherWork implementation in the interface");
}
static void getStatic() {
System.out.println("static method");
}
default public void doSomeOtherWork2(){
getStu();
//私有静态方法用于为接口中的默认方法服务
getStatic1();
System.out.println("DoSomeOtherWork2 implementation in the interface");
}
//java9中可以创建私有方法了
private void getStu() {
System.out.println( "private method!");
}
//java9中可以创建私有静态方法了
private static void getStatic1() {
System.out.println("private static method");
}
}
class SimpleInterfaceImpl implements SimpleInterface{
@Override
public void doSomeWork() {
System.out.println("Do Some Work implementation in the class");
}
@Override
public void doSomeOtherWork() {
System.out.println("Do doSomeOtherWork implementation in the class");
}
/*
* Not required to override to provide an implementation
* for doSomeOtherWork.
* 在SimpleInterfaceImpl里,不需要再去实现接口中定义的doSomeOtherWork方法
*/
public static void main(String[] args) {
SimpleInterfaceImpl simpObj = new SimpleInterfaceImpl();
simpObj.doSomeWork();
simpObj.doSomeOtherWork();
simpObj.doSomeOtherWork2();
SimpleInterface.getStatic();
}
}
···