将泛型类方法作为参数传递

时间:2017-03-24 09:52:32

标签: java android list generics reflection

有没有办法将泛型类型的方法作为参数传递? 我试图实现的是这样的:

ListUtils.mapObjectToField( entries, Contact.getZipCode );

我从通用类List<T>传递T和方法。 到目前为止,我对通用List很好,但我无法实现方法调用。

public static <T, U> List<U> mapObjectToField( List<T>elements, /*generic method*/ )
{
    List<U> result = new ArrayList<>();

    for ( T current : elements )
    {
        result.add(current./*generic method*/);
    }
    return result;
}

没有Java 8,因为我正在编写Android min SDK 14。

3 个答案:

答案 0 :(得分:0)

可能最好的方法是在Java 8中像Stream.map一样实现它并提供您自己的接口,可能称为Mapper,但是为了在呼叫站点提供实现,您必须使用匿名内部类。 Lambdas更好。

可能看起来像这样:

public interface Mapper<T, U> {
    U map(T t);
}

ListUtils希望如此:

public class ListUtils {
    public static List<U> mapObjectToField(List<T> elements, Mapper<T, U> mapper) {
        List<U> result = new ArrayList<>();
        for (T current : elements) {
            result.add(mapper.map(current));
        }
        return result;
    }
}

你可以这样称呼它:

List<String> zipCodes = ListUtils.mapObjectToField(contacts,
    new Mapper<Contact, String>() {
        public String map(Contact contact) {
            return contact.getZipCode();
        }
    });

您可以在其他地方定义映射器,这会稍微清理一下外观,但它不会像拥有lambda那样好。

答案 1 :(得分:0)

如果你想使用反射,就这样做(但不建议使用它),

public static <T, U> List<U> mapObjectToField( List<T>elements, String methodName )
    {
        List<U> result = new ArrayList<>();
        Method method = null;

        for ( T current : elements )
        {
            if(method == null){
                try {
                    method = current.getClass().getDeclaredMethod(methodName);
                } catch (Exception e) {
                    e.printStackTrace();
                } 
            }

            U object = (U) invokeMethod(current, method);
            result.add(object);
        }
        return result;
    }


public static Object invokeMethod(Object obj , Method method)
    {
        if (method != null) {
            try {
                Object value = method.invoke(obj);
                return value;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return null;
    }

答案 2 :(得分:0)

您可以使用 Retrolambda 在Android SDK 14中使用lambdas和方法引用。

https://github.com/evant/gradle-retrolambda

https://stackoverflow.com/a/42996933/802034中建议的代码将变为:

  public void main(){
    List<Integer> lengths = mapObjectToField(nCopies(5, "hello"), String::length);
  }

  public static <T, U> List<U> mapObjectToField(List<T> elements, Mapper<T, U> mapper) {
    List<U> result = new ArrayList<>();
    for (T current : elements) {
      result.add(mapper.map(current));
    }
    return result;
  }

  public interface Mapper<T, U> {
    U map(T t);
  }


}

如果你想进一步使用 Streams ,你可以使用这个库安装android:https://github.com/aNNiMON/Lightweight-Stream-API

 List<Integer> lengths =
        Stream.of(nCopies(5, "hello"))
              .map(String::length)
              .collect(Collectors.toList());