匿名内部类、函数式接口和Lambda
目录
匿名内部类,函数式接口和Lambda
1. 匿名内部类
1.1 接口 和 abstract 类复习
接口 interface
成员变量缺省属性: public static final
成员方法缺省属性: public abstract
abstract 修饰的方法可以定义在哪些结构中???
abstract 修饰类,一个是 interface 接口
一个 非 abstract 修饰的类 继承 abstract 类有什么要求???
一个 非 abstract 修饰的类 遵从 接口有什么要求???
非 abstract 修饰的类必须实现 abstract 类内 或者 interface 接口内的所有 abstract 修饰方法
package com.qfedu.a_ait;
interface A {
void test();
}
class TypeA implements A {
@Override
public void test() {
System.out.println("遵从接口A必须实现的方法");
}
}
abstract class BaseType {
public abstract void testMethod();
}
class TypeB extends BaseType {
@Override
public void testMethod() {
System.out.println("非 abstract 类继承 abstract 修饰类要求实现的方法");
}
}
1.2 匿名内部类分析和操作实现
package com.qfedu.a_ait;
interface B {
void test();
}
/*
TypeC 类名所代表的的内容是 类大括号里面的所有内容。
类大括号所有内容看做是一个类的【本体】
对于 TypeC 类对应的包含内容,实际上是在【实现】接口 B 要求的方法。
请问类名重要吗???
当前类的主要目的是为了按照接口的要求,实现接口规定的方法,类名称呼不重要
【重点】
在于实现接口中的方法!!!
类名不重要
是否可以
1. 保留必要的继承/遵从关系
2. 完成方法体实现
3. 可以实例化对象
4. 满足方法的调用操作
*/
class TypeC implements B {
@Override
public void test() {
System.out.println("TypeC 类遵从接口B 实现 test方法");
}
}
public class Demo2 {
public static void main(String[] args) {
new TypeC().test();
/*
* 看一下 匿名内部类 基本操作方式
* B b 接口 B 对应的引用数据类型变量,可以存储 B 接口实现类对象地址
* new B()
* 【注意】这里没有实例化 B 接口对象,而是在描述以下内容
* 1. new 需要在内存的堆区申请必要的数据空间,用于实例化对象使用,同时对当前数据空间进行擦除
* 2. B() 看上去是一个 接口 B 的构造方法,实际上是在告知编译器,当前匿名内部类遵从的接口是 B 接口
* 利用构造方法基本要求的格式形式 new + 构造方法。
* new B(); 实例化对象,同时告知编译器当前实例化对象数据类型是遵从接口 B 的
* 【注意】没有类名!!!
* {} 里面的内容,就是一个遵从接口 B 实现类必须完成的方法内容,从这里也看出匿名类遵从的接口类型是 B 接口
*
* 实例化对象赋值给接口 B 引用数据类型变量,方便后期
*/
B b = new B() {
@Override
public void test() {
System.out.println("匿名内部类实现方法,实例化对象赋值给接口的引用数据类型变量,方便方法调用");
}
};
b.test();
/*
* 略微高阶一丢丢的方法
*
* 王·渣男·某平
* 匿名内部类的匿名对象,直接调用方法
*/
new B() {
@Override
public void test() {
System.out.println("匿名内部类的匿名对象,直接调用方法");
}
}.test();
testInnerType(new TypeC());
/*
* 匿名内部类的匿名对象直接作为方法的参数!!!
* JDK 1.8 之前流行操作!!!
*/
testInnerType(new B() {
@Override
public void test() {
System.out.println("匿名内部类的匿名对象直接作为方法的参数!!!");
}
});
}
/**
* 当前方法所需参数是 接口 B 类型,实际上可以传入的参数是接口 B 的实现类对象
*
* @param b B 接口类型,实际参数是接口B的实现类
*/
public static void testInnerType(B b) {
b.test();
}
/*
interface USB {
void connect();
}
当前方法所需参数是 USB 接口的实现类, USB 设备。
public static void useUseInterface(USB usb) {
usb.connect();
}
*/
}
2. 函数式接口 【JDK 1.8 新特征】
2.1 基本语法
JDK 1.8 版本及其以上版本有效!!!
语法要求
1. 使用注解 @FunctionalInterface 告知编译器当前接口是一个【函数式接口】
2. 在函数式接口中,有且只允许出现一个尚未完成(No method body)的方法。
3. 允许使用 default 关键字修饰方法,可以存在多个有方法体的方法[非必要]
package com.qfedu.b_fi;
/*
* @FunctionalInterface
* 格式检查注解,要求当前接口中有且只有一个尚未完成(No Method Body)的方法 ,缺省属性为 public abstract 修饰方法
* 必须有一个尚未完成(No Method Body)的方法
*
* 函数式接口是一个对于接口类型约束操作,按照正常的接口操作使用。
*/
@FunctionalInterface
interface A {
void test();
// void test2();
default void testDefault() {
System.out.println("default 修饰默认方法,JDK 1.8 新特征");
}
}
class TypeA implements A {
@Override
public void test() {
System.out.println("正常操作");
}
}
public class Demo1 {
public static void main(String[] args) {
new TypeA().test();
new A() {
@Override
public void test() {
System.out.println("匿名内部类的匿名对象,直接调用方法");
}
}.test();
}
}
2.2 应知应会 JDK1.8 常用函数式接口
// 消费接口
interface Consumer<T> {
void accept(T t)
}
// 生产接口
interface Supplier<T> {
T get();
}
// 转换接口
interface Function<T, R> {
R apply(T t);
}
// 判断接口
interface Predicate<T> {
boolean test(T t);
}
// 比较接口
interface Comparator<T> {
int compare(T o1, T o2)
}
3. Lambda表达式
3.1 基本概述
Lambda 表达式是 JDK1.8 及其以上版本允许的技术点,类似于
Objective-C Block代码块
Python JS 匿名函数
核心目标:
提高代码的执行效率!!!重点关注方法内容实现
技术使用前提:
1. 常用于方法中!!!
2. 要求方法参数是一个接口类型。
3. 方法参数接口类型必须是一个函数式接口 @FunctionalInterface
四类:
无参数无返回
有参数有返回
有参数无返回
无参数有返回
3.2 无参数无返回 Lambda
需要定义一个接口,并且接口中有且只有一个未完成的方法!!!就一个函数式接口,最好使用 @FunctionalInterface 开启检查
@FunctionalInterface
interface A {
void test();
}
准备一个方法,方法参数是接口 A 类型
public static void testLambda(A a) {
a.test();
}
package com.qfedu.c_lambda;
/*
* 1. 完成 接口 A 实现类 通过该 实例化对象作为方法参数调用执行 testLambda
* 2. 直接使用 接口 A 的匿名内部类的匿名对象作为 testLambda 方法参数
* 3. Lambda 表达式操作
*/
@FunctionalInterface
interface A {
void test();
}
class TypeA implements A {
@Override
public void test() {
System.out.println("实现类 TypeA 实现完成 test 方法");
}
}
public class Demo1 {
/*
* JVM 执行 main 方法
*/
public static void main(String[] args) {
// 方式一
testLambda(new TypeA());
// 方式二 JDK 1.8 之前
testLambda(new A() {
@Override
public void test() {
System.out.println("匿名内部类的匿名对象,直接作为方法的参数");
}
});
/*
* 【重点】方式三 Lambda表达式
* () 对应当前 接口 A 中的 test 方法没有参数
* -> Java Lambda 表达式语法规则
* {} 表示需要完成的方法体内容
* 当前 接口A 中的方法 void test() 没有返回值,所以在 Lambda 表达式对应
* 大括号中无需return关键字返回数据
*/
testLambda(() -> {
System.out.println("Lambda表达式直接作为方法的参数");
});
// Lambda 表达式有且只有一行代码,可以省略大括号
testLambda(() -> System.out.println("如果Lambda表达式只有一行,可以省略大括号"));
}
public static void testLambda(A a) {
a.test();
}
}