如何将这种鸭子类型(Python)转换为Java泛型?
下面是一个简单的Python函数作为例子:
def quantize(data, nlevels, quantizer=lambda x, d: int(floor(x/d))):
llim = min(data)
delta = (max(data) - llim)/(nlevels - 1) # last level x == max(data) only
y = type(data)
if delta == 0:
return y([0] * len(data))
else:
return y([quantizer(x - llim, delta) for x in data])
这是它运行的样子:
>>> from random import random
>>> data = [10*random() for _ in range(10)]
>>> data
[6.6181668777075018, 9.0511321773967737, 1.8967672216187881, 7.3396890304913951,
4.0566699095012835, 2.3589022034131069, 0.76888247730320769, 8.994874996737197,
7.1717500363578246, 2.887112256757157]
>>> quantize(data, nlevels=5)
[2, 4, 0, 3, 1, 0, 0, 3, 3, 1]
>>> quantize(tuple(data), nlevels=5)
(2, 4, 0, 3, 1, 0, 0, 3, 3, 1)
>>> from math import floor
>>> quantize(data, nlevels=5, quantizer=lambda x, d: (floor(x/d) + 0.5))
[2.5, 4.5, 0.5, 3.5, 1.5, 0.5, 0.5, 3.5, 3.5, 1.5]
这个函数确实有一些缺点——比如,它没有检查输入的参数是否正确,而且在返回值的类型上也应该更聪明一些——但它的优点是,无论数据中的元素是整数、浮点数还是其他数字类型,它都能正常工作。此外,默认情况下,它返回的是一个整数列表,不过通过传入一个合适的函数作为可选的量化器参数,这个返回值的类型可以改变。而且,如果数据参数是一个列表,返回的值也会是一个列表;如果数据是一个元组,返回的值就会是一个元组。(最后这个特性确实是最弱的,但也是我在Java中最不想复制的部分,所以我没有花太多精力去让它更健壮。)
我想写一个高效的Java版本的这个函数,这意味着我需要想办法绕过Java的类型限制。自从我很久以前学Java以来,Java引入了泛型。我尝试去了解Java的泛型,但发现它们实在是太难懂了。我不知道这是因为我年纪大了,还是因为自从我上次编程(大约在2001年)以来,Java的复杂性增长太快,但我找到的每一页资料都比前一页更让人困惑。如果有人能教我怎么在Java中实现这个功能,我会非常感激。
谢谢!
2 个回答
这可能不是你想要的答案,但我可以建议你试试Jython。通过这个工具,你可以把你的Python代码直接转换成Java的字节码。因为你自从2001年就没用过Java,而现在又在用Python,所以Jython可能会比你先去了解Java的各种变化要简单得多。
解决输入/输出类型问题的一种方法是使用 Number
类及其子类,配合通配符。如果你想接受任何类型的数字参数,可以指定输入类型为 Number
或者 ? extends Number
。如果输入是一个列表,后者的形式更有优势,因为它可以确保列表中的每个元素都是同一种类型(必须是 Number
的子类)。这里的 ?
被称为 通配符,当它表示为 ? extends Number
时,就是一个“有界通配符”,它只能指代边界类型的子类型。
举个例子:
public List<Number> func(List<? extends Number> data, Number nlevels)
这段代码会接受一个特定子类的 Number
列表,一个 Number
类型的 nlevels 参数,并返回一个 Number
的列表。
至于函数的输入参数,可以输入一个 Method
,不过在这个阶段类型检查会变得比较困难,因为你将把一个有界的未知参数传递给一个 Method
对象。我不太确定这具体是怎么运作的。
至于返回类型,可以指定另一个参数,一个类对象(可能又是 ? extends Number
),这样列表中的元素就可以被转换成这个类型。
public List<? extends Number> quantize(List<? extends Number> data,
Number nlevels,
Method quantizer,
Class<? extends Number> returnType)
这就是你在 Java 中为函数可能做的声明尝试。不过,具体的实现会复杂一些。