Java:泛型方法如何工作?

时间:2015-02-19 01:31:12

标签: java generics

我有几种类型Objects,我试图计算。这些对象彼此非常不同,但共同的特征是它们每个都有一个描述它们的Enum常量。

例如,Day.getDayOfWeek()成员可能会返回DayOfWeek.THURSDAYCard.getSuit()可能会返回Suit.SPADEDog.getBreed()可能会返回枚举常量Breed.LABRADOR等等。

现在,让我们说我有List<T>个这些对象(List<Dog>List<Card>等等...),我想根据这些对象计算这些对象他们的枚举状态。单独地,我可以做以下事情:

    public int[] getSuitCount(List<Card> cardList, int enumSize) {
        int[] array = new int[enumSize];
        for (Card card : cardList) {
            ++array[ card.getSuit().ordinal() ];
        }
        return array;
    }

    public int[] getDayCount(List<Day> dayList, int enumSize) {
        int[] array = new int[enumSize];
        for (Day day : dayList) {
            ++array[ day.getDayOfWeek().ordinal() ];
        }
        return array;
    }

    public int[] getBreedCount(List<Dog> dogList, int enumSize) {
        int[] array = new int[enumSize];
        for (Dog fido : dogList) {
            ++array[ fido.getBreed().ordinal() ];
        }
        return array;
    }

虽然这可行,但它非常重复。以下是优选的:

    public int[] getEnumCount(List<T> itemList, int enumSize
                             SomeFunction GENERIC_FUNCTION()  ) {

        int[] array = new int[enumSize];
        for (Class<T> item : itemList) {
            ++array[ item.GENERIC_FUNCTION().ordinal() ];
        }
        return array;
    }

...唯一的问题是,GENERIC_FUNCTION()在其调用的每个成员中都有不同的名称。有没有办法表示泛型函数?当我说泛型时,我的意思是,GENERIC_FUNCTION()是否可以表示getSuit()或getBreed(),因为它们都返回Enum<?>

我希望能够将List<Card>Card.getSuit()个参数传递给此函数,并获得正确的计数。我有这种结构的数百个函数,因此在可读性和维护方面这是一个非常不可忽视的优化。

注意:我根本无法编辑任何这些类。我唯一能做的就是使用泛型函数,如果存在这样的话。

3 个答案:

答案 0 :(得分:2)

如果您有Java 8编译器,则可以使用lambda表达式方便地执行此操作。

public int[] getEnumCount(List<T> itemList, int enumSize
                         Function<T, Enum<?>> enumGetterFunction) {

    int[] array = new int[enumSize];
    for (Class<T> item : itemList) {
        ++array[ enumGetterFunction.apply(item).ordinal() ];
    }
    return array;
}

Function是一个类似于CallableRunnable的接口,但它接受一个参数并返回结果。您可以使用lambda语法(Function)创建(Dog d) -> d.getBreed(),这意味着您可以像这样调用getEnumCount

int[] counts = getEnumCount(listOfDogs, Breed.values().length, (Dog d) -> d.getBreed());

或甚至更短,使用方法参考(相当于上述):

int[] counts = getEnumCount(listOfDogs, Breed.values().length, Dog::getBreed);

答案 1 :(得分:1)

如果您使用Java 8,则应该能够使用method references

答案 2 :(得分:1)

没有Java 8(让我们说Java 7),或者只是使用泛型,这是完全可能的。 lambda或委托函数的泛型等效函数是一个函数接口,可以调用一个定义的方法。

首先定义一个功能通用接口,它将为您提供一个通用方法来调用,并且可以为每个具体类型覆盖:

interface GetEnumFromType<S> {
  Enum getEnum(S item);
}

现在你在计算方法中调用它:

public static <T> int[] getEnumCount(List<T> itemList, int enumSize,
    GetEnumFromType<T> converter) {

  int[] array = new int[enumSize];
  for (T item : itemList) {
    ++array[ converter.getEnum(item).ordinal() ];
  }
  return array;
}

最后你可以通过为每个类型创建一个匿名类来调用它,这个类调用实际的&#34; enum&#34;方法(如果你在很多地方使用它,则为具体类):

int[] suitCounts = getEnumCount(cards, Suits.values().length,
    new GetEnumFromType<Card>(){
      public Enum getEnum(Card card) { return card.getSuit(); }
  });
int[] dayCounts = getEnumCount(days, DayOfWeek.values().length,
    new GetEnumFromType<Day>() {
      public Enum getEnum(Day day) { return day.getDayOfWeek(); }
  });
int[] dogCounts = getEnumCount(dogs, Breeds.values().length,
    new GetEnumFromType<Dog>(){
      public Enum getEnum(Dog fido) { return fido.getBreed(); }
  });
相关问题