接口的进化之路,从Java7到Java8到Java9

一门好的编程语言会擅于不断吸收其他语言的优点,并不断进行改进,Java就是一个很好的例子,这也是它之所以能够历经风霜而依然独占鳌头的重要原因。例如,在Java中扮演重要角色的“接口”,其功能就在不断地增强。

一、Java7中的接口:抽象方法+常量

在Java7中,接口可以包含以下两种成员:抽象方法、常量。比如,一个用于连接数据库的接口可能是这样的:

public interface ConnectionService{

String CONN_URL="127.0.0.1"; //常量:定义数据库地址

Connection getConnection(); //抽象方法1:获取连接

void closeConnection(); //抽象方法2:关闭连接

}

二、Java8中的接口:抽象方法+常量+默认方法+静态方法

假设我们上面所定义的接口已经被公司中的很多项目所使用,现在,我想在接口中增加两个功能,分别用来测试数据库是否可以访问,以及显示数据库的版本,例如想改成这样:

public interface ConnectionService{

String CONN_URL="127.0.0.1"; //常量:定义数据库地址

Connection getConnection(); //抽象方法1:获取连接

void closeConnection(); //抽象方法2:关闭连接

boolean testConnection(); //抽象方法3:测试数据库是否可达

String getVersion();//抽象方法4:显示数据库版本

}

问题来了,我们都知道,一个类要实现接口,必须实现接口中的所有的方法,这意味着,如果我们有50个子项目引用了这个接口,那么子项目中所有的实现类都要增加testConnection()和getVersion()的实现,而实际上,可能很多项目并不需要这个功能,所以可能只需要实现一个空的方法。那有没有办法在不修改现有的实现类的基础上去增强接口的功能呢?于是,Java8引入了默认方法和静态方法。而我们的接口可以这样写:

public interface ConnectionService{

String CONN_URL="127.0.0.1"; //常量:定义数据库地址

Connection getConnection(); //抽象方法1:获取连接

void closeConnection(); //抽象方法2:关闭连接

default boolean testConnection(){ //默认方法:测试数据库是否可达

//实现代码

if( ....) return true;

return false;

}

static String getVersion(){

//实现代码

System.out.println("数据库类型、版本号");

}

}

可以看到,接口中的default方法和static方法不再是抽象方法的形式,它们有方法体,也就是说你可以直接在接口中实现相应的功能。那么,default方法和static方法有何区别呢?区别在于,default方法可以被实现类重写,但static方法则不允许重写。

三、Java9中接口:抽象方法+常量+默认方法+静态方法+私有方法+私有静态方法

既然我们可以在接口中直接定义方法的内容,那随之而来就有一个问题:怎么在接口当中进行代码复用,而且我不想这些内部使用的代码暴露给实现类。在Java8当中,可以通过内部类的方式来实现。例如:

public interface ConnectionService{

String CONN_URL="127.0.0.1"; //常量:定义数据库地址

Connection getConnection(); //抽象方法1:获取连接

void closeConnection(); //抽象方法2:关闭连接

default boolean testConnection(){ //默认方法:测试数据库是否可达

Util.doPing();

if( ....) return true;

return false;

}

static String getVersion(){

Util.doPing();

System.out.println("数据库类型、版本号");

}

class Util{

private static boolean doPing(){

System.out.println("ping 服务器成功");

return true;

}

}

在上面的接口中,我们定义了一个Util内部类,其中有一个doPing()的私有方法。然后,我们的default方法和static方法都引用了这个方法。

不过,上面这种写法毕竟不太优雅,如果能够像普通的类那样子,直接将方法定义成私有方法,那么接口的实现类不就看不到了吗?于是乎,Java9增加了相关特性。

public interface ConnectionService{

String CONN_URL="127.0.0.1"; //常量:定义数据库地址

Connection getConnection(); //抽象方法1:获取连接

void closeConnection(); //抽象方法2:关闭连接

default boolean testConnection(){ //默认方法:测试数据库是否可达

doSomething();

if( ....) return true;

return false;

}

static String getVersion(){

doPing();

System.out.println("数据库类型、版本号");

}

private void doSomething(){

System.out.println("想不到例子了,应付一下");

}

private static boolean doPing(){

System.out.println("ping 服务器成功");

return true;

}

}

需要注意的是,private方法不能是abstract的,因为二者在语义上是相互冲突的。private意味着实现类不能访问该方法,而abstract意味着实现类必须覆盖该方法。

你可能感兴趣的:(接口的进化之路,从Java7到Java8到Java9)