简体   繁体   English

方法参考的通用功能接口的方法签名

[英]Method signature of generic Functional Interface of Method References

Suppose you have a Method 假设你有一个方法

void m(String s) {} 

by using the new Method References you can create a Consumer from it 通过使用新的方法引用,您可以从中创建Consumer

Consumer<String> c = Class::m;

If you now take a look at the class of the created Consumer via reflection you will see that its only declared method is 如果您现在通过反射查看创建的Consumer的类,您将看到它唯一声明的方法是

void accept(Object)

If had created the Consumer the old way by creating an anonymous inner class 如果通过创建匿名内部类以旧方式创建了Consumer

Consumer<String> c = new Consumer<String>() {
    public void accept(String s){}
}

there would be the bridge method void accept(Object) as well as void accept(String) . 会有bridge方法void accept(Object)以及void accept(String)

now lets say we have to pass this consumer around and thereby loose its generic type. 现在让我们说我们必须通过这个消费者,从而松开它的通用类型。 If you had an implementation of Consumer<String> rather than a Lambda expression you could get it back by looking using relfection to access its methods. 如果你有一个Consumer<String>的实现而不是Lambda表达式,你可以通过查看使用relfection访问它的方法来获取它。 Since the consumer created via method reference does only have the general method this wont work. 由于通过方法引用创建的使用者只有通用方法,因此不起作用。 Is there a way to get the parameter type of the consumer created by method reference? 有没有办法获取方法引用创建的使用者的参数类型?

Sorry I didn't see this question earlier. 对不起,我之前没有看到这个问题。 If you're running on an Oracle or OpenJDK you can resolve generic type information from lambdas or method references using TypeTools . 如果您在Oracle或OpenJDK上运行,则可以使用TypeTools从lambda或方法引用中解析泛型类型信息。 Ex: 例如:

Consumer<String> c = this::m;
Class<?> type = TypeResolver.resolveRawArgument(Consumer.class, c.getClass());
assert type == String.class;

Pretty simple. 很简单。 Tell your friends :) 告诉你的朋友 :)

Invocation of a raw Consumer (without a generic type) always results in a warning. 调用原始使用者(没有通用类型)总是会产生警告。 You simply should not do that as you do not know the type. 你不应该这样做,因为你不知道类型。 Raw types do not have a type. 原始类型没有类型。 That didn't change with Java 8. Java 8没有改变。

The interface Consumer has a generic type but you do not know that at runtime. 接口Consumer具有泛型类型,但您不知道它在运行时。 Even not for lambdas. 甚至不是为了lambdas。 Some classes might actually have the information, but that wont help you. 有些类可能实际上有信息,但这对你没有帮助。 If you actually need to know the type then simply create such an interface. 如果您确实需要知道类型,那么只需创建这样的接口。

  @FunctionalInterface
  public static interface StringConsumer {
    void consume(String s);
  }

  public static void main(String[] args) throws Throwable {
    StringConsumer sc = System.out::println;
    sc.consume("Hello");
    Method m = StringConsumer.class.getMethods()[0]; // only one: "consume"
    m.invoke(sc, m.getParameters()[0].getType().getSimpleName());
  }

Here's some example code and output to see what methods there are and how they can and can not ne invoked: 下面是一些示例代码和输出,以查看有哪些方法以及如何调用它们:

package com.example.foo;

import static java.util.Arrays.asList;

import java.lang.reflect.Method;
import java.util.function.Consumer;

public class SomeClass {
  @FunctionalInterface
  static interface FI {
    public void m(String s);
  }

  static final class MyRegularClass {
    @SuppressWarnings("static-method")
    public void m(String s) {
      System.out.println("MyRegularClass: " + s);
    };
  }

  static final class MyGenericClass<T> {
    public void m(T s) {
      System.out.println("MyGenericClass: " + s);
    };
  }

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

    Consumer<String> c1 = (s) -> {
      System.out.println("Lambda: " + s);
    };
    Consumer<String> c2 = new Consumer<String>() {
      public void accept(String s) {
        System.out.println("Anonym: " + s);
      }
    };
    Consumer<String> c3 = new MyRegularClass()::m;
    Consumer<String> c4 = new MyGenericClass<String>()::m;

    for (Consumer<String> c : asList(c1, c2, c3, c4)) {
      c.accept("regular invocation of accept(String)");

      for (Method m : c.getClass().getDeclaredMethods()) {
        String n = m.getName() + "(" + m.getParameters()[0].getType().getSimpleName() + ")";
        try {
          m.invoke(c, n);
        } catch (Exception e) {
          System.out.println("Did not accept String: " + n + " => " + e);
        }
        try {
          m.setAccessible(true);
          m.invoke(c, new StringBuilder("StringBuilder of ").append(n));
        } catch (Exception e) {
          System.out.println("Did not accept StringBuilder: " + n + " => " + e);
        }
      }
      System.out.println("-----");
    }
  }
}

/* ==========================================
Output:

Lambda: regular invocation of accept(String)
Lambda: accept(Object)
Did not accept StringBuilder: accept(Object) => java.lang.reflect.InvocationTargetException
-----
Anonym: regular invocation of accept(String)
Anonym: accept(String)
Did not accept StringBuilder: accept(String) => java.lang.IllegalArgumentException: argument type mismatch
Anonym: accept(Object)
Did not accept StringBuilder: accept(Object) => java.lang.reflect.InvocationTargetException
-----
MyRegularClass: regular invocation of accept(String)
MyRegularClass: accept(Object)
Did not accept StringBuilder: accept(Object) => java.lang.reflect.InvocationTargetException
Did not accept String: get$Lambda(MyRegularClass) => java.lang.IllegalAccessException: Class com.example.foo.SomeClass can not access a member of class com.example.foo.SomeClass$$Lambda$2/1175962212 with modifiers "private static"
Did not accept StringBuilder: get$Lambda(MyRegularClass) => java.lang.IllegalArgumentException: argument type mismatch
-----
MyGenericClass: regular invocation of accept(String)
MyGenericClass: accept(Object)
Did not accept StringBuilder: accept(Object) => java.lang.reflect.InvocationTargetException
Did not accept String: get$Lambda(MyGenericClass) => java.lang.IllegalAccessException: Class com.example.foo.SomeClass can not access a member of class com.example.foo.SomeClass$$Lambda$3/617901222 with modifiers "private static"
Did not accept StringBuilder: get$Lambda(MyGenericClass) => java.lang.IllegalArgumentException: argument type mismatch
-----
*/

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM