Как мне умножить 10 на объект Integer и вернуть объект Integer?
Я ищу самый изящный способ сделать это.
Я бы сделал это, наверное, так:
Получите int из объекта Integer, умножьте его на другой int и создайте другой объект Integer с этим значением int.
Код будет примерно таким ...
integerObj = new Integer(integerObj.intValue() * 10);
Но я видел код, в котором автор делает это следующим образом: получить String из объекта Integer, объединить «0» в конце и затем вернуть объект Integer с помощью Integer.parseInt.
Код выглядит примерно так:
String s = integerObj + "0";
integerObj = Integer.parseInt(s);
Есть ли какая-то заслуга в том, чтобы делать это в любом случае?
И какой способ в целом и в данном случае был бы наиболее эффективным / изящным?
Использование Integer на самом деле является ограничением дизайна. Идея в том, что я получаю объект Integer, и мне нужно его обновить. Так что не могу с этим покончить :)
<pedantry> Обновление существующего объекта Integer не произойдет без отражения вуду. (Целое число, как и другие типы примитивных оболочек, неизменяемо.) Лучшее, что вы можете разумно сделать - и то, что сделает любой разумный пример, - это заменить его другим объектом. Этого достаточно для большинства случаев, но означает, что void modifyInteger(Integer i) не сделает ничего стоящего.




Строковый подход забавен, но почти наверняка это плохой способ.
Получение значения int для Integer и создание нового будет очень быстрым, тогда как вызов parseInt будет довольно дорогостоящим.
В целом, я согласен с вашим первоначальным подходом (который, как отмечали другие, можно сделать без лишнего беспорядка, если у вас есть автобоксинг, представленный в Java 5).
С помощью Java 5 автобокс вы можете просто сделать:
Integer a = new Integer(2); // or even just Integer a = 2;
a *= 10;
System.out.println(a);
Не рекомендуется использовать конструктор Integer. Вместо этого используйте autoboxing или valueOf () ...
Держитесь подальше от второго подхода, лучше всего будет автобокс, если вы используете java 1.5, лучше всего подойдет все, что раньше, ваш первый пример.
Решение с использованием метода String не так хорошо по ряду причин. Некоторые из них являются эстетическими, другие - практичными.
На практике версия String создает больше объектов, чем более обычная форма (как вы выразились в своем первом примере).
Что касается эстетики, я думаю, что вторая версия скрывает предназначение кода, и это почти так же важно, как заставить его дать желаемый результат.
Проблема со вторым способом заключается в том, как строки обрабатываются в 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 неизменяемый.
Кстати, автобоксинг / распаковка внутренне такая же, как и у первого метода.
Integer.parseInt(...) не должен создавать целочисленный объект, он напрямую работает с примитивом int.
Приведенный выше ответ инструментария является правильным и лучшим способом, но он не дает полного объяснения того, что происходит. Предполагая, что 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'. Это связано с тем, что "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' не изменился, хотя мы изменили его значение с помощью отражения. (НЕ ИСПОЛЬЗУЙТЕ ОТРАЖЕНИЕ ТАК В РЕАЛЬНОЙ ЖИЗНИ !!)
Я также посоветовал бы вам проверить, ДЕЙСТВИТЕЛЬНО ли необходимо использование Integer. Джошуа указал, что использование примитивов во много раз быстрее в Effective Java. Так что, если можете, придерживайтесь int.