@functionInterface lambda语法没有泛型信息,求高手

新手上路,请多包涵

题目描述

自定义的FunctionInterface,lambda 写法反射获取方法时泛型信息被擦除,直接实现该接口可以正确获得泛型类型。

题目来源及自己的思路

Java function

猜测1:lambda写法的直接实现了 CFunction<T> 顶级接口,造成缺失子接口PersonFunction的泛型信息

相关代码

package com.example.test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;

public class TestLambda {

    public static void main(String[] args) throws Exception {

        invoke(personFunctionImpl());
        invoke(personFunction());
    }

    public static void invoke(PersonFunction personFunction)
            throws InvocationTargetException, IllegalAccessException {
        Class<? extends PersonFunction> lambdaClass = personFunction.getClass();
        System.out.println("methods: " + Arrays.toString(lambdaClass.getDeclaredMethods()));
        Method accept;
        try {
            accept = lambdaClass.getMethod("accept", Person.class);
            accept.invoke(personFunction, new Person("java"));
        } catch (NoSuchMethodException e) {
            System.out.println(e);
        }
    }

    public static PersonFunction personFunction() {
        return System.out::println;
    }

    public static PersonFunction personFunctionImpl() {
        return new PersonFunction() {
            @Override
            public void accept(Person person) {
                System.out.println(person);
            }
        };
    }
}
@FunctionalInterface
interface CFunction <T> {
    void accept(T t);
}

class Person {
    String name;

    public Person(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return name;
    }
}

interface PersonFunction extends CFunction<Person> {}

你期待的结果是什么?实际看到的错误信息又是什么?

运行日志:

methods: [public void com.example.test.TestLambda$1.accept(com.example.test.Person), public void com.example.test.TestLambda$1.accept(java.lang.Object)]
java
methods: [public void com.example.test.TestLambda$$Lambda$1/303563356.accept(java.lang.Object), private static com.example.test.PersonFunction com.example.test.TestLambda$$Lambda$1/303563356.get$Lambda(java.io.PrintStream)]
java.lang.NoSuchMethodException: com.example.test.TestLambda$$Lambda$1/303563356.accept(com.example.test.Person)

测试代码输出可以看到实现类有具体类型的方法,以及泛型接口的Object参数方法,lambda表达式实现的方法只有一个 Object参数的方法。

理论上两种写法应该是同一种行为,为何会有如此大的差距,给编写框架造成很大困扰。有没有好的实践方式求大佬指点。

阅读 2.7k
2 个回答

其实有点没太看懂题主想要表达的意思,如果仅仅是为了获取泛型类型,那你这种情况就是Type体系下的ParameterizedType,也就是一种参数化类型

那获取就很简单直接了

Type[] genericInterfaces = lambdaClass.getInterfaces()[0].getGenericInterfaces();
// 因为这里确认就是ParameterizedType,就不用类型判断了
ParameterizedType parameterizedType = ParameterizedType.class.cast(genericInterface);
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
Type actualTypeArgument = actualTypeArguments[0];
Class personClass = Class.class.cast(actualTypeArgument);

拿不到
lambda只是编译时受到泛型约束,运行时会被擦掉,于是只有一个参数是 Object 的方法
实现接口,实现方法,则是真的“有”一个有具体类型的方法,但是因为擦除的问题,还是能看到参数是Object 的方法

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题