Java interface

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

  1. 定义:由一个抽象方法及若干默认方法、静态方法组成的接口
  2. 验证:@FunctionalInterface 注解用于验证当前接口是否为函数式接口
  3. 类型:
    1. 自定义函数式接口
    2. 常用的函数式接口
接口名称接口方法接口功能接口入参接口出参组合方法
Supplierget产生新的对象
Consumeraccept消费对象信息andThen
Predicatetest对象类型判断booleanand / or / nevigate
Functionapply对象类型转换TVandThen
  1. Lambda 表达式语法:参数列表 -> 函数体5
  2. 调用:
    1. 声明接口对象 = Lambda 表达式
    2. 接口作为成员方法入参,调用成为方法时传入 Lambda 表达式
    3. 方法引用:特殊的 Lambda 表达式
      1. 对象::成员方法
      2. 类::静态方法
      3. super::成员方法
      4. this::成员方法
      5. 类::构造方法 new
  3. 示例
    1. 自定义无参数函数式接口:() -> 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();
          }
      }
      
      
    2. 自定义有参数函数式接口:

      1. 只有一行方法:(a,b) -> Lambda(a,b)
      2. 包含多行方法:(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);
          }
      }
      
    3. 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();
          }
      }
      
    4. 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);
          }
      }
      
    5. 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);
          }
      }
      
    6. 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);
          }
      }
      
      
    7. 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 表达式内部使用某个变量的值,而该变量后续需要重新赋值,需要对该值进行拷贝,避免异常
          }
      

  1. java中接口是否可以继承多个接口? ↩︎

  2. Java接口中的成员变量默认为(public、static、final)、方法为(public、abstract) ↩︎

  3. JDK1.8新特性总结 ↩︎ ↩︎

  4. jdk1.8新特性:函数式接口、方法引用、函数式编程、常用函数式接口 ↩︎

  5. Java 8系列之Lambda表达式 ↩︎

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值