当前位置: 首页 > article >正文

匿名内部类与Lambda表达式不理解点

一、匿名内部类与Lambda表达式

// 传统匿名内部类实现 Runnable
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("Hello from anonymous class!");
    }
}).start();请你把语句拆分出来

代码思路

原始代码使用了传统的匿名内部类来实现 Runnable 接口并创建一个新线程。拆分的过程就是把匿名内部类提取出来,创建一个具体的类来实现 Runnable 接口,然后使用这个类的实例来创建线程。

拆分后的代码

// 定义一个具体的类,实现 Runnable 接口
class MyRunnable implements Runnable {
    // 实现 Runnable 接口的 run 方法
    @Override
    public void run() {
        // 线程要执行的任务,打印信息
        System.out.println("Hello from anonymous class!");
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建 MyRunnable 类的实例
        MyRunnable myRunnable = new MyRunnable();
        // 使用 MyRunnable 实例创建一个新的线程
        Thread thread = new Thread(myRunnable);
        // 启动线程
        thread.start();
    }
}

代码解释

  1. MyRunnable 类

    • 定义了一个名为 MyRunnable 的类,该类实现了 Runnable 接口。
    • 实现了 Runnable 接口的 run 方法,在该方法中打印了一条信息。
  2. Main 类

    • 在 main 方法中,首先创建了 MyRunnable 类的一个实例 myRunnable
    • 然后使用 myRunnable 实例创建了一个新的 Thread 对象 thread
    • 最后调用 thread 的 start 方法启动线程,线程启动后会执行 MyRunnable 类的 run 方法。

二、匿名内部类语法结构

1.基本概念

匿名内部类是没有名字的局部内部类,它可以扩展一个类或者实现一个接口。通常用于创建只使用一次的类实例。

// 继承一个类的匿名内部类
父类类型 变量名 = new 父类构造器(参数列表) {
    // 匿名内部类的类体部分
    // 可以重写父类的方法
    @Override
    public void 方法名() {
        // 方法实现
    }
};

// 实现一个接口的匿名内部类
接口类型 变量名 = new 接口名() {
    // 匿名内部类的类体部分
    // 必须实现接口的所有抽象方法
    @Override
    public void 方法名() {
        // 方法实现
    }
};

2.继承一个类的匿名内部类

// 定义一个父类
class Animal {
    public void makeSound() {
        System.out.println("动物发出声音");
    }
}

public class AnonymousClassExample {
    public static void main(String[] args) {
        // 使用匿名内部类继承 Animal 类
        Animal dog = new Animal() {
            @Override
            public void makeSound() {
                System.out.println("汪汪汪");
            }
        };
        dog.makeSound();
    }
}

⑴.关键点解析:

  1. 匿名内部类的本质

    • new Animal() { ... } 并不是直接实例化父类 Animal,而是定义了一个继承 Animal 的匿名子类。

    • 这个匿名子类重写了 makeSound() 方法,实现了"汪汪汪"的输出。

  2. 多态的体现

    • 变量 dog 的编译时类型是 Animal(父类),但运行时类型是匿名子类。

    • 通过父类引用调用方法时,实际执行的是子类重写后的方法(动态绑定)。

⑵.完整写法

// 定义一个父类
class Animal {
    public void makeSound() {
        System.out.println("动物发出声音");
    }
}

// 定义一个子类继承 Animal 类
class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("汪汪汪");
    }
}

public class NormalClassExample {
    public static void main(String[] args) {
        // 创建 Dog 类的实例
        Animal dog = new Dog();
        dog.makeSound();
    }
}

3.实现一个接口的匿名内部类

interface MyInterface {
    void doSomething();
}

public class Main {
    public static void main(String[] args) {
        // 使用匿名内部类实现接口
        MyInterface obj = new MyInterface() {
            @Override
            public void doSomething() {
                System.out.println("Doing something...");
            }
        };
        // 调用接口方法
        obj.doSomething();
    }
}
// 定义接口
interface MyInterface {
    void doSomething();
}

// 定义一个具体的类来实现 MyInterface 接口
class MyInterfaceImpl implements MyInterface {
    // 实现接口中的抽象方法
    @Override
    public void doSomething() {
        System.out.println("Doing something...");
    }
}

public class Main {
    public static void main(String[] args) {
        // 创建实现类的实例
        MyInterface obj = new MyInterfaceImpl();
        // 调用接口方法
        obj.doSomething();
    }
}

三、Lambda 表达式是什么?

Lambda 表达式是匿名函数的简写形式,它可以替代传统的匿名内部类,用于实现函数式接口(只有一个抽象方法的接口)。Lambda 的核心目的是:

  • 简化代码:减少模板代码(如匿名类的冗余语法)。

  • 支持函数式编程:将函数作为参数传递,或直接定义行为。

四、Lambda和匿名内部类的拆分理解

public class LambdaTest02 {

    public static void main(String[] args) {

        // 匿名内部类方式(匿名内部类可以是一个抽象类)
        LambdaTest02.test(new Animal() {
            @Override
            public void run() {
                System.out.println("Animal run....");
            }
        });

        // 匿名内部类
        LambdaTest02.doFly(new Flyable() {
            @Override
            public void run() {
                System.out.println("run.....");
            }

            @Override
            public void fly() {
                System.out.println("fly.....");
            }
        });
    }

    public static void test(Animal a){
        a.run();
    }

    public static void doFly(Flyable f){
        f.fly();
        f.run();
    }
}

abstract class Animal{
    public abstract void run();
}

interface Flyable {
    void run();
    void fly();
}

拆分:

1. 定义 Animal 抽象类

创建一个名为 Animal.java 的文件,内容如下:

// Animal.java
public abstract class Animal {
    public abstract void run();
}

2. 定义 Flyable 接口

创建一个名为 Flyable.java 的文件,内容如下:

// Flyable.java
public interface Flyable {
    void run();
    void fly();
}

3. 创建继承 Animal 抽象类的具体类

创建一个名为 ConcreteAnimal.java 的文件,内容如下:

// ConcreteAnimal.java
public class ConcreteAnimal extends Animal {
    @Override
    public void run() {
        System.out.println("Animal run....");
    }
}

4. 创建实现 Flyable 接口的具体类

创建一个名为 ConcreteFlyable.java 的文件,内容如下:

// ConcreteFlyable.java
public class ConcreteFlyable implements Flyable {
    @Override
    public void run() {
        System.out.println("run.....");
    }

    @Override
    public void fly() {
        System.out.println("fly.....");
    }
}

5. 主类 LambdaTest02

创建一个名为 LambdaTest02.java 的文件,内容如下:

// LambdaTest02.java
public class LambdaTest02 {
    public static void main(String[] args) {
        // 创建 ConcreteAnimal 类的实例
        ConcreteAnimal concreteAnimal = new ConcreteAnimal();
        // 调用 test 方法
        LambdaTest02.test(concreteAnimal);

        // 创建 ConcreteFlyable 类的实例
        ConcreteFlyable concreteFlyable = new ConcreteFlyable();
        // 调用 doFly 方法
        LambdaTest02.doFly(concreteFlyable);
    }

    public static void test(Animal a) {
        a.run();
    }

    public static void doFly(Flyable f) {
        f.fly();
        f.run();
    }
}

五、Lambda和匿名内部类的拆分理解

List<Integer> list = Arrays.asList(3, 6, 1, 7, 2, 5, 4);
Collections.sort(list, new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2 - o1;
    }
});
System.out.println("排序后:" + list);

拆分

import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;

// 定义一个具体的类来实现 Comparator 接口
// 该类用于对 Integer 类型的元素进行降序排序
class IntegerDescComparator implements Comparator<Integer> {
    // 实现 compare 方法,用于比较两个 Integer 对象
    // 根据 o2 - o1 的结果来决定元素的顺序
    // 如果结果大于 0,o2 排在 o1 前面;如果结果小于 0,o1 排在 o2 前面;如果结果等于 0,两者顺序不变
    @Override
    public int compare(Integer o1, Integer o2) {
        return o2 - o1;
    }
}

public class SortExample {
    public static void main(String[] args) {
        // 创建一个包含整数的列表
        // Arrays.asList 方法用于将一组元素转换为 List 集合
        List<Integer> list = Arrays.asList(3, 6, 1, 7, 2, 5, 4);

        // 创建 IntegerDescComparator 类的实例
        // 该实例将作为排序时的比较器
        IntegerDescComparator comparator = new IntegerDescComparator();

        // 使用 Collections.sort 方法对列表进行排序
        // 传入列表和比较器作为参数,列表将按照比较器定义的规则进行排序
        Collections.sort(list, comparator);

        // 打印排序后的列表
        System.out.println("排序后:" + list);
    }
}

五、四个基本的函数式接口

名字接口名对应的抽象方法
消费Consumer<T>void accept(T t);
生产Supplier<T>T get();
转换Function<T, R>R apply(T t);
判断Predicate<T>boolean test(T t);

1.Iterable 接口的 forEach 方法

Iterable 接口是 Java 集合框架中的基础接口,Collection 接口继承自 Iterable 接口,因此像 List、Set 等集合类都可以使用 forEach 方法。

语法

default void forEach(Consumer<? super T> action)

这里的 action 是一个 Consumer 函数式接口的实例,它定义了对集合中每个元素要执行的操作。

import java.util.ArrayList;
import java.util.List;

public class IterableForEachExample {
    public static void main(String[] args) {
        List<String> fruits = new ArrayList<>();
        fruits.add("Apple");
        fruits.add("Banana");
        fruits.add("Cherry");

        // 使用 Lambda 表达式
        fruits.forEach(fruit -> System.out.println(fruit));

        // 使用方法引用
        fruits.forEach(System.out::println);
    }
}

在上述示例中,首先创建了一个 List 集合,然后分别使用 Lambda 表达式和方法引用两种方式调用 forEach 方法对集合中的每个元素进行打印操作。

2. Map 接口的 forEach 方法

Map 接口提供了 forEach 方法,用于遍历 Map 中的键值对。

default void forEach(BiConsumer<? super K,? super V> action)

这里的 action 是一个 BiConsumer 函数式接口的实例,它接受两个参数,分别是 Map 中的键和值,定义了对每个键值对要执行的操作。

import java.util.HashMap;
import java.util.Map;

public class MapForEachExample {
    public static void main(String[] args) {
        Map<String, Integer> scores = new HashMap<>();
        scores.put("Alice", 85);
        scores.put("Bob", 90);
        scores.put("Charlie", 78);

        // 使用 Lambda 表达式
        scores.forEach((name, score) -> System.out.println(name + ": " + score));
    }
}

在这个示例中,创建了一个 Map 集合,然后使用 Lambda 表达式调用 forEach 方法,对 Map 中的每个键值对进行打印操作。

3.Consumer<T>

Consumer<T> 是一个消费型接口,它接受一个输入参数 T,并且不返回任何结果。其抽象方法是 void accept(T t)。

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class ConsumerExample {
    public static void main(String[] args) {
        // 创建一个包含整数的列表
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);

        // 使用 Consumer 打印列表中的每个元素
        Consumer<Integer> printer = num -> System.out.println(num);
        numbers.forEach(printer);

        // 也可以直接在 forEach 中使用 Lambda 表达式
        numbers.forEach(num -> System.out.println(num * 2));
    }
}

在这个示例中,我们创建了一个 Consumer 实例 printer,它接受一个整数并将其打印出来。然后使用 forEach 方法遍历列表,并将 printer 作为参数传递给它。另外,我们还直接在 forEach 方法中使用 Lambda 表达式来打印每个元素的两倍。

⑴.不使用Lambda和匿名内部类

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

// 定义一个实现 Consumer 接口的类,用于打印整数
class IntegerPrinter implements Consumer<Integer> {
    @Override
    public void accept(Integer num) {
        System.out.println(num);
    }
}

// 定义一个实现 Consumer 接口的类,用于打印整数的两倍
class IntegerDoublePrinter implements Consumer<Integer> {
    @Override
    public void accept(Integer num) {
        System.out.println(num * 2);
    }
}

public class ConsumerExample {
    public static void main(String[] args) {
        // 创建一个包含整数的列表
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);

        // 创建 IntegerPrinter 类的实例
        IntegerPrinter printer = new IntegerPrinter();
        // 调用 forEach 方法,将 printer 作为参数传入,遍历列表并打印每个元素
        numbers.forEach(printer);

        // 创建 IntegerDoublePrinter 类的实例
        IntegerDoublePrinter doublePrinter = new IntegerDoublePrinter();
        // 调用 forEach 方法,将 doublePrinter 作为参数传入,遍历列表并打印每个元素的两倍
        numbers.forEach(doublePrinter);
    }
}

运行结果:

⑵.不使用 Lambda 表达式,使用匿名内部类

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

public class ConsumerExample {
    public static void main(String[] args) {
        // 创建一个包含整数的列表
        List<Integer> numbers = new ArrayList<>();
        // 向列表中添加元素 1
        numbers.add(1);
        // 向列表中添加元素 2
        numbers.add(2);
        // 向列表中添加元素 3
        numbers.add(3);
        // 向列表中添加元素 4
        numbers.add(4);

        // 创建一个实现了 Consumer 接口的匿名内部类实例,用于打印元素
        Consumer<Integer> printer = new Consumer<Integer>() {
            @Override
            public void accept(Integer num) {
                // 打印传入的整数
                System.out.println(num);
            }
        };
        // 调用 forEach 方法,将 printer 作为参数传入,遍历列表并打印每个元素
        numbers.forEach(printer);

        // 创建另一个实现了 Consumer 接口的匿名内部类实例,用于打印元素的两倍
        Consumer<Integer> doublePrinter = new Consumer<Integer>() {
            @Override
            public void accept(Integer num) {
                // 打印传入整数的两倍
                System.out.println(num * 2);
            }
        };
        // 调用 forEach 方法,将 doublePrinter 作为参数传入,遍历列表并打印每个元素的两倍
        numbers.forEach(doublePrinter);
    }
}

4.Supplier<T>

Supplier<T> 是一个供应型接口,它不接受任何参数,但返回一个结果 T。其抽象方法是 T get()。

import java.util.function.Supplier;

public class SupplierExample {
    public static void main(String[] args) {
        // 使用 Supplier 生成一个随机数
        Supplier<Double> randomSupplier = () -> Math.random();
        double randomNumber = randomSupplier.get();
        System.out.println("随机数: " + randomNumber);
    }
}

运行结果:

⑴.不使用Lambda和匿名内部类

import java.util.function.Supplier;

// 定义一个具体的类来实现 Supplier 接口
class RandomNumberSupplier implements Supplier<Double> {
    // 实现 Supplier 接口的 get 方法
    @Override
    public Double get() {
        return Math.random();
    }
}

public class SupplierExample {
    public static void main(String[] args) {
        // 创建 RandomNumberSupplier 类的实例
        RandomNumberSupplier randomSupplier = new RandomNumberSupplier();
        // 调用 get 方法获取随机数
        double randomNumber = randomSupplier.get();
        // 打印生成的随机数
        System.out.println("随机数: " + randomNumber);
    }
}

⑵.不使用 Lambda 表达式,使用匿名内部类

import java.util.function.Supplier;

public class SupplierExample {
    public static void main(String[] args) {
        // 使用匿名内部类实现 Supplier 接口
        Supplier<Double> randomSupplier = new Supplier<Double>() {
            @Override
            public Double get() {
                return Math.random();
            }
        };

        double randomNumber = randomSupplier.get();
        System.out.println("随机数: " + randomNumber);
    }
}

5.Function<T, R>

Function<T, R> 是一个函数型接口,它接受一个输入参数 T,并返回一个结果 R。其抽象方法是 R apply(T t)。

import java.util.function.Function;

public class FunctionExample {
    public static void main(String[] args) {
        // 使用 Function 将字符串转换为整数
        Function<String, Integer> stringToInt = str -> Integer.parseInt(str);
        String input = "123";
        int result = stringToInt.apply(input);
        System.out.println("转换结果: " + result);
    }
}

运行结果:

⑴.不使用Lambda和匿名内部类

// 导入 java.util.function 包中的 Function 接口,该接口是 Java 8 引入的函数式接口,用于表示接受一个参数并产生结果的函数
import java.util.function.Function;

// 定义一个具体的类 StringToIntFunction,该类实现了 Function 接口,指定泛型参数为 <String, Integer>
// 表示该函数接受一个 String 类型的参数,返回一个 Integer 类型的结果
class StringToIntFunction implements Function<String, Integer> {
    // 重写 Function 接口的 apply 方法,该方法用于执行具体的函数逻辑
    // 接收一个 String 类型的参数 str,并将其转换为 Integer 类型的值
    @Override
    public Integer apply(String str) {
        // 使用 Integer 类的 parseInt 方法将字符串 str 转换为整数
        return Integer.parseInt(str);
    }
}

// 定义一个公共类 FunctionExample,包含程序的入口方法 main
public class FunctionExample {
    // 程序的入口方法,Java 程序从这里开始执行
    public static void main(String[] args) {
        // 创建 StringToIntFunction 类的一个实例,用于后续的字符串到整数的转换操作
        StringToIntFunction stringToInt = new StringToIntFunction();
        // 定义一个字符串变量 input,初始值为 "123",该字符串将作为转换的输入
        String input = "123";
        // 调用 StringToIntFunction 实例的 apply 方法,将 input 字符串转换为整数
        // 并将结果存储在 int 类型的变量 result 中
        int result = stringToInt.apply(input);
        // 使用 System.out.println 方法输出转换结果,输出格式为 "转换结果: " 加上转换后的整数
        System.out.println("转换结果: " + result);
    }
}

⑵.不使用 Lambda 表达式,使用匿名内部类

import java.util.function.Function;

public class FunctionExample {
    public static void main(String[] args) {
        // 使用匿名内部类实现 Function 接口
        Function<String, Integer> stringToInt = new Function<String, Integer>() {
            @Override
            public Integer apply(String str) {
                return Integer.parseInt(str);
            }
        };
        String input = "123";
        // 调用 apply 方法进行转换
        int result = stringToInt.apply(input);
        System.out.println("转换结果: " + result);
    }
}

6.Predicate<T>

Predicate<T> 是一个断言型接口,它接受一个输入参数 T,并返回一个布尔值。其抽象方法是 boolean test(T t)。

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class PredicateExample {
    public static void main(String[] args) {
        // 创建一个包含整数的列表
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);

        // 使用 Predicate 过滤出偶数
        Predicate<Integer> isEven = num -> num % 2 == 0;
        for (Integer num : numbers) {
            if (isEven.test(num)) {
                System.out.println(num);
            }
        }
    }
}

运行结果:

⑴.不使用Lambda和匿名内部类

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

// 定义一个具体的类实现 Predicate 接口
class EvenNumberPredicate implements Predicate<Integer> {
    // 实现 test 方法,判断是否为偶数
    @Override
    public boolean test(Integer num) {
        return num % 2 == 0;
    }
}

public class PredicateExample {
    public static void main(String[] args) {
        // 创建一个包含整数的列表
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);

        // 创建 EvenNumberPredicate 类的实例
        EvenNumberPredicate isEven = new EvenNumberPredicate();

        // 遍历列表,使用 Predicate 过滤出偶数
        for (Integer num : numbers) {
            if (isEven.test(num)) {
                System.out.println(num);
            }
        }
    }
}

⑵.不使用 Lambda 表达式,使用匿名内部类

import java.util.ArrayList;
import java.util.List;
import java.util.function.Predicate;

public class PredicateExample {
    public static void main(String[] args) {
        // 创建一个包含整数的列表
        List<Integer> numbers = new ArrayList<>();
        numbers.add(1);
        numbers.add(2);
        numbers.add(3);
        numbers.add(4);

        // 使用匿名内部类实现 Predicate 接口
        Predicate<Integer> isEven = new Predicate<Integer>() {
            // 实现 test 方法,判断是否为偶数
            @Override
            public boolean test(Integer num) {
                return num % 2 == 0;
            }
        };

        // 遍历列表,使用 Predicate 过滤出偶数
        for (Integer num : numbers) {
            if (isEven.test(num)) {
                System.out.println(num);
            }
        }
    }
}


http://www.kler.cn/a/569668.html

相关文章:

  • 第34周:文献阅读
  • 基于SSM实现的bbs论坛系统功能实现九
  • git管理的项目 发布时有收费版/免费版/客户定制版,如何管理分支,通过merge(合并) 还是 cherry-pick(挑拣) 引入更新的代码?
  • 25考研数二408部分时间统计
  • 【漫话机器学习系列】109.线性无关(Linearly Independent)
  • DeepSeek 助力 Vue3 开发:打造丝滑的弹性布局(Flexbox)
  • Netty介绍
  • HTML——<head>标签中可放入的标签
  • 计算机毕业设计SpringBoot+Vue.js线上辅导班系统(源码+文档+PPT+讲解)
  • 线上服务器的文件下载到本地Windows电脑
  • Golang | 每日一练 (4)
  • 【uniapp】在UniApp中实现持久化存储:安卓--生成写入数据为jsontxt
  • 【tplink】校园网接路由器如何单独登录自己的账号,wan-lan和lan-lan区别
  • 从神经元到大语言模型及其应用
  • React + TypeScript AI Agent开发实战
  • docker高级
  • SpringSecurity基于JWT实现Token的处理
  • 基于SpringBoot的“青少年心理健康教育网站”的设计与实现(源码+数据库+文档+PPT)
  • 实体机器人识别虚拟环境中障碍物
  • 25环境工程研究生复试面试问题汇总 环境工程专业知识问题很全! 环境工程复试全流程攻略 环境工程考研复试调剂真题汇总