赞
踩
引言:
JDK8之前在接口中添加新的方法就需要修改它的实现类
因此为了兼容老的接口JDK8就增加了接口新特性
在JDK8之前接口只能定义抽象方法,它的默认修饰符是public abstract
//JDK8之前的写法
interface MyInterface1{
void eat();
void sleep();
void play();
//此时等效于 public abstract void eat();
}
JDK8接口主要增加了默认方法和静态方法以及四个函数式接口
默认方法可以有方法体,可以被实现类使用
默认方法格式:
default 返回值类型 方法名(参数列表){
//方法体语句
}
如果不用default就会默认public abstract修饰,此时不能有方法体!
//定义一个接口 interface Myface{ public abstract void eat(); //抽象方法 //这里定义一个默认方法 default void fun() { System.out.println("接口中的默认方法"); } } //定义一个实现类 class Test implements Myface{ //抽象方法依旧需要重写,先重写eat方法 //实现了某接口,就拥有了某接口的默认方法 @Override public void eat(){ System.out.println("实现接口中的方法"); } } //测试类 class Test1{ public static void main(String[] arg){ Test t = new Test(); t.eat(); //使用接口中的默认方法 t.fun(); } //输出结果: //实现接口中的方法 //接口中的默认方法 }
借用以上代码
//定义一个接口 interface Myface{ public abstract void eat(); //抽象方法 //这里定义一个默认方法 default void fun() { System.out.println("接口中的默认方法"); } } //定义一个实现类 class Test implements Myface{ //抽象方法依旧需要重写,先重写eat方法 @Override public void eat(){ System.out.println("实现接口中的方法"); } //重写接口中的fun方法 @Override public void fun(){ System.out.println("重写接口中的默认方法"); } } //测试类 class Test1{ public static void main(String[] arg){ Test t = new Test(); t.eat(); //使用接口中的默认方法 t.fun(); }
此时引入一个问题?如果一个类实现两个接口,而这两个接口中有相同的默认方法,此时会发生什么?
因为在JDK8之前我们的接口都是抽象方法,即使出现相同的方法名也无关紧要,因为他们都没有方法体,实现类重写抽象方法也不会造成歧义性,而现在我们应该怎么做呢?
实现多个接口时如果有相同方法签名的默认方法,必须对该默认方法进行重写
//定义第一个接口,包含show方法 interface Myface1{ default void show() { System.out.println("这是Myface1的show方法"); } } //定义第二个接口,包含show方法 interface Myface2{ default void show() { System.out.println("这是Myface2的show方法"); } } //定义一个实现类,此时的实现类必须重写show方法。 class Test1 implements Myface1,Myface2{ //没有重写的话会报错,不重写不知道该实现哪个方法 @Override public void show() { System.out.println("重写两个接口中的show方法"); } } //测试类 class Test{ public static void main(String[] arg){ Test1 tt = new Test1(); tt.show(); } }
上边的案例我们可以看到,实现类必须重写两个接口中相同的方法,
那么我们怎么使用两个接口中的方法呢?
基本格式: 接口名.super.方法名
这里使用上述代码,只对实现类进行修改
class Test1 implements Myface1,Myface2{
//没有重写的话会报错,不重写不知道该实现哪个方法
@Override
public void show() {
System.out.println("重写两个接口中的show方法");
}
//定义一个方法去调用接口中的方法
public void show2(){
Myface1.super.show(); //调用Myface1接口中的show方法
Myface2.super.show(); //调用Myface2接口中的show方法
}
}
默认方法注意:
1.父接口默认方法可以直接被实现类所使用,不强制重写(实现单接口,或者是多接口没有相同的默认方法)
2.实现类重写接口中的方法,权限修饰符必须是public
3.重写父接口中默认方法时如需要调用接口中的默认方法可以使用:接口名.super.方法名(参数列表);
4.如果一个类继承一个父类的同时实现多个接口,原则是:"父优先"
JDK8还可以在接口中定义静态方法
格式:
static 返回值类型 方法名(参数列表){
//方法体
}
静态方法的使用比较简单,有个注意事项
父接口中的静态方法不能被实现类所直接使用,只能通过:接口名.直接调用
代码演示:
interface MyJieKou{ //定义一个静态方法 static void run(){ System.out.println("接口中的静态方法执行"); } } //定义一个实现类 class TestJieKou implements MyJieKou{ //这里类不拥有接口中的静态方法 } //测试类 class Test{ public static void main(String[] args){ TestJieKou t1 = new TestJieKou(); //此时不能使用 t1.run() //如果需要接口中的静态方法,则可以直接调用 MyJieKou.run(); } }
在函数式接口的学习前如果你还不会使用Lambda表达式,那么你很有必要先去了解一下我的另一篇文章:Lambda表达式入门
前言:为什么要引入函数式接口?
我的理解是,为了满足不同用户对同一方法的不同要求(这里不是重载的理念)
我们知道方法的参数列表是一些数据类型,而有时我们还需要一些方法作为参数,然而方法又不属于数据类型,那么我们怎么来实现这个操作呢?
函数式接口是JDK1.8引入的新概念,我们学习函数式接口一般会学习四个,他们分别是:
1.消费型接口:
Consumer<T>
void accept(T t) : 对于T类型数据的处理方式
2.供给型接口:
Supplier<T>
T get(): 获取到T类型数据
3.函数型接口:
Function<T,R>
R apply(T) : 通过T类型参数, 获取到R类型数据结果
4.断言型接口 :
Predicate<T>
boolean test(T) : 提供一个T类型参数,判断出T类型参数是否符合规则和要求
接下来我们采用具体的案例来分别进行演示:
接受输入单个参数,不返回结果的操作
Consumer<T> 来自:java.util.function
方法:
accept(T t) :对给定的参数执行此操作
解释:如果有这么一个参数t,我们需要对它进行处理,
可处理的方式很多,我们不能确定如何操作,就可以使用消费型接口作为
参数,对传入的参数进行不同的处理,根据用户自己的需求去实现
案例分析:
需求 : 定义出一个方法功能, 客户消费指定金额, 这些金额都如何消费的
客户1 : 花了500元, 买了一把大宝剑
客户2 : 花了400元, 买了一双小花猫
… 还有很多很多的客户, 对于指定金额有不同的消费
那么用户这么多,需求又不一样,我们怎么定义这个方法呢,此时我们的函数式接口就可以很好的实现
代码分析:
import java.util.function.Consumer; //使用的时候需要导包哦! public class Test_消费型接口 { public static void main(String[] args) { //用户1 Consumer<Double> c1 = (x) -> System.out.println("花费"+x+"买一把大宝剑"); buy(500,c1); //用户2,还可以对钱进行判断,执行相应的操作 Consumer<Double> c2 = (x) ->{ if(x > 300) { System.out.println("太贵了,先不买吧"); }else { System.out.println("花费"+x+"买一只小花猫"); } }; buy(100,c2); //输出结果: //花费500.0买一把大宝剑 //花费100.0买一只小花猫 } //定义一个方法去实现不同的用户完成不同的需求 //注意,泛型只能使用引用数据类型,所以要使用基本数据类型的包装类 public static void buy(double money,Consumer<Double> con) { //接受同一个参数,执行不同的方法 con.accept(money); } }
不接受参数,返回需要的结果
Supplier< T > 来自 java.util.function
方法: T get() //返回用户指定的类型
获取T类型的结果,却不知道怎么获取
案例分析:
需求 : 定义出一个方法功能, 方法能给客户返回一个ArrayList容器, 返回的容器中包含几个数据, 集合中存储的数据有什么规律, 根据客户的实际要求决定
客户1 : 存储5个数据, 数据是30-80之间的随机数
客户2 : 存储8个数据, 数据是1-100之间的随机偶数
…
每一个客户都需要得到符合条件的集合容器
代码分析:
import java.util.ArrayList; import java.util.List; import java.util.Random; import java.util.function.Supplier; public class Test_供给型接口 { public static void main(String[] args) { //定义用户1需要获取的方式 Supplier<Integer> sup1 = () ->{ Random ran = new Random(); int i = ran.nextInt(51)+30; return i; }; System.out.println(getList(5,sup1)); //定义用户2需要获取的方式 Supplier<Integer> sup2 = () ->{ Random ran = new Random(); while(true) { int i = ran.nextInt(100)+1; if(i % 2 == 0) { return i; } } }; System.out.println(getList(8,sup2)); //输出结果: // [71, 60, 66, 64, 41] // [66, 82, 10, 12, 76, 58, 56, 52] } //定义一个用户需要获取的方法 public static List<Integer> getList(int n,Supplier<Integer> sup){ List<Integer> list = new ArrayList<>(); for(int i = 0; i < n; i++) { //get()方法来返回用户需要的结果 list.add(sup.get()); } return list; } }
Function<T,R> 来自 java.util.function
方法: R apply(T t) 将此函数应用于指定的参数
解释:如果方法中已经有数据T类型,想通过T类型的参数,获得R类型的结果,具体怎么通过T计算出R类型的,方式很多,不能具体确定,那么就可以将Function接口作为方法参数传递,相当于传递apply();
需求 : 定义出一个方法功能, 根据int类型x的值, 计算出另外一个int类型y的值, y获取方式根据客户的要求决定
客户1 : y值为x的2倍
客户2 : y值为x + 1
客户3 : y值为x-1
…
代码分析:
import java.util.function.Function; public class Test_函数式接口 { public static void main(String[] args) { //这里定义三个函数,第一个参数是传入的数据类型,第二个参数是需求的返回值的数据类型 Function<Integer,Integer> f1 = (x) -> 2*x; Function<Integer,Integer> f2 = (x) ->x+1; Function<Integer,Integer> f3 = (x) -> x-1; System.out.println(get(10,f1)); System.out.println(get(10,f2)); System.out.println(get(10,f3)); } //定义方法来传递不同的参数返回用户需求的方法 public static int get(int x,Function<Integer,Integer> fun) { return fun.apply(x); } }
Predicate<T> 来自 java.util.function
方法: boolean test(T) 在给定的参数上评估这个谓词
解释:如果方法中有T类型数据,需要判断出T类型参数是否符合规则
和要求,返回boolean类型结果,可以将Predicate断言型接口作为
方法参数传递,相当于传递test方法功能
需求 : 万能的数据筛选功能; 客户提供一个ArrayList容器, 根据客户的要求, 将容器中符合条件的数据筛选出来, 放置到一个新的ArrayList容器给客户, 筛选规则由客户决定
客户1 : 筛选出集合中所有小于100的偶数
客户2 : 筛选出集合中所有的奇数
客户3 : 筛选出集合中所有大于50的数
代码分析:
import java.util.ArrayList; import java.util.List; import java.util.function.Predicate; public class Test_断言型接口 { public static void main(String[] args) { ArrayList<Integer> list2 = new ArrayList<>(); list2.add(120); list2.add(43); list2.add(68); list2.add(98); list2.add(23); list2.add(76); //创建一个集合 Predicate<Integer> p1 = (x) -> x > 100 && x%2 ==0; System.out.println(panduan(list2,p1)); Predicate<Integer> p2 = (x) -> x % 2 != 0; System.out.println(panduan(list2,p2)); Predicate<Integer> p3 = (x) -> x > 50; System.out.println(panduan(list2,p3)); } //传递一个集合,返回筛选后的集合 public static List<Integer> panduan(ArrayList<Integer> list,Predicate<Integer> pre){ ArrayList<Integer> li = new ArrayList<>(); for(int i = 0; i < list.size(); i++) { int len = list.get(i); //断言型返回一个boolean类型 if(pre.test(len)) { li.add(len); } } return li; } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。