如何用反射获取函数对象的类型参数?

时间:2018-06-13 20:14:26

标签: java reflection lambda

我有一个用例,使用反射来获取Function对象 1 的参数和返回值类型会很有用。

但是我发现遵循由lambda表达式导致的函数对象的令人惊讶的行为:该对象没有具有特定类型的import java.lang.reflect.Type; import java.lang.reflect.Method; import java.util.function.Function; public class Trying { public static void main(String[] args) { Function<Integer, Double> lambda = i -> i.doubleValue(); Function<Integer, Double> methodRef = Integer::doubleValue; Function<Integer, Double> anon = new Function<Integer, Double>() { @Override public Double apply(Integer i) { return i.doubleValue(); } }; printType("lambda", lambda); printType("methodRef", methodRef); printType("anon", anon); } private static void printType(String name, Function<?, ?> f) { System.out.println("### " + name); System.out.println("super: " + f.getClass().getSuperclass().getSimpleName()); for (Type i : f.getClass().getGenericInterfaces()) { System.out.println("interface: " + i); } for (Method m : f.getClass().getDeclaredMethods()) { System.out.println("name: " + m.getName() + ", bridge: " + m.isBridge() + ", arg type: " + m.getParameterTypes()[0].getSimpleName() + ", return type: " + m.getReturnType().getSimpleName()); } System.out.println(); } } 方法。

示例代码:

### methodRef
super: Object
interface: interface java.util.function.Function
name: apply, bridge: false, arg type: Object, return type: Object

### lambda
super: Object
interface: interface java.util.function.Function
name: apply, bridge: false, arg type: Object, return type: Object

### anon
super: Object
interface: java.util.function.Function<java.lang.Integer, java.lang.Double>
name: apply, bridge: false, arg type: Integer, return type: Double
name: apply, bridge: true, arg type: Object, return type: Object

此代码打印以下内容:

testreturn.py
  1. 有没有办法解决这个问题并使用反射来获取函数对象的具体类型?
  2. 语言是指定的行为还是依赖于实现?
  3. 为什么lambda和方法引用对象以这种方式运行?
  4. 1:我想使用此信息为数据绑定API创建默认转换器。

1 个答案:

答案 0 :(得分:0)

首先,我要感谢您发布一个非常完整的代码片段,只需要进行一些修改即可编译和运行。它让我们更容易。

我的简短回答是不要做。编写依赖于这种反射工作的代码会有问题...可能会有一些技巧让它像上面所示使用内部类一样工作,但它最终会咬你,所以我的建议是远离这种做法。

相反,您可以创建一个“类型化”函数子类,使用这样的有效Java惯用语来解决问题:

df.isnull().values.sum()

然后使用代码实例化这些函数的方式如下:

abstract class TypedFunction<T, U> implements Function<T, U> {
  final Class<T> inClass;
  final Class<U> outClass;

  TypedFunction(final Class<T> inClass, final Class<U> outClass) {
    this.inClass = inClass;
    this.outClass = outClass;
  }

  static <TT, UU> TypedFunction<TT, UU> make(
          final Class<TT> inClass, 
          final Class<UU> outClass,
          final Function<? super TT, ? extends UU> func) {
    return new TypedFunction<TT, UU>(inClass, outClass) {
            @Override
            UU apply(final TT in) {
              return func.apply(in);
            }
    };
  }
}

反过来,用于解析in和out类的反射代码只是访问传递的TypedFunction<Integer, Double> lambda = TypedFunction.make(Integer.class, Double.class, i -> i.doubleValue()); TypedFunction<Integer, Double> methodRef = TypedFunction.make(Integer.class, Double.class, Integer::doubleValue); TypedFunction<Integer, Double> anon = TypedFunction.make(Integer.class, Double.class, new Function<Integer, Double>() { @Override public Double apply(Integer i) { return i.doubleValue(); } }; TypedFunction<Integer, Double> anonSimple = new TypedFunction<Integer, Double>(Integer.class, Double.class) { @Override public Double apply(Integer i) { return i.doubleValue(); } }; 上的inClassoutClass字段。当然,如果这些类型恰好是通用类型,它会返回“原始”类型而不是通用形式,但我认为我们应该离开它。

如果包含TypedFunction<?, ?>Integer.class似乎很乏味,你可以创建一个二阶函数,其构造函数接受Double.classT类引用,它本身就是一个函数来自基础U到其Function<T, U>包装版本。