Java方法引用介绍

方法引用

1.方法引用可以理解为把已经有的方法拿过来用,当作函数式接口中抽象方法的方法体

2.方法引用的使用条件:

  • 引用处必须是函数式接口
  • 被引用的方法必须已经存在
  • 被引用方法的形参和返回值需要跟抽象方法保持一致(可以自动装箱的也可以认为一致)
  • 被引用方法的功能要满足当前需求

3.方法引用符:两个冒号 ::

4.方法引用的分类:

  • 引用静态方法
  • 引用成员方法
  • 引用构造方法
  • 其它调用方法

引用静态方法

1.使用说明:

格式:类名::静态方法

范例:Integer::parseInt

比如在需要将集合中的数字字符串转换成int类型时:

假定已经创建了集合list,且其中有"1","2","3","4","5"

list.stream.map(Integer::parseInt).collector(Collectors.toList());

第一,Function接口是函数式接口;

第二,Function接口中的方法apply形参是String,返回值是Integer,而Integer的parseInt的形参类型也是String,返回值类型是int,int和Integer存在自动装箱,因此也符合;

第三,想要实现的功能和parseInt是一样的,因此可以使用。

其中的 Integer::parseInt 就相当于函数式接口Fuction中抽象方法的方法体。

引用成员方法

1.使用说明:

格式:对象::成员方法

1)其他类:其它类对象::方法名(可以用已创建对象的变量名::方法名,也可以直接new 类名()::方法名)

2)本类:this::方法名(静态方法中是没有this的,因此如果在静态方法中,需要new 本类类名()::方法名)

3)父类:super::方法名(静态方法中是没有super的,因此如果在静态方法中,需要new 父类类名()::方法名)

在使用之前一定要确定方法已经存在,同时方法满足返回值,形参的数据类型与函数式接口中方法的返回值、形参的数据类型一致,以及方法的功能是满足需求的

引用构造方法

1.使用说明:

格式:类名::new

范例:Student::new

引用构造方法时,可以认为返回值就是创建的对象的类型。

有必要的时候可以重写一个构造方法,将形参对应上,把功能写成需要的内容。

其它调用方法

1.使用类名引用成员方法。

2.引用数组的构造方法。

使用类名引用成员方法

1.使用说明:

格式:类名::成员方法

范例:String::substring

一般会在Stream流中实现Function接口时使用到。

注意:使用类名引用成员方法时,需要根据当前使用数据的类型去引用对应的方法,不能引用其它类的成员方法。因此在不少情况下需要在自建类中书写相关方法。

该类引用有独有的方法引用规则,跟上述三种不完全一样:

1)需要有函数式接口;

2)被引用的方法必须已经存在;

3)被引用方法的形参,需要跟抽象方法的第二个形参到最后一个形参保持一致,返回值需要保持一致;

4)被引用方法的功能需要满足当前的需求。

此时需要解释一下抽象方法:

第一个参数:表示被引用方法的调用者,决定了可以引用那些类中的方法。在Stream流中,                        第一个参数一般都表示流里面的每一个数据,假设流里面的数据是字符串,                            那么使用这种方式进行方法引用,只能引用String这个类中的方法。

第二个参数到最后一个参数:跟被引用方法的形参保持一致,如果没有第二个参数,说明被                                                 引用的方法按需要是无参的成员方法。

引用数组的构造方法

1.使用说明:

格式:数据类型[]::new

范例:int[]::new

一般会在Stream流中的toArray方法中使用到。

细节:数组的类型,需要和流中数据的类型保持一致。

        /*
            练习1:集合中存储一些字符串的数据,比如:张三,23
                  收集到Student类型的数组当中,使用方法引用完成。

            练习2:创建集合添加学生对象,学生对象属性:name,age
                  只获取姓名并放到数组当中,使用方法引用完成。

            练习3:创建集合添加学生对象,学生对象属性:name,age
                  把姓名和年龄拼接成:张三-23的字符串,并放到数组当中(使用方法引用完成)
         */

        // 练习1
        // 创建集合并添加数据
        ArrayList<String> list1 = new ArrayList<>();
        Collections.addAll(list1,"张无忌,15","张三丰,50","张强,20","诸葛亮,34","周瑜,32");

        // 使用Stream流,将类型转换
        Student[] students1 = list1.stream()
                .map(Student::new)
                .toArray(Student[]::new);
        System.out.println(Arrays.toString(students1));

        // 练习2
        // 创建集合并添加数据
        ArrayList<Student> list2 = new ArrayList<>();
        for (Student student : students1) {
            list2.add(student);
        }

        // 使用Stream流,将姓名放到一个数组中
        String[] students2 = list2.stream()
                .map(Student::getName)
                .toArray(String[]::new);
        System.out.println(Arrays.toString(students2));

        // 练习3
        // 创建集合并添加数据
        ArrayList<Student> list3 = new ArrayList<>();
        for (Student student : students1) {
            list3.add(student);
        }

        // 使用Stream流,将姓名和年龄拼接成对应格式,并放到数组中
        String[] students3 = list3.stream()
                .map(Student::pinJie)
                .toArray(String[]::new);
        System.out.println(Arrays.toString(students3));

        // Student中的方法pinJie
        public String pinJie(Student this){
            return this.name + "-" + this.age;
        }

<think>好的,我现在需要详细回答用户关于Java方法引用的类型和使用示例的问题。首先,用户已经提供了之前的对话历史和我的回复,其中我已经给出过方法引用的类型和示例,但现在用户再次询问类似的问题,可能是希望获得更全面或更详细的解释。我需要确保回答结构清晰,符合用户的要求,同时参考之前的引用内容,但避免重复。 首先,用户的问题是关于Java方法引用的类型及使用示例。根据之前的回答,我提到了三种适用的方法引用类型:静态方法引用、实例方法引用和类的任意对象方法引用,以及不适用的情况。现在需要再次整理这些内容,可能需要更详细的分点说明,并补充更多示例或细节。 同时,用户提供的引用内容中有三个引用,其中引用1和2涉及方法引用的基本概念和类型,引用3则是关于弱引用的内容,这可能与当前问题无关,但需要确认是否有必要提及。根据用户的问题,主要关注方法引用,因此可以忽略引用3,专注于引用1和2的内容。 接下来,需要确保回答符合用户给出的格式要求:使用中文,行内数学表达式用$...$,独立公式用$$...$$,但这里可能用不上数学公式。需要生成相关问题,并在回答末尾添加引用标识。同时,用户希望回答结构清晰,逐步解决问题,保证真实可靠。 回顾之前的回答,结构分为几个部分:匹配性分析、可应用类型及示例、不可应用类型及原因、综合应用场景、关键规则总结、常见问题解答。现在可能需要采用类似的框架,但避免完全重复,可以调整结构或添加更多细节。 需要确保涵盖四种方法引用类型,因为引用2提到四种类型,而之前的回答只提到三种适用的类型。可能用户提到的四种类型包括:静态方法引用、实例方法引用(特定对象)、实例方法引用(任意对象)、构造方法引用。但在之前的分析中,构造方法引用被列为不适用的情况,因为接口要求返回int而构造方法返回对象。因此,需要明确说明四种类型,但指出哪些适用于当前的接口示例。 可能需要调整结构,先介绍Java方法引用的四种类型,然后结合用户提供的hello接口示例,说明哪些适用,哪些不适用,并给出示例。此外,引用1和2中的内容需要被合理引用,例如在解释概念时引用[^1][^2]。 需要注意用户可能存在的疑问点,例如为什么某些类型不适用,或者如何在实际中选择合适的方法引用类型。同时,要确保示例代码正确,语法无误,符合Java规范,特别是方法引用的使用场景。 最后,生成相关问题,确保问题与主题相关,能够帮助用户进一步理解方法引用的其他方面,例如性能考虑、与其他Java特性的结合等。 总结思考步骤: 1. 确定用户需求:详细的方法引用类型及示例,特别是与hello接口相关的应用。 2. 参考之前的回答,但避免重复,补充更多细节或不同的示例。 3. 结合引用1和2的内容,确保概念正确,引用适当。 4. 结构安排:先介绍四种方法引用类型,再分别说明适用性,给出示例,最后总结规则和常见问题。 5. 检查是否有遗漏的类型或使用场景,确保全面性。 6. 生成相关问题,促进深入学习。</think>--- ### Java方法引用类型详解与使用示例 --- #### 一、方法引用基础概念 Java方法引用是Lambda表达式的简化形式,通过`类名::方法名`或`对象::方法名`直接引用已有方法[^1][^2]。它要求目标方法的**参数列表**和**返回类型**必须与函数式接口的抽象方法匹配。以下是四种核心类型及具体应用场景: --- #### 二、方法引用类型与示例 ##### 1. **静态方法引用** **语法**:`类名::静态方法名` **适用场景**:直接调用类的静态方法 **示例**: ```java // 函数式接口 @FunctionalInterface interface Calculator { int compute(int a, int b); } public class Main { public static int add(int a, int b) { return a + b; } public static void main(String[] args) { // 静态方法引用 Calculator adder = Main::add; System.out.println(adder.compute(3, 5)); // 输出8 } } ``` *关键点*: - `Main::add`匹配`Calculator`接口的`int compute(int, int)`签名 - 替代Lambda:`(a, b) -> Main.add(a, b)`[^1] --- ##### 2. **特定对象的实例方法引用** **语法**:`对象实例::实例方法名` **适用场景**:绑定到具体对象的实例方法 **示例**: ```java class Multiplier { public int multiply(int a, int b) { return a * b; } } public class Main { public static void main(String[] args) { Multiplier obj = new Multiplier(); // 实例方法引用 Calculator multiplier = obj::multiply; System.out.println(multiplier.compute(4, 5)); // 输出20 } } ``` *关键点*: - 方法调用依赖于特定对象的状态(若对象无状态,可复用) - 等效Lambda:`(a, b) -> obj.multiply(a, b)`[^2] --- ##### 3. **类的任意对象实例方法引用** **语法**:`类名::实例方法名` **适用场景**:方法第一个参数隐式作为方法调用者 **示例**: ```java class StringComparator { public int compareIgnoreCase(String s1, String s2) { return s1.compareToIgnoreCase(s2); } } public class Main { public static void main(String[] args) { // 类的实例方法引用 Comparator<String> comparator = String::compareToIgnoreCase; System.out.println(comparator.compare("Java", "JAVA")); // 输出0 } } ``` *关键点*: - 实际调用逻辑:`(s1, s2) -> s1.compareToIgnoreCase(s2)` - 第一个参数`s1`成为`compareToIgnoreCase`的调用者 --- ##### 4. **构造方法引用** **语法**:`类名::new` **适用场景**:创建新对象(需与函数式接口返回类型匹配) **示例**: ```java @FunctionalInterface interface Factory<T> { T create(String name); } class Product { private String name; public Product(String name) { this.name = name; } } public class Main { public static void main(String[] args) { // 构造方法引用 Factory<Product> factory = Product::new; Product p = factory.create("Laptop"); } } ``` *关键点*: - 接口`Factory`的`create`方法返回`Product`,与构造方法一致 - 参数`String name`需与构造方法参数匹配[^2] --- #### 三、`hello`接口的适用性分析 用户定义的`hello`接口: ```java public interface hello { int hello(int a, int b); } ``` **适用类型**: 1. **静态方法引用**(需静态方法接受两个`int`参数,返回`int`) 2. **实例方法引用**(需实例方法接受两个`int`参数,返回`int`) 3. **类的任意对象实例方法引用**(需第一个参数为隐式调用者,如`IntWrapper`示例) **不适用类型**: - **构造方法引用**:`hello`要求返回`int`,而构造方法返回对象实例 --- #### 四、综合应用示例 ```java public class Demo { public static void main(String[] args) { // 静态方法引用(Math工具类) hello power = Math::pow; // 错误!Math.pow返回double,与int不兼容 hello safeAdd = Math::addExact; // 正确,返回int // 实例方法引用(自定义类) class CustomOps { public int xor(int a, int b) { return a ^ b; } } CustomOps ops = new CustomOps(); hello xorOperator = ops::xor; System.out.println(xorOperator.hello(5, 3)); // 输出6 } } ``` *注意事项*: - 类型严格匹配:`Math::pow`因返回`double`不兼容`int`会编译报错 - 上下文推断:编译器根据`hello`接口自动选择匹配的方法[^1] --- #### 五、方法引用与Lambda的选择 | 场景 | 方法引用 | Lambda表达式 | |---------------------|----------|--------------| | 直接调用现有方法 | ✔️ | ✔️ | | 需要复杂逻辑 | ❌ | ✔️ | | 代码简洁性优先 | ✔️ | ❌ | | 需要捕获外部变量 | ❌ | ✔️ | --- #### 六、常见问题解答 **Q1: 方法引用是否会增加性能开销?** 无额外开销,编译器会将方法引用转换为等效的Lambda形式,最终生成相同的字节码。 **Q2: 如何处理方法重载的情况?** 编译器根据目标接口的类型推断具体方法。例如: ```java class OverloadDemo { public static int calc(int a) { return a; } public static int calc(int a, int b) { return a + b; } } hello ref = OverloadDemo::calc; // 自动匹配两个参数的calc方法 ``` **Q3: 是否支持私有方法引用?** 仅在类内部通过实例引用访问私有方法,静态私有方法无法直接引用。 --- #### 七、最佳实践 1. **优先选择方法引用**:提升代码可读性(如`String::compareToIgnoreCase`比Lambda更直观) 2. **避免过度简化**:若Lambda逻辑复杂(如包含条件判断),保留Lambda形式 3. **注意空指针**:实例方法引用需确保对象非空(如`obj::method`中`obj`不为`null`) ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值