Java: 泛型方法是如何工作的?
Java: How do generic methods work?
我有几种类型的 Objects
正在计算。这些对象彼此非常不同,但共同的特征是它们每个都有一个 Enum
常量来描述它们。
例如,Day.getDayOfWeek()
成员可能 return DayOfWeek.THURSDAY
。 Card.getSuit()
可能 return Suit.SPADE
、Dog.getBreed()
可能 return 枚举常量 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(),因为它们都是 return Enum<?>
?
我希望能够将 List<Card>
和 Card.getSuit()
参数传递给此函数,并获得正确的计数。这种结构我有几百个函数,所以这在可读性和维护性上是一个非常不可忽视的优化。
注意:我根本无法编辑这些 类 中的任何一个。我唯一能做的就是使用通用函数,如果存在的话。
如果您有 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
是一个类似于 Callable
或 Runnable
的接口,但它接受一个参数和 returns 个结果。您可以使用 lambda 语法 ((Dog d) -> d.getBreed()
) 创建 Function
,这意味着您可以像这样调用 getEnumCount
:
int[] counts = getEnumCount(listOfDogs, Breed.values().length, (Dog d) -> d.getBreed());
或更短,通过使用方法参考(等同于上述):
int[] counts = getEnumCount(listOfDogs, Breed.values().length, Dog::getBreed);
如果你使用Java8,你应该可以使用method references。
没有 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;
}
最后,您可以通过为调用实际 "enum" 方法(或具体的 class 的每个类型创建一个匿名 class 来调用它,如果您在很多地点):
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(); }
});
我有几种类型的 Objects
正在计算。这些对象彼此非常不同,但共同的特征是它们每个都有一个 Enum
常量来描述它们。
例如,Day.getDayOfWeek()
成员可能 return DayOfWeek.THURSDAY
。 Card.getSuit()
可能 return Suit.SPADE
、Dog.getBreed()
可能 return 枚举常量 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(),因为它们都是 return Enum<?>
?
我希望能够将 List<Card>
和 Card.getSuit()
参数传递给此函数,并获得正确的计数。这种结构我有几百个函数,所以这在可读性和维护性上是一个非常不可忽视的优化。
注意:我根本无法编辑这些 类 中的任何一个。我唯一能做的就是使用通用函数,如果存在的话。
如果您有 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
是一个类似于 Callable
或 Runnable
的接口,但它接受一个参数和 returns 个结果。您可以使用 lambda 语法 ((Dog d) -> d.getBreed()
) 创建 Function
,这意味着您可以像这样调用 getEnumCount
:
int[] counts = getEnumCount(listOfDogs, Breed.values().length, (Dog d) -> d.getBreed());
或更短,通过使用方法参考(等同于上述):
int[] counts = getEnumCount(listOfDogs, Breed.values().length, Dog::getBreed);
如果你使用Java8,你应该可以使用method references。
没有 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;
}
最后,您可以通过为调用实际 "enum" 方法(或具体的 class 的每个类型创建一个匿名 class 来调用它,如果您在很多地点):
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(); }
});