Как умножить 10 на объект «Целое число» в Java?
Вопрос
Как умножить 10 на Integer
объект и вернуть Integer
объект?
Я ищу самый аккуратный способ сделать это.
Я бы, наверное, сделал это так:Получить данные из Integer
объект, умножьте его на другой int и создайте еще один объект Integer с этим значением int.
Код будет что-то вроде...
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 и создание нового будет очень быстрым, тогда как вызов parseInt будет довольно дорогим.
В целом, я бы согласился с вашим первоначальным подходом (который, как отмечали другие, можно сделать без особого беспорядка, если у вас есть автобокс, представленный в Java 5).
Проблема второго способа заключается в том, как строки обрабатываются в Java:
"0"
преобразуется в постоянный объект String во время компиляции.Каждый раз, когда вызывается этот код,
s
создается как новый объект String иjavac
преобразует этот код вString s = new StringBuilder().append(integerObj.toString()).append("0").toString()
(StringBuffer для более старых версий).Даже если вы используете тот жеintegerObj
, то есть,String s1 = integerObj + "0"; String s2 = integerObj + "0";
(s1 == s2)
было быfalse
, покаs1.equals(s2)
было быtrue
.Integer.parseInt
внутренние звонкиnew Integer()
в любом случае, потому чтоInteger
является неизменным.
Кстати, автобокс/распаковка внутренне аналогичны первому методу.
Держитесь подальше от второго подхода, лучше всего будет использовать автобокс, если вы используете Java 1.5, лучше всего подойдет любой более ранний вариант.
Решение с использованием метода String не так хорошо по ряду причин.Некоторые из них эстетические, другие практичные.
С практической точки зрения, в версии 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», вы не меняете значение int внутри объекта «a», а фактически назначаете новый объект «a».Это связано с тем, что «а» автоматически распаковывается для выполнения умножения, а затем результат умножения автоматически распаковывается и присваивается «а».
Integer — неизменяемый объект.(Все классы-оболочки неизменяемы.)
Возьмем, к примеру, этот фрагмент кода:
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» не изменился, хотя мы изменили его значение с помощью отражения.
(НЕ ИСПОЛЬЗУЙТЕ ОТРАЖЕНИЕ ТАКИМ СПОСОБОМ В РЕАЛЬНОЙ ЖИЗНИ!!)