我想创建一个泛型方法,它可以采用Integer,Float的ArrayList或任何扩展Number的类型。
public void mulBy2(ArrayList<? extends Number> list) {
// I want to multiply the value of each element in list by 2
// and store it back in list
for(int i = 0; i < al.size(); i++) {
Double d = al.get(i).doubleValue()*2;
al.set(i,d); // Obvious error here says required ? extends Number
// how to solve this issue
}
}
如果list是值为[2,3,4]的ArrayList,我的方法应该返回或者使用值为[4,6,8]的arrayList 最初[1.2,3.4]的ArrayList应转换为[2.4,6.8]
答案 0 :(得分:1)
我们不想做你的作业,但我认为这个问题应该回答,因为它对未来的访问者有用。解决方案应包括以下内容:
class
class
以获取其值,如果它是Integer
,invoke
通过反射对象的intValue
,将其乘以2并将列表的相应元素设置为新值有用的知道:
相应的方法有:intValue
,longValue
,floatValue
,doubleValue
,byteValue
和shortValue
,与Double
,Float
等相关的类或多或少与它们相关联。请参阅此处:https://docs.oracle.com/javase/7/docs/api/java/lang/Number.html
您可以通过调用class
方法获取Object
的{{1}}。可以通过调用生成的getClass
的getEnclosingClass来获取其名称。例如:
class
Class<?> enclosingClass = getClass().getEnclosingClass();
if (enclosingClass != null) {
System.out.println(enclosingClass.getName());
} else {
System.out.println(getClass().getName());
}
答案 1 :(得分:0)
<Number>
列表
这是一个快速修复:
public void mulBy2(List<Number> list) {
for (int i = 0; i < list.size(); i++) {
Double d = list.get(i).doubleValue()*2;
list.set(i,d);
}
}
该修复程序包含以下更改:
List<Number>
。 List<Number>
可以保留任何数字组合,例如Integer
,Float
,BigDecimal
。List
而不是实施,ArrayList
。Double
个数字。此代码存在一些问题:
List<Integer>
参数。BigDecimal
-s insanceof
的绑定子类型检查。所以让我们写另一个修复:
public <T extends Number> void mulBy2Attempt2(List<T> list) {
for (int i = 0; i < list.size(); i++) {
list.set(i, multiplyBy2(list.get(i)));
}
}
private <T extends Number> T multiplyBy2(T num) {
if (num instanceof BigDecimal) {
return (T) ((BigDecimal) num).multiply(new BigDecimal(2));
}
if (num instanceof BigInteger) {
return (T) ((BigInteger) num).multiply(new BigInteger("2"));
}
if (num instanceof Long) {
return (T) new Long(num.longValue() * 2);
}
if (num instanceof Integer) {
return (T) new Integer(num.intValue() * 2);
}
if ((num instanceof Double)) {
return (T) new Double(num.doubleValue() * 2);
}
if (num instanceof Float) {
return (T) new Float(num.floatValue() * 2);
}
if (num instanceof Byte) {
return (T) new Byte((byte) (num.byteValue() * 2));
}
if (num == null) {
throw new NullPointerException("Cannot multiply a null-number by two");
}
throw new IllegalArgumentException("Cannot handle a number of " + num.getClass().getCanonicalName() + " yet.");
}
这真的很酷。由于绑定类型<T extends Number>
,它可以接受任何类型的列表,例如List<AtomicInteger>
或List<Number>
。这个解决方案有一些缺点:
instanceof
支票Number
子类,因为任何人都可以自由地实现新的Number
子类,然后你就完成了。我们可以使用lambdas将这个负担放在调用者身上:
public <T extends Number> void mulBy2Attempt3(List<T> list, Function<T,T> multiplier) {
for (int i = 0; i < list.size(); i++) {
list.set(i, multiplier.apply(list.get(i)));
}
}
所以你可以这样称呼它:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
mulBy2Attempt3(list, n -> n * 2);
System.out.println(list);
map
我们现在拥有的几乎就像map
函数:
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
list.add(4);
List<Integer> list2 = list.stream().map(n -> n * 2).collect(Collectors.toList());
System.out.println(list2);
这略有不同,因为它不会修改原始列表。
现在你有几种选择。根据您的要求,您可以决定走哪条路。