匿名内部类
-
匿名类是指没有类名的内部类,必须在创建时使用 new 语句来声明类。其语法形式如下:
父类名|接口名 对象名 = new 父类构造器(参数列表)|实现接口(){ // 方法重写 @Override public void method() { // 执行语句 } };//分号结尾
-
使用匿名内部类的条件是:必须继承一个父类或实现一个接口,因为类没有名字,要创建该对象的引用的话,则必须继承一个父类或者实现一个接口,然后通过父类引用匿名内部类实例,再通过多态特性调用方法。
-
特点:
- 定义类的时候直接实例化,则该类不可能是抽象类,也不能拥有任何抽象方法。
- 类没有名字,则不存在类变量,类方法,类初始化块,也没有构造函数。
-
代码
public interface Animal { void play(); void eat(); } abstract class Person { abstract void play(); abstract void eat(); } class AnimalTest{ public static void main(String[] args) { //接口 Animal animal = new Animal() { @Override public void play() { System.out.println("小狗在玩耍!!"); } public void eat() { System.out.println("小狗在吃东西!"); } }; animal.eat(); animal.play(); //抽象类 Person person = new Person() { @Override void play() { System.out.println("人在玩耍!!"); } @Override void eat() { System.out.println("人在吃东西!"); } }; person.eat(); person.play(); } }
-
由上面的例子可以看出,只要一个类是抽象的或是一个接口,那么其子类中的方法都可以使用匿名内部类来实现。最常用的情况就是在多线程的实现上,因为要实现多线程必须继承Thread类或是继承Runnable接口
函数式接口
-
只包含一个抽象方法的接口,称为函数式接口。
-
我们可以在一个接口上使用
@FunctionalInterface
注解,这样做可以检查它是否是一个函数式接口。同时 javadoc 也会包含一条声明,说明这个接口是一个函数式接口。 -
函数式接口:只有一个方法的接口。只要是函数式接口,都可以通过匿名函数来实现。
四大核心函数式接口
函数式接口 | 参数类型 | 返回类型 | 用途 |
---|---|---|---|
Consumer :消费型接口 | T | void | 类型为T的对象应用操作,方法:void accept(T t) |
Supplier:供给型接口 | 无 | T | 返回类型为T的对象,方法:T get() |
Function<T, R>:函数型接口 | T | R | 对T对象操作,返回R对象.方法:R apply(T t) |
Predicate:断定型接口 | T | boolean | T对象是否满足某约束,返回boolean. |
//消费型接口 传入T 无返回
@FunctionalInterface
public interface Consumer<T> {
void accept(T t);
//默认方法
default Consumer<T> andThen(Consumer<? super T> after) {
Objects.requireNonNull(after);
return (T t) -> { accept(t); after.accept(t); };
}
}
//供给型接口 不传参数,返回T
@FunctionalInterface
public interface Supplier<T> {
T get();
}
//函数型接口 传入T 返回R
@FunctionalInterface
public interface Function<T, R> {
R apply(T t);
}
//断定型接口 传入T 返回boolean
@FunctionalInterface
public interface Predicate<T> {
boolean test(T t);
//静态方法
static <T> Predicate<T> isEqual(Object targetRef) {
return (null == targetRef)? Objects::isNull: object -> targetRef.equals(object);
}
}
- 接口复习,Java8之前,接口中只能声明常量和抽象方法;Java8中,接口中可以声明默认方法和静态方法。
Lambda 表达式
-
Lambda 是一个匿名函数,我们可以把 Lambda 表达式理解为是一段可以传递的代码(将代码像数据一样进行传递)。
-
使用labmda函数重写方法的前提是实现的接口中有且仅有一个需要重写的抽象方法。
-
Lambda表达式的本质:作为函数式接口的实例。即可以通过 Lambda 表达式来创建该接口的对象。只要一个对象是函数式接口的实例,那么该对象就可以用Lambda表达式来表示。
-
Lambda 表达式的操作符为 “->” , 该操作符被称为 Lambda 操作符或箭头操作符。它将 Lambda 分为两个部分:
左侧:指定了 Lambda 表达式需要的参数列表
**右侧:**指定了 Lambda 体,是抽象方法的实现逻辑,也即Lambda 表达式要执行的功能。
-
口诀为:拷贝小括号,写死右箭头,落地大括号。
方法引用
- 当要传递给Lambda体的操作,已经有实现的方法了,可以使用方法引用!
- 方法引用可以看做是Lambda表达式深层次的表达。换句话说,方法引用就是Lambda表达式,也就是函数式接口的一个实例,通过方法的名字来指向一个方法,可以认为是Lambda表达式的一个语法糖。
- 要求:实现接口的抽象方法的参数列表和返回值类型,必须与方法引用的方法的参数列表和返回值类型保持一致!
- 格式:使用操作符 “::” 将类(或对象) 与 方法名分隔开来。有如下三种主要使用情况:
- 对象::实例方法名
- 类::静态方法名
- 类::实例方法名
@Test
public void testFunction(){
//消费型接口使用 lambda例子 一个参数
Consumer<String> consumer = (str) -> {
System.out.println("str = " + str);
};
consumer.accept("消费型接口");
//两个参数的
Comparator<Integer> comparator = (o1,o2) -> {return Integer.compare(o1,o2);};
System.out.println(comparator.compare(5,10));
//方法引用
Consumer<String> con = System.out::println;
con.accept("方法引用");
}