Jdk8 新特性 接口的默认方法以及函数式接口

专题1—— Jdk8 新特性 接口的默认方式以及函数式接口

Jdk8之前接口

首先让我们来看一下Jdk8之前的接口定义

An interface in Jdk is similar to a class, but the body of an interface can include only abstract methods and final fields (constants). A class implements an interface by providing code for each method declared by the interface

通过上面一段话我们可以看出Java对于接口的定义仅仅是为了定义类的规范。由于Java不支持多继承。而接口可以提供多继承的大多数好处,同时避免多重继承的复杂性和低效性。

/**
 * Jdk8以前的接口定义
 *
 */
public interface Calculator {
	//常数
	int l=11;
	//抽象方法
	String getfun();
	//嵌套类型默认private
	class Nested {

	}

}

Jdk 8的接口变化

首先让我们来看一下接口的最新定义What is an Interface,里面提到:

In the Jdk programming language, an interface is a reference type, similar to a class, that can contain only constants, method signatures, default methods, static methods, and nested types. Method bodies exist only for default methods and static methods. Interfaces cannot be instantiated—they can only be implemented by classes or extended by other interfaces.

既然Jdk8以前的接口我们已经知道了,那么Jdk 8的接口又是为了解决什么问题呢?
这一切根源来自于一个2010年的一个问题开始:如果接口中有个方法的定义是可以确定的(实现该接口的类必须重复实现该方法),如何更优雅的设计这个接口?
文中提到了许多折中的方法:通过接口里的静态类、借助工具类的静态方法等。
但到了jdk8也就是2014年,这个问题被解决了:接口引入了default关键字和静态方法(public static method),接口中通过default修饰的方法可以有方法体,实现具体功能。这在接口的最新定义中也有提出。

/**
 * Jdk 8 的接口定义
 *
 */
public interface Calculator {
	//常数
	int l=11;
	//抽象方法
	String getfun();
	//嵌套类型
	class Nested 
	}
	 default public void newSkill(){
	        System.out.print("实现了这个接口的类可以不实现这个方法");
	    }
	public static void newStaticSkiil(){
	        System.out.print("实现了这个接口的类可以不实现这个静态方法");  
	    }
}

函数式接口

既然我们谈到了接口,不妨再来看一下Jdk8的又一新特性—函数式接口。”函数式接口”是指仅仅只包含一个抽象方法的接口。为了确保你的接口一定达到这个要求,你只需要给你的接口添加上@ FunctionalInterface注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。

@FunctionalInterface
public interface Calculator<F, T> {
	//常数
	int l=11;

	//嵌套类型
	class Nested {

	}
	 default public void newSkill(){
	        System.out.print("实现了这个接口的类可以不实现这个方法");
	    }
	public static void newStaticSkiil(){
	        System.out.print("实现了这个接口的类可以不实现这个静态方法");  
	    }
	T convert(F from);
}

可以看到该接口还可以实现默认方法和静态方法(这两个方法不算抽象方法)。而由于函数式接口的定义,从而Jdk8另一特性由此而省Lambda表达式。

Lambda表达式

在Jdk8以前的版本中我们接口方法是怎样使用的呢?下面为完成一个计算器的加法运算的实现

Integer sum=new Calculator<Integer, Integer,Integer>() {
 			@Override
 			public Integer add(Integer param1, Integer param2) {
 				return param1+param2;
 			}
     	 }.add(11, 12);
System.out.println(sum);//23

我们发现要实现两个整数的相加我们使用了一个匿名对象 然后实现其中的add方法最后再使用其中的add方法。这样相当麻烦。
在Java 8 中你就没必要使用这种传统的匿名对象的方式了,Java 8提供了更简洁的语法,lambda表达式

Calculator<Integer , Integer,Integer> calculator=
(param1,param2)->param1+param2;
    	 System.out.println(calculator.add(11, 12));//23

方法引用

既然提及Lambda表达式,那么作为Jdk8中另一个精简代码的新特性就必须要再来谈一谈了。
Jdk8允许你用::关键字来传递方法或者构造函数引用具体使用方法为

步骤1:定义一个函数式接口

步骤2:定义一个满足函数式接口抽象方法要求的方法

步骤3:使用对步骤2中定义的方法引用实例化函数式接口的实例。

//step1
@FunctionalInterface
interface Supplier<T> {
    T get();
}
 //step2
class Car {
   
    public static Car create(final Supplier<Car> supplier) {
        return supplier.get();
    }
 
    public static void collide(final Car car) {
        System.out.println("Collided " + car.toString());
    }
 
    public void follow(final Car another) {
        System.out.println("Following the " + another.toString());
    }
 
    public void repair() {
        System.out.println("Repaired " + this.toString());
    }
}
//step3
public class Test {

	 public static void main(String args[]){
		 //构造器引用:它的语法是Class::new,或者更一般的Class< T >::new实例如下:
		 final Car car = Car.create( Car::new );
		 final List< Car > cars = Arrays.asList( car );
		 //静态方法引用:它的语法是Class::static_method
		 cars.forEach( Car::collide );
		 //特定类的任意对象的方法引用:它的语法是Class::method
		 cars.forEach( Car::repair );
		 //特定对象的方法引用:它的语法是instance::method
		 final Car police = Car.create( Car::new );
		 cars.forEach( police::follow );
	   }
}
posted @ 2019-10-15 15:49  考研小黑  阅读(6)  评论(0编辑  收藏  举报