我有以下不完整的课程。它实现了一个方法,该方法将任何Number
对象作为参数并将其约束为存储在long中的限制,然后返回原始值或约束值。但是,返回的约束值必须与输入参数具有相同的具体类型。
public class Max implements Constraint {
long max;
public Number constrain(Number n) {
if (n.longValue() <= max) {
return n;
}
// return a number of the type passed in with value max
}
}
关于创建与另一个类型相同的对象还有其他问题,但答案假设有一个no-arg构造函数可用,而数字类型则不是这样。
我玩过:
n.getClass().getConstructor(new Class<?>[] { n.getClass() }).newInstance(max);
但即使在这里,我仍然有关于传递正确参数的问题。我回到原点。无论如何,它并不优雅。
我知道我可以用很多if
语句来做,但我正在寻找更聪明的东西。
答案 0 :(得分:1)
由于Number
的子类的构造函数将primitives
作为参数,因此您无法查找具有Wrapper Class
作为参数的构造函数
他们都拥有的构造函数是String
一个
long max;
public Number constrain(Number n) {
if (n.longValue() <= max)
try{
return n.getClass()
.getConstructor(String.class)
.newInstance(String.valueOf(max));
}catch(Exception ex){ex.printStackTrace();}
return n;
}
public static void main(String[]args){
Max m = new Max();
m.max = 10;
System.out.println(m.constrain(new Double(25)).getClass()); // class java.lang.Double
System.out.println(m.constrain((int) 18).getClass()); // class java.lang.Integer
}
答案 1 :(得分:0)
如果您只讨论允许原始类型作为构造函数输入的Numbers成员,如Float / Double / Integer / Long / ...,则可以使用以下代码:
//Number n is valid someInput;
//Note this only works for Classes that take a single numeric value as input
Class type = (Class) n.getClass().getDeclaredField("TYPE").get(n);
return n.getClass().getConstructor(type).newInstance(max)
像BigInteger这样的东西不适用于这个。
对于原始类型n,似乎“Number n”被不同的签名替换,并且使用Integer.TYPE(或Float.TYPE等),你可以传入'int'作为getConstructor的参数。你可以在这里使用n.TYPE(但提醒TYPE是类成员,它可能会弹出一些警告)。
n.getClass().getConstructor(n.TYPE).newInstance(max);
然而,正如@azro指出的那样:如果你坚持不使用字符串并希望它变得聪明,你仍然需要分支,它可能更糟糕:你需要考虑Number的所有子类,包括BigInteger。
是的,将它转换为字符串是令人讨厌的,但是否则,您可能需要使用一个额外的类来包装Number的每个子类,该类允许非基本类型作为构造函数的args。我几乎认为if-statements更糟糕。
我对Reflection不是很熟悉。 但是这里的一个主要问题是Numbers的构造函数是字符串或原始类型,如'int',你不能真正利用'int'作为getConstructor的输入。
至少,以下可能有效。
//assume n is some Number object.
n.getClass().getConstructor(String.class).newInstance(max.toString());
这就像Float / Integer / BigInt这样的类... /具有以String作为输入的构造函数。
答案 2 :(得分:0)
使用Java 5或者hogher,你可以在你的方法中使用泛型
package test;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
import org.junit.Assert;
public class Max {
Number max;
public <T extends Number> T constrain(T n) {
if (n.floatValue() <= max.floatValue()) {
return n;
} else {
return castTo(max, n.getClass());
}
}
@SuppressWarnings("unchecked")
private <T extends Number> T castTo(Number max2, Class<? extends Number> class1) {
if (class1.equals(AtomicInteger.class)) {
return (T) new AtomicInteger(max2.intValue());
} else if (class1.equals(AtomicLong.class)) {
return (T) new AtomicLong(max2.longValue());
// these case are dangerous to handle
} else if (class1.equals(BigDecimal.class)) {
return (T) BigDecimal.valueOf(max2.doubleValue());
} else if (class1.equals(BigInteger.class)) {
return (T) BigInteger.valueOf(max2.longValue());
// Std Case
} else if (class1.equals(Byte.class)) {
return (T) (Byte) max2.byteValue();
} else if (class1.equals(Double.class)) {
return (T) (Double) max2.doubleValue();
} else if (class1.equals(Float.class)) {
return (T) (Float) max2.floatValue();
} else if (class1.equals(Integer.class)) {
return (T) (Integer) max2.intValue();
} else if (class1.equals(Long.class)) {
return (T) (Long) max2.longValue();
} else if (class1.equals(Short.class)) {
return (T) (Short) max2.shortValue();
} else {
throw new IllegalArgumentException("Can't handle this kind of Number : " + class1.getName());
}
}
public static void main(String[] args) {
Max max = new Max();
max.max = 32;
Integer constrain = max.constrain(33);
Assert.assertEquals(Integer.class, constrain.getClass());
Assert.assertEquals(max.max, constrain);
Double constrain2 = max.constrain(33d);
Assert.assertEquals(Double.class, constrain2.getClass());
Assert.assertEquals(max.max.doubleValue(), constrain2, 0);
Float constrain3 = max.constrain(33f);
Assert.assertEquals(Float.class, constrain3.getClass());
Assert.assertEquals(max.max.floatValue(), constrain3, 0);
Short constrain4 = max.constrain((short) 33);
Assert.assertEquals(Short.class, constrain4.getClass());
Assert.assertEquals(max.max.shortValue(), constrain4, 0);
Byte constrain5 = max.constrain((byte) 33);
Assert.assertEquals(Byte.class, constrain5.getClass());
Assert.assertEquals(max.max.byteValue(), constrain5, 0);
Long constrain6 = max.constrain(33l);
Assert.assertEquals(Long.class, constrain6.getClass());
Assert.assertEquals(max.max.longValue(), constrain6, 0);
BigDecimal constrain7 = max.constrain(BigDecimal.valueOf(33));
Assert.assertEquals(BigDecimal.class, constrain7.getClass());
BigInteger constrain8 = max.constrain(BigInteger.valueOf(33));
Assert.assertEquals(BigInteger.class, constrain8.getClass());
AtomicInteger constrain9 = max.constrain(new AtomicInteger(33));
Assert.assertEquals(AtomicInteger.class, constrain9.getClass());
AtomicLong constrain10 = max.constrain(new AtomicLong(33));
Assert.assertEquals(AtomicLong.class, constrain10.getClass());
}
}
但是在你的代码中构造所有数字的子代,没有常见的构造函数,最安全的方法是减少你想要处理的情况,我没有处理所有的Striped64孩子
答案 3 :(得分:0)
我发现了:
import org.apache.commons.beanutils.ConvertUtils;
...
return (Number)ConvertUtils.convert(max, n.getClass());
我没有看过消息来源,但我怀疑里面是否非常聪明。我相信它只是托管类型转换器的集合。
这是一种替代方法-并不比其他答案更好,但至少是简洁的。