文章目录
一、接口默认方法和静态方法
接口中可以使用default
关键字,来实现方法。
// NumInterface.java
public interface NumInterface
{
// 定义一个抽象方法
int toDoubleDouble(int number);
// 默认方法
default int toDouble(int number) {
return number * 2;
}
}
接口中实现的默认方法,它的实现类可以直接调用。
// Num.java
public class Num implements NumInterface
{
@Override
public int toDoubleDouble(int number) {
return toDouble(number) * 2;
}
}
// Main.java
public static void main(String[] args) {
NumInterface num = new Num(){
};
System.out.println(num.toDouble(3)); // 输出6
}
当然,实现类也能重写接口中的默认方法,调用时依据”就近原则“,即实现类如果重写了,就先调用实现类的,否则调用最近接口的。
接口中还能实现静态方法:
// NumInterface.java
public interface NumInterface
{
// 抽象方法
int toDoubleDouble(int number);
// 默认方法
default int toDouble(int number) {
return number * 2;
}
// 静态方法
static void sayHello() {
System.out.println("Hello");
}
}
二、Lambda表达式
例如对一个用户列表进行排序,排序规则是他们的年龄(假设都存在),那么以往的代码是这么写的:
ArrayList<User> userList = new ArrayList<>();
userList.add(user1);
userList.add(user2);
...
userList.sort(new Comparator<User>()
{
@Override
public int compare(User o1, User o2) {
return o1.getAge() - o2.getAge();
}
});
上面的代码传入了一个匿名内部类,来实现Comparator接口中的compare方法。
现在就能简化这一个操作。
userList.sort((User a, User b) -> {
return a.getAge() - b.getAge();
});
对于只包含一行方法的代码块,我们可以省略大括号和return
甚至能更加简化:
userList.sort((a, b) -> a.getAge() - b.getAge());
使用Lambda表达式的前提是,接口必须为函数式接口。
三、函数式接口
函数式接口,就是只包含一个需要被实现的抽象方法的接口。
也就是说:接口中可以定义其他的方法,比如默认方法、抽象方法、甚至是equals
、toString
这些不需要被实现的方法(Object
类中实现了),只需要保证只有一个抽象方法需要被实现就行。
为了保证一个接口明确的被定义为一个函数式接口,可以在接口上添加注解:@FunctionalInterface
,如果接口中添加了其他的抽象方法,就会报错。
// NumInterface.java
@FunctionalInterface
public interface NumInterface
{
// 定义一个抽象方法
int toDoubleDouble(int number);
// 默认方法
default int toDouble(int number) {
return number * 2;
}
}
上面的代码,即使去掉
@FunctionalInterface
也是好使的,它仅仅是一种约束而已。
四、方法引用
String::compareToIgnoreCase
这种“对象/类名 + 双冒号 + 方法名”格式就是方法引用。
所谓方法引用,是指如果某个方法签名和接口的恰好一致,就可以直接传入方法引用。
例如这一段代码:
public static void main(String[] args) {
String[] array = new String[] {
"Apple", "Orange", "Banana", "Lemon" };
Arrays.sort(array, Main::cmp);
System.out.println(String.join(", ", array));
}
static int cmp(String s1, String s2) {
return s1.compareTo(s2);
}
本来Arrays.sort()
中的第二个参数是传入的int compare(String, String)
这种类型的,而cmp
方法的参数列表、返回类型和需求一致。因此,两者的方法签名一致,可以直接把方法名作为lambda表达式传入:
Arrays.sort(array, Main::cmp);
当然,里面也可传入String::compareTo
,而compareTo方法中只有一个参数。这是因为方法参数中含有一个隐藏的this
,每次调用compareTo
时,实际上是调用public static int compareTo(this, String o)
,所以也是可行的。
方法引用的四个种类:
- 静态方法引用
格式:类名::静态方法名
上面的例子Main:cmp
就是静态方法引用,和静态方法调用相比,就是把.
换成了::
例如:
Math::pow 等效于 (x, y) -> Math.pow(x, y)
String::valueOf 等效于 (x) -> String.valueOf(x)
- 实例方法引用
格式:实例名::实例中的方法名
例如:
public static void main(String[] args) {
List<String> list = Arrays.asList("hello", "kitty");
list.forEach(new Main()::printWithSpace);
}
private void printWithSpace(String s) {
for (int i = 0 ; i < s.length() ; i++) {
System.out.print(s.charAt(i) + " ");
}
}
- 实例的超类方法引用
格式:super::超类中的方法名
这里的super指的是当前类的父类。
例如:
public