如果您只有一个Class
对象,如何获得对方法的方法引用,例如toString
?稍后我们将拥有这个特定类的实例,我们将在其上通过方法引用调用此方法。
例如,考虑一个 Java 枚举,它是Enum
. 这里T
定义为<T extends Enum>
。
Class c = MyEnum.class
…
Function< T , String> f = c :: toString ;
我收到一条错误消息,提示“方法引用无效”。
因为toString
,它就像 一样简单Object::toString
。所有Object
s 都有toString
,所以你可以在那里使用它。对于您不知道该对象具有该方法的静态方法的其他方法,没有简单的方法;你必须编写一个 lambda 来以丑陋的反射方式完成它。
如果您可以Class
使用表单中的类文字访问您的对象Class<MyEnum> c=MyEnum.class;
,则意味着该类型MyEnum
在编译时是已知的。在这种情况下,Class
对象是不必要的绕道。MyEnum
您可以使用表单访问该类的所有方法MyEnum::methodName
,例如
Function<MyEnum,String> f=MyEnum::toString;
这就是本教程所描述的“对特定类型的任意对象的实例方法的引用”。它不需要实际的MyEnum
实例。
MyEnum
然而,当你想要 a 时处理它是没有意义的,Function<T,…>
因为该函数必须能够使用 的任意实例T
,不一定是MyEnum
。所以这个函数只能使用已有的方法,T
不需要在MyEnum
.
由于您的目标方法不特定于MyEnum
,因此这是可能的:
Function<T,String> f=T::toString;
但是正如已经指出的那样,方法toString
是在 中定义的java.lang.Object
,所以你也可以使用形式
Function<T,String> f=Object::toString;
作为为所有对象声明的方法也可以在T
. 尽管即使这也有点毫无意义,因为您也可以使用
Function<Object,String> f=Object::toString;
反映消费任何实例的能力Object
,而不仅仅是T
。精心编写的通用代码将始终使用通配符来避免对其输入进行不必要的限制。所以它将接受一个可以消费 T
的函数(这意味着消费的能力MyEnum
),而不需要它的类型参数与该类型完全匹配。例如:
<R> Stream<R> map(Function<? super T,? extends R> mapper)
map
, 应用于 aStream<T>
将接受 aFunction<Object,…>
作为…Object
的超类型T
</p>
因此,您可以使用T::methodName
访问该类型边界可用的每个方法,即在您的情况下,您可以使用Enum
and,当然,的所有方法Object
,但没有特定于MyEnum
不存在于其超类型中的方法。这与您尝试对T
. 此外,不存在的方法无论如何T
都没有资格创建有效的方法Function<T,…>
。
如果要为Function
编译时未知的方法创建实例,则必须使用反射,这是唯一必须处理Class
对象的情况(在方法引用的上下文中)。此答案的第二个示例显示了如何为Function
返回对象的实例方法创建一个,但这实际上只适用于那些确切知道自己在做什么的人......</p>
另请注意,此类反射创建Function
的 s 必须使用原始类型,因为无法声明其适当的泛型类型,因为它会引用编译时不存在的类型。
您在这里尝试的是获取toString()
class的参考Class
,这可能不是您想要的。正如toString()
为所有对象定义的那样,这应该可以工作(未经测试):
Function< T , String> f = t -> t.toString();