2015-08-27 4 views
2

Если у вас есть только объект Class, как получить method reference методу, например toString? Позже мы будем иметь экземпляры этого конкретного класса, на который мы будем ссылаться на этот метод с помощью ссылки на метод.Если у вас есть объект класса, обратитесь к методу `toString`

Например, рассмотрите перечисление Java, подкласс Enum. Здесь T определяется как <T extends Enum>.

Class c = MyEnum.class 
… 
Function< T , String> f = c :: toString ; 

Я получаю сообщение об ошибке «invalid method reference».

ответ

7

Для toString это так же просто, как Object::toString. Все Object s имеют toString, так что вы можете использовать его прямо там. Для других методов, когда вы не знаете статически, что объект имеет этот метод, нет простого способа; вы должны написать лямбду, которая делает это уродливым рефлексивным способом.

1

Что вы здесь делаете, это получить ссылку toString() для класса Class, что, вероятно, не так, как вы планировали. Как toString() определяются для всех объектов, это должно работать (не проверено):

Function< T , String> f = t -> t.toString(); 
4

Если вы можете получить доступ к Class объекту, используя класс буквального в виде Class<MyEnum> c=MyEnum.class;, это означает, что тип MyEnum известен во время компиляции , В этом случае объект Class является ненужным объездом. Вы можете получить доступ ко всем методам класса MyEnum, используя форму MyEnum::methodName, например.

Function<MyEnum,String> f=MyEnum::toString; 

Это то, что tutorial описывает как «ссылка на экземпляр метода произвольного объекта определенного типа». Он не требует фактического экземпляра MyEnum.

Тем не менее, нет никакого смысла в борьбе с MyEnum, когда вы хотите иметь Function<T,…> как функция должна быть в состоянии потреблять произвольные экземпляры из T, не обязательно быть MyEnum. Таким образом, эта функция может использовать только методы, существующие в T, и его не нужно искать в MyEnum.

Поскольку целевой метод не является специфическим для MyEnum, что это возможно:

Function<T,String> f=T::toString; 

Но as already pointed out, метод 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, наносят на Stream<T> будут принимать Function<Object,…> в Object является супертипом T ...


Таким образом, вы можете использовать T::methodName получить доступ ко всем доступный метод для границ, которые типа, то есть в вашем случае вы можете использовать все методы Enum и, конечно, Object, но никаких методов, специфичных для MyEnum, нет в его супертипах. Это не отличается от обычных вызовов метода, которые вы пытаетесь применить к экземплярам T. Кроме того, способ, отсутствующий в T, не будет иметь права на создание действительного Function<T,…> в любом случае.


Если вы хотите создать Function экземпляров для методов не известен во время компиляции, вы должны будете использовать Reflection, и это единственный случай, когда вам приходится иметь дело с Class объектами (в контексте методы Рекомендации). Второй пример this answer показывает, как создать Function для метода экземпляра, возвращающего объект, но это действительно только для тех, кто точно знает, что они делают ...

Следует также отметить, что такие рефлекторно созданы Function s должны использовать сырые типы, как их соответствующий общий тип не может быть объявлен, поскольку он будет ссылаться на тип, отсутствующий во время компиляции.