如何在 Java 中将 10 乘以“Integer”对象?
题
如何将 10 乘以一个 Integer
对象并取回 Integer
目的?
我正在寻找最简洁的方法来做到这一点。
我可能会这样做:获取整数来自 Integer
对象,将其与另一个 int 相乘,并使用该 int 值创建另一个 Integer 对象。
代码将类似于...
integerObj = new Integer(integerObj.intValue() * 10);
但是,我看到作者这样做的代码:获取 String
来自 Integer
对象,在末尾连接“0”,然后得到 Integer
通过使用返回对象 Integer.parseInt
代码是这样的:
String s = integerObj + "0";
integerObj = Integer.parseInt(s);
这样做有什么好处吗?
在这种情况下,一般情况下最有效/最简洁的方法是什么?
解决方案
使用 Java 5 自动装箱, ,您可以简单地执行以下操作:
Integer a = new Integer(2); // or even just Integer a = 2;
a *= 10;
System.out.println(a);
其他提示
字符串方法很有趣,但几乎可以肯定是一种糟糕的方法。
获取 Integer 的 int 值并创建一个新的值将非常快,而调用 parseInt 的成本相当昂贵。
总的来说,我同意你原来的方法(正如其他人指出的那样,如果你有 Java 5 中引入的自动装箱功能,那么可以在没有太多混乱的情况下完成)。
第二种方式的问题在于 Java 中处理字符串的方式:
"0"
在编译时转换为常量 String 对象。每次调用此代码时,
s
被构造为一个新的 String 对象,并且javac
将该代码转换为String s = new StringBuilder().append(integerObj.toString()).append("0").toString()
(旧版本的 StringBuffer)。即使你使用相同的integerObj
, , IE。,String s1 = integerObj + "0"; String s2 = integerObj + "0";
(s1 == s2)
将会false
, , 尽管s1.equals(s2)
将会true
.Integer.parseInt
内部调用new Integer()
无论如何,因为Integer
是不可变的。
顺便说一句,自动装箱/拆箱在内部与第一种方法相同。
远离第二种方法,如果您使用的是 java 1.5,最好的选择是自动装箱,任何早期的第一个示例都是最好的。
由于多种原因,使用 String 方法的解决方案并不是那么好。有些是出于美观原因,有些则是实用原因。
在实际方面,字符串版本比更普通的形式创建更多的对象(正如您在第一个示例中所表达的那样)。
从美学角度来看,我认为第二个版本掩盖了代码的意图,这几乎与让它产生您想要的结果一样重要。
工具包上面的答案是正确的,也是最好的方法,但它没有给出正在发生的事情的完整解释。假设 Java 5 或更高版本:
Integer a = new Integer(2); // or even just Integer a = 2;
a *= 10;
System.out.println(a); // will output 20
您需要知道的是,这与执行以下操作完全相同:
Integer a = new Integer(2); // or even just Integer a = 2;
a = a.intValue() * 10;
System.out.println(a.intValue()); // will output 20
通过对对象“a”执行操作(在本例中为 *=),您并没有更改“a”对象内部的 int 值,而是实际上将一个新对象分配给“a”。这是因为“a”会自动拆箱以便执行乘法,然后乘法的结果会自动装箱并分配给“a”。
整数是一个不可变的对象。(所有包装类都是不可变的。)
以这段代码为例:
static void test() {
Integer i = new Integer(10);
System.out.println("StartingMemory: " + System.identityHashCode(i));
changeInteger(i);
System.out.println("Step1: " + i);
changeInteger(++i);
System.out.println("Step2: " + i.intValue());
System.out.println("MiddleMemory: " + System.identityHashCode(i));
}
static void changeInteger(Integer i) {
System.out.println("ChangeStartMemory: " + System.identityHashCode(i));
System.out.println("ChangeStartValue: " + i);
i++;
System.out.println("ChangeEnd: " + i);
System.out.println("ChangeEndMemory: " + System.identityHashCode(i));
}
输出将是:
StartingMemory: 1373539035
ChangeStartMemory: 1373539035
ChangeStartValue: 10
ChangeEnd: 11
ChangeEndMemory: 190331520
Step1: 10
ChangeStartMemory: 190331520
ChangeStartValue: 11
ChangeEnd: 12
ChangeEndMemory: 1298706257
Step2: 11
MiddleMemory: 190331520
您可以看到“i”的内存地址正在改变(您的内存地址将会不同)。
现在让我们用反射做一个小测试,将其添加到 test() 方法的末尾:
System.out.println("MiddleMemory: " + System.identityHashCode(i));
try {
final Field f = i.getClass().getDeclaredField("value");
f.setAccessible(true);
f.setInt(i, 15);
System.out.println("Step3: " + i.intValue());
System.out.println("EndingMemory: " + System.identityHashCode(i));
} catch (final Exception e) {
e.printStackTrace();
}
额外的输出将是:
MiddleMemory: 190331520
Step2: 15
MiddleMemory: 190331520
您可以看到“i”的内存地址没有改变,即使我们使用反射更改了它的值。
(不要在现实生活中以这种方式使用反射!!)