Java interface
概述
- JDK : 1.8
总结
- Java 中类是单继承多实现;Java 中接口是多继承无实现1
- Java 接口中的方法默认访问限制为public 无需声明2
- 接口默认方法
- default 关键字修饰
- 接口中可以增加方法实现
- 接口静态方法
- static 关键字修饰
- 接口中必须添加方法实现
- 类优先原则3
- 当一个类继承父类又实现接口时,若后两者方法名相同,则优先继承父类中的同名方法
- 实现同名方法冲突问题3
- 如果实现两个同名方法的接口,需要手动声明默认实现哪个接口中的方法
- 函数式接口
- 仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法
一、接口方法
1. default 接口中默认方法
/**
* 接口默认方法
* 背景:
* 1. JDK 1.7 之前接口中只能定义抽象方法,即只定义而不能实现
* 2. JDK 1.8 开始接口中方法通过default关键字修饰,可以添加默认实现
* 优势:
* 1. 接口中的默认方法,子类可以不用实现父类中的默认方法而直接调用
* 2. 同一个接口有多个子类,可以简化大量重复代码;便于项目维护
*/
public interface DefaultService {
Integer getNumberOne();
default Integer getNumberTwo(){
return 2 ;
}
default Integer getNumberThree(){
return 3 ;
}
}
public class DefaultServiceImpl implements DefaultService {
@Override
public Integer getNumberOne() {
return 1;
}
// 无需实现 getNumberTwo()
@Override
public Integer getNumberThree() {
return 33 ;
}
}
public class DefaultServiceTest {
public static void main(String[] args) {
System.out.println("begin");
DefaultService defaultService = new DefaultServiceImpl();
// DefaultServiceImpl 实现类中的方法
System.out.println(defaultService.getNumberOne());
// 输出 1
// DefaultServiceImpl 没有实现父类中的默认方法
System.out.println(defaultService.getNumberTwo());
// 输出 2
// DefaultServiceImpl 覆盖父类中的方法实现
System.out.println(defaultService.getNumberThree());
// 输出 33
}
}
2. static 接口中的静态方法
/**
* 静态接口方法
* 必须要有方法实现
*/
public interface StaticService {
static void test(){
System.out.println("StaticService");
}
}
public class StaticServiceTest {
public static void main(String[] args) {
StaticService.test();
}
}
二、接口原则
1. 类优先原则
public interface DefaultParentService {
default Integer getNumberOne(){
return 2 ;
}
}
/**
* 继承与实现类中均有 getNumberOne() 方法
*/
public class DefaultParentServiceImpl extends DefaultServiceImpl implements DefaultParentService {
}
public class DefaultParentServiceTest {
public static void main(String[] args) {
DefaultParentServiceImpl service = new DefaultParentServiceImpl() ;
// 此时输出的是 DefaultServiceImpl 中 getNumberOne() 的返回值 1
// 而非 DefaultParentService 中 getNumberOne() 的返回值 2
// 类优先原则,优先继承父类中的同名方法
System.out.println(service.getNumberOne());
// 输出 1
}
}
2. 实现同名方法冲突问题
/**
* 默认接口方法同时实现多个接口
* 如果实现两个同名方法的接口,需要手动声明默认实现哪个接口中的方法
*/
public class DefaultDoubleServiceImpl implements DefaultParentService, DefaultService {
@Override
public Integer getNumberOne() {
return 11;
}
}
三、函数式接口4
- 定义:由一个抽象方法及若干默认方法、静态方法组成的接口
- 验证:
@FunctionalInterface
注解用于验证当前接口是否为函数式接口 - 类型:
- 自定义函数式接口
- 常用的函数式接口
接口名称 | 接口方法 | 接口功能 | 接口入参 | 接口出参 | 组合方法 |
---|---|---|---|---|---|
Supplier | get | 产生新的对象 | 无 | 无 | 无 |
Consumer | accept | 消费对象信息 | 有 | 无 | andThen |
Predicate | test | 对象类型判断 | 有 | boolean | and / or / nevigate |
Function | apply | 对象类型转换 | T | V | andThen |
- Lambda 表达式语法:参数列表 -> 函数体5
- 调用:
- 声明接口对象 = Lambda 表达式
- 接口作为成员方法入参,调用成为方法时传入 Lambda 表达式
- 方法引用:特殊的 Lambda 表达式
- 对象::成员方法
- 类::静态方法
- super::成员方法
- this::成员方法
- 类::构造方法 new
- 示例
-
自定义无参数函数式接口:
() -> Lambda
// 接口声明:包含一个抽象方法 // 接口验证:如果接口不符合函数式接口定义编译时提示 @FunctionalInterface public interface PersonalNoArgsService { void print(); // 可以同时包含若干个默认方法、静态方法 default void printLine(){ System.out.println(); } static void printLines(){ System.out.println(); } }
public class PersonalNoArgsServiceTest { public static void main(String[] args) { // 声明函数式接口对象 = Lambda 表达式 PersonalNoArgsService test = () -> System.out.println("a") ; test.print(); // 函数式接口作为成员方法入参 // 启动延迟执行的作用,"" + "a" 的拼接会延迟到执行 print() 时 print(() -> System.out.println(""+"a")); } private static void print(PersonalNoArgsService personalNoArgsService){ personalNoArgsService.print(); } }
-
自定义有参数函数式接口:
- 只有一行方法:
(a,b) -> Lambda(a,b)
- 包含多行方法:
(a,b) -> {return (a,b);}
@FunctionalInterface public interface PersonalHasArgsService<T,V> { V function(T t,V v); }
public class PersonalHasArgsServiceTest { public static void main(String[] args) { // Lambda 赋值 PersonalHasArgsService service = (a,b) -> a.toString() + b.toString() ; System.out.println(service.function("a", 1)); service = (a,b) -> Integer.parseInt(a.toString()) + Integer.parseInt(b.toString()) ; System.out.println(service.function("1", "1")); // 方法体 service = (a,b) -> { if(null != a) { System.out.println(a.toString()); return a.toString(); }else { System.out.println(b.toString()); return b.toString(); } }; service.function(null,1); } }
- 只有一行方法:
-
Supplier 函数式接口
public class SupplierServiceTest { public static void main(String[] args) { // 无参数 System.out.println(getObject(() -> "abc")); System.out.println(getObject(() -> 1)); // 产生新的对象 getObject(SupplierServiceTest::new); } private static <T> T getObject(Supplier<T> supplier){ return supplier.get(); } }
-
Consumer 函数式接口
public class ConsumerServiceTest { public static void main(String[] args) { // 对象类型消费 // 接口无返回值 consume(1,a -> System.out.println(a*a+a) ); } private static <T> void consume(T t ,Consumer<T> consumer){ consumer.accept(t); } }
-
Predicate 函数式接口
public class PredicateServiceTest { public static void main(String[] args) { // 集合中有一个符合条件返回 true System.out.println(predicate(Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8), a -> a.stream().anyMatch(b -> b >= 9))); } private static <T> boolean predicate(T t ,Predicate<T> predicate){ return predicate.test(t); } }
-
Funcation 函数式接口
public class FunctionServicesTest { public static void main(String[] args) { // 数据类型转换 System.out.println(function("1", Integer::parseInt)); } public static Integer function(String t ,Function<String,Integer> function){ return function.apply(t); } }
-
Lambda 函数体内部对外部引用的是值而非变量
private static void streamMatch(){ // 两个集合取交集 final List<Integer> integerList = Arrays.asList(1, 2, 3, 4, 5); boolean b = Arrays.asList(1, 2, 3, 4, 5, 6, 7, 8).stream().anyMatch(a -> integerList.contains(a)); System.out.println(b); // Lambda 表达式内部使用的外部参数,引用值而非变量,相当于 final 修饰 // 当变量重新赋值时会提示便于错误 // 如果 Lambda 表达式内部使用某个变量的值,而该变量后续需要重新赋值,需要对该值进行拷贝,避免异常 }
-