Как умножить 10 на «целочисленный» объект в Java? - PullRequest
9 голосов
/ 05 сентября 2008

Как мне умножить 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);

Есть ли смысл в том или ином случае?

А что было бы наиболее эффективным / изощренным способом в целом и в этом случае?

Ответы [ 6 ]

26 голосов
/ 05 сентября 2008

С Java 5 autoboxing вы можете просто сделать:

Integer a = new Integer(2); // or even just Integer a = 2;
a *= 10;
System.out.println(a);
7 голосов
/ 05 сентября 2008

Строковый подход забавен, но почти наверняка это плохой способ сделать это.

Получение значения int для Integer и создание нового будет очень быстрым, тогда как parseInt будет довольно дорогим для вызова.

В целом, я бы согласился с вашим первоначальным подходом (который, как отмечали другие, можно сделать без лишних помех, если у вас есть автобокс, представленный в Java 5).

3 голосов
/ 05 сентября 2008

Проблема со вторым способом заключается в способе обработки строк в 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 является неизменным.

Кстати, автобокс / распаковка внутренне аналогичен первому способу.

1 голос
/ 05 сентября 2008

Решение с использованием метода String не очень хорошо по разным причинам. Некоторые из них эстетические причины, другие практичны.

На практическом фронте в версии String создается больше объектов, чем в более нормальной форме (как вы выразились в первом примере).

С эстетической точки зрения, я думаю, что вторая версия затемняет смысл кода, и это почти так же важно, как заставить его получить желаемый результат.

1 голос
/ 05 сентября 2008

Держитесь подальше от второго подхода, лучше всего было бы делать автобокс, если вы используете Java 1.5, и все, что раньше, ваш первый пример будет лучшим.

0 голосов
/ 18 июня 2014
Ответ

инструментария выше является правильным и наилучшим способом, но он не дает полного объяснения того, что происходит. Предполагая 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' не изменился, хотя мы изменили его значение с помощью отражения.
(НЕ ИСПОЛЬЗУЙТЕ ОТРАЖЕНИЕ ЭТОГО СПОСОБА В РЕАЛЬНОЙ ЖИЗНИ !!)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...