匿名内部类、函数式接口和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();
	}
}

posted @ 2022-05-15 23:53  qtyanan  阅读(105)  评论(0编辑  收藏  举报