关于接口,每天的编码都在写,就不多说了。这里对比下接口,抽象类,类3者的关系:

1),接口是一种规范,就是告诉外界这个东东可以做什么。

2),抽象类是一种模板,就是告诉外界这个东西的一部分公共功能。

3),类和上面的接口,抽象类最大的区别就是类可以维护状态信息。



  • 在以前的接口中

1,没有构造方法,不能实例化

2,接口只能继承接口,不能继承类

3,接口里没有普通方法,方法全是抽象的

4,接口里的方法默认修饰符是public abstract

5,接口里的字段全是全局常量,默认修饰符是public static final





java8中的接口在原来的基础上增加了一些功能,主要是2个:默认方法,静态方法。

  • 1,默认方法

首先来了解下为什么会出现默认方法这个东西。许多开发语言都将函数表达式集成到了其集合库中,这样子比循环方式所需的代码更少,并且更加容易理解。比如以前我们写循环代码:

for(int i = 0; i<list.size();i++)
{
System.out.println(list.get(i));
}

现在我们使用函数函数式编程,代码如下:

public static void main(String[] args)
{
List<Integer> list = Lists.newArrayList(1, 2, 3);
Stream<Integer> stream = list.stream();
stream.forEach(System.out::println);
}

现在假设我们自己不用流,我们想直接在list集合上面提供一个forEach方法,用来将一个函数应用到集合的每一个元素上面。下面是使用这种方式编写的代码:

list.forEach(System.out::println);

上面的效果很好,如果我们自己定义也就是说重新设计集合当然是没有问题的,但是java的集合是许多年前设计的,这就会带来一个问题,我们为List接口增加了一个方法,那么所有的实现类都要改过,这样子代码才不会报错,这基本是无法想象的。所以呢,java设计者希望通过允许接口包含具体实现的方法来一劳永逸的解决这个问题。当然,为接口提供默认方法还有别的好处,我们一会会整理到。

java8中允许在接口中定义默认方法,默认方法必须使用default来修饰。先来看一个例子,熟悉下java8中默认方法的语法:

public class Test implements TestInterface
{ public static void main(String[] args)
{
Test test = new Test();
//使用自己类中的方法
System.out.println(test.getId());
//使用接口中的默认方法
System.out.println(test.getName());
} @Override
public Integer getId()
{
return 25;
} } interface TestInterface
{
Integer getId(); default String getName()
{
return "默认方法里面的输出。。。";
}
}

上面的代码使用了TestInterface接口中定义的默认方法getName(),程序执行没一点问题。当然我们也可以自己来重写接口中默认方法中的默认方法。

public class Test implements TestInterface
{ public static void main(String[] args)
{
Test test = new Test();
//使用自己类中的方法
System.out.println(test.getId());
//使用接口中的默认方法
System.out.println(test.getName());
} @Override
public Integer getId()
{
return 25;
} @Override
public String getName()
{
//默认使用接口中的默认方法,注意下面的使用父类接口中方法的语法
//return TestInterface.super.getName();
return "自己的类中重写了接口中的默认方法";
} } interface TestInterface
{
Integer getId(); default String getName()
{
return "默认方法里面的输出。。。";
}
}

在上面的使用过程中,我们发现了现在使用java8接口的默认方法很好的解决了前面我说的问题了,我们不必在每个实现类中都去实现接口中新加的方法了,只需要在接口中增加一个default修饰的默认方法就好了。



另外,在上面的编码过程中,我们不难还能发现一个使用默认方法带来的好处,我们现在可以很方便的在接口中指定本质上可选的方法,根据接口的使用方式来选择使用的方法。举个例子吧,比如我们定义了一个接口,里面有一个删除元素的方法remove(),但是实际情况是这个接口应该支持可修改和不可修改2种系列,在可修改系列中没有问题,我们直接实现remove()方法就好了,不可修改系列我们不需要这个方法,但是也只能定义一个remove()的空实现,最好抛出一个异常。现在我们使用java8中的默认方法,就避免了用于不可修改系列的类也必须定义自己的,占位符性质的多余的方法,总结一下就是说默认方法让一些类要去实现的方法变成了可选方法。

  • 总结一下:

默认方法提供了2个优点:

1,优雅的随时间演化接口。也就是代码的向后兼容性

2,提供可选功能,类不必在不需要该功能的时候提供占位符实现。

  • 2,多级继承的问题

java中的继承是单继承,这个不多说了。现在考虑到接口新增的默认方法,现在java是不是绕开了单继承呢?明显不是。接口不能维护状态信息,但是现在默认方法可以提供一些行为上面的多继承。比如说一个类实现2个接口,在这2个接口中定义了2个默认方法,那么这个类同时拿到了2个方法,编码确实多了很大的灵活性。但是也会有一个很明确也是必须要解决的问题,就是冲突问题,比如说A类实现了B接口,C接口,如果B和C接口都提供了一个叫test的默认方法,那A类将实现那个接口里面的test方法呢?又比如说A类提供了自己的实现,这时候将发生什么?又比如说A同时也继承了一个有test方法的类,那么这个时候有事什么情况呢?





不慌的,解决上面的问题很简单,就是定义一组规则就好了,按照一个约定来定义解决上面的冲突。具体的规则如下:

1),在所有的情况,类实现的优先级高于接口的默认实现,也就是先使用自己类中定义的方法或者是父类中的方法。类优先是解决上面系列问题的最主要的规则。

2),当类同时实现了2个接口,2个接口中如果包含相同的默认方法,那么这个类中就必须重写这个接口,不然代码报错。

3),如果是一个接口继承了另外一个接口,2个接口中也包含相同的默认方法,那么继承接口的版本具有更高的优先级。比如A扩展了B接口,那么优先使用A类里面的test方法。

4),通过使用super,可以显式的引用被继承接口的默认实现,语法如下:InterfaceName.super.methodName()。

相关代码如下:

public class Test extends C
{ public static void main(String[] args)
{
Test test = new Test();
System.out.println(test.getName());
} } class C implements A, B
{
@Override
public Integer getId()
{
// TODO Auto-generated method stub
return null;
} //不管接口A和接口B中的这个方法是不是默认方法,有没有提供实现都必须重写, 不然代码报错
@Override
public String getName()
{
System.out.println(A.super.getName());
return "自己类中必须重写这个方法。。。";
} } interface A
{
Integer getId(); default String getName()
{
return "接口A。。。";
}
} interface B
{ default String getName()
{
return "接口B。。。";
} }
  • 3,在接口中使用静态方法

在java8中为接口新增了一项功能,定义一个或者更多个静态方法。类似于类中的静态方法,接口定义的静态方法可以独立于任何对象调用。所以,在调用静态方法时,不需要实现接口,也不需要接口的实例,也就是说哦和调用类的静态方法的方式类似。语法如下:

接口名字.静态方法名。

public class Test implements A
{ public static void main(String[] args)
{
System.out.println(A.getName());
} } interface A
{ static String getName()
{
return "接口A。。。";
}
}

注意,实现接口的类或者子接口不会继承接口中的静态方法。static不能和default同时使用。在java8中很多接口中都增加了静态方法,比如下面代码:

public class Test
{
public static void test(List<String> list)
{
//直接使用Comparator的静态方法
list.sort(Comparator.comparing(String::length));
} public static void main(String[] args)
{
List<String> list = Lists.newArrayList("122","2","32");
test(list);
for (String str : list)
{
System.out.println(str);
}
} }

java1.8--改进的接口的更多相关文章

  1. Java1.8新特性——接口改动和Lambda表达式

    Java1.8新特性——接口改动和Lambda表达式 摘要:本文主要学习了Java1.8的新特性中有关接口和Lambda表达式的部分. 部分内容来自以下博客: https://www.cnblogs. ...

  2. java9新特性-7-语法改进:接口的私有方法

    1.官方Feature 213: Milling Project Coin Support for private methods in interfaces was briefly in consi ...

  3. java8接口定义增强

    java1.7之前,接口中只允许有全局常量和抽象方法,而1.8之后允许在接口中扩充default修饰的普通方法和static修饰的静态方法 其目的是在修改接口中方法的时候,子类就不必去一一修改 pac ...

  4. Effective Java 第三版——41.使用标记接口定义类型

    Tips <Effective Java, Third Edition>一书英文版已经出版,这本书的第二版想必很多人都读过,号称Java四大名著之一,不过第二版2009年出版,到现在已经将 ...

  5. JavaSE基础知识(5)—面向对象(抽象类和接口)

    一.抽象类 1.理解 用abstract关键字定义的类,称为抽象类用abstract关键字定义的方法,称为抽象方法意义:当设计父类时,发现该父类根本不需要创建对象,并且里面有不好描述的方法.这个时候往 ...

  6. Java面向对象进阶篇(抽象类和接口)

    一.抽象类 在某些情况下,父类知道其子类应该包含哪些方法,但是无法确定这些子类如何实现这些方法.这种有方法签名但是没有具体实现细节的方法就是抽象方法.有抽象方法的类只能被定义成抽象类,抽象方法和抽象类 ...

  7. java 1.8新特性(二) 关于 function 接口的使用

    需求1:从user集合中 找出age=15的用户  传统方法 就不说了 举例明一下 java1.8 使用Predicate接口解决该需求: @FunctionalInterface public in ...

  8. Java 集合-Collection接口和迭代器的实现

    2017-10-30 00:30:48 Collection接口 Collection 层次结构 中的根接口.Collection 表示一组对象,这些对象也称为 collection 的元素.一些 c ...

  9. Java学习笔记-抽象类与接口

    抽象类用于在类中不用具体实现,而在子类中去实现的类 抽象类 抽象类概述 抽象定义:抽象就是从多个事物中将共性的,本质的内容抽取出来 抽象类:Java中可以定义没有方法体的方法,该方法的具体实现由子类完 ...

随机推荐

  1. Flask基础

    简介 Flask是当下流行的Web框架,它是用Python实现的.Flask显著的特点是:它是一个“微”框架.”微”意味着Flask旨在保持核心的简单,但同时又易于扩展.默认情况下,Flask 不包含 ...

  2. 工作整理: python报表系统常见错误整理

    1.一般收不到邮件是因为配置文件邮箱写错 2.如果报表数据不对,看数据插入的时候是否再次写入产生冲突 3.如果收不到报表某些组别的excel查看组别名称是否匹配正确,是否匹配成功,不成功无法发送

  3. 降维之pca算法

    pca算法: 算法原理: pca利用的两个维度之间的关系和协方差成正比,协方差为0时,表示这两个维度无关,如果协方差越大这表明两个维度之间相关性越大,因而降维的时候, 都是找协方差最大的. 将XX中的 ...

  4. 【转】TCP粘包分析

    一 .两个简单概念长连接与短连接: 1.长连接     Client方与Server方先建立通讯连接,连接建立后不断开, 然后再进行报文发送和接收. 2.短连接     Client方与Server每 ...

  5. Javascrip随笔1

    isNaN:指示某个值不是数字 文本字符串中使用反斜杠对代码行进行换行; 在计算机程序中,经常会声明无值的变量.未使用值来声明的变量,其值实际上是 undefined.在执行过以下语句后,变量 car ...

  6. RequireJS模块化后JS压缩合并

    使用RequireJS模块化后代码被拆分成多个JS文件了,在部署生产环境需要压缩合并,RequireJS提供了一个打包压缩工具r.js来对模块进行合并压缩.r.js非常强大,不但可以压缩js,css, ...

  7. HDU1754-I Hate It-线段树

    I Hate It Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  8. HDU--2115

    I Love This Game Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) ...

  9. Centos7安装和卸载Mongodb数据库

    MongoDB是一个基于分布式文件存储的数据库.由C++语言编写.旨在为WEB应用提供可扩展的高性能数据存储解决方案. MongoDB MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非 ...

  10. 总结过滤器,监听器,servlet的异同点,已经执行顺序。

    1.过滤器 Servlet中的过滤器Filter是实现了javax.servlet.Filter接口的服务器端程序,主要的用途是过滤字符编码.做一些业务逻辑判断等.其工作原理是,只要你在web.xml ...