Когда я делаю "" +1, я получаю строку - почему - PullRequest
5 голосов
/ 19 марта 2010

Пожалуйста, поймите, во-первых, что я полностью понимаю, что Java будет возвращать строку, когда я использую "" + int.

Что я действительно не уверен в том, что именно происходит в аспекте памяти. Как именно Java выполняет это преобразование. Я имею в виду это очень углубленно, а не «автобокс» или что-то в этом роде :)

Я надеюсь, что кто-то с более глубоким пониманием может объяснить, что именно сделано.

Ответы [ 5 ]

9 голосов
/ 19 марта 2010

На самом деле, для "" + 1 компилятор создает строковую константу String со значением "1" и помещает ее в пул констант - поэтому во время выполнения ничего не делается.

Если у вас есть "" + x (где x - переменная типа int), вы получите следующий байт-код (из текущего JDK 1.6):

  0:   new     #2; //class java/lang/StringBuilder
  3:   dup
  4:   invokespecial   #3; //Method java/lang/StringBuilder."<init>":()V
  7:   ldc     #4; //String
  9:   invokevirtual   #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
  12:  aload_0
  13:  arraylength
  14:  invokevirtual   #6; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
  17:  invokevirtual   #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
  20:  astore_1
  21:  return

Таким образом, он создает StringBuilder, добавляет к нему «», затем добавляет к нему значение int, а затем вызывает toString для экземпляра StringBuilder.

Внутри метода StringBuilder.append (int) он в конечном итоге вызывает Integer.getChars (закрытый метод пакета).

Вы можете найти источник в append и getChars в вашей копии JDK src.zip (или src.jar).

8 голосов
/ 19 марта 2010

+ рассматривается как конкатенация строк, потому что строка находится на одной стороне операнда - это также будет работать на 1+"".Таким образом, 1 неявно преобразуется в строку "1" и "" соединяется с ней, что приводит к ""+"1" => "1".

Это иногда используется как быстрый и грязный способ преобразованияцелочисленная переменная для String, например

String s = "" + myInt;

Но «правильный» способ сделать это будет:

String s = Integer.toString(myInt);

или альтернативно:

String s = String.valueOf(myInt);

Редактировать:

Чтобы уточнить, компилятор делает это определение и вставляет код, который преобразует целое число в строку перед выполнением конкатенации.

Таким образом, в основном компилятор видит:

String s = "" + myInt;

И эффективно создает байт-код, эквивалентный

String s = "" + String.valueOf(myInt)

Хотя это, вероятно, на практике оптимизирует конкатенацию.

6 голосов
/ 19 марта 2010

Спецификация языка Java 15.18.1.1 Преобразование строки

Любой тип может быть преобразован в тип String с помощью преобразование строки .

Значение х из примитивный тип T сначала преобразуется в эталонное значение, как будто, давая ему в качестве аргумента для соответствующего класса выражение создания экземпляра:

  • Если T булево, используйте new Логическое (х).
  • Если T - символ, тогда используйте новый персонаж (х).
  • Если T является байтом, short или int, затем используйте новый Целое число (х).
  • Если T длинный, используйте новый длинный (х).
  • Если T - float, тогда использовать новый поплавок (х).
  • Если T двойной, то используйте новый Double (x).

Эта ссылка Затем значение преобразуется в тип String путем преобразования строки.

Теперь только эталонные значения должны быть считается. Если ссылка нулевая, он преобразуется в строку «ноль» (четыре символа ASCII n, u, l, l). В противном случае преобразование выполняется как будто при вызове toString метод ссылочного объекта с без аргументов; но если результат вызов метода toString равен нулю, тогда используется строка «ноль» вместо.

Метод toString определяется изначальный класс Object; много классов переопределить его, в частности, логическое, Характер, Целое, Длинное, Плавающее, Двойной и струнный.

2 голосов
/ 20 марта 2010

Некоторые из этих цитат отредактированы для актуальности, и можно добавить акцент.

JLS 15.18.1 Оператор конкатенации строк +

Если только одно выражение операнда имеет тип String, то преобразование строки выполняется для другого операнда для получения строки во время выполнения. Результатом является ссылка на объект String, который является объединением двух строк операндов.

JLS 15.18.1.1 Преобразование строки

  • Значение x примитивного типа T сначала преобразуется в эталонное значение , как если бы , передав его в качестве аргумента соответствующему выражению создания экземпляра класса:
    • Если T равно byte, short или int, используйте new Integer(x).
  • Теперь необходимо учитывать только эталонные значения. Преобразование выполняется как если бы путем вызова метода toString().

Согласно этой спецификации, "" + i оценивается , как если бы было записано как "" + new Integer(i).toString(). Операция - конкатенация строк, которая приводит к строке.

Запишите фразу «как будто» в вышеприведенных отрывках; точно указано только правильное поведение, но как это сделать скрытно, оставлено на усмотрение.

Несколько вещей, которые я пока пропустил в этом обсуждении:

  • null всегда преобразуется в "null"
  • Вставка констант времени компиляции ( JLS 15,28 )
  • Оптимизация с использованием изменяемого StringBuffer / StringBuilder ( JLS 15.18.1.2 )
0 голосов
/ 19 марта 2010

"a" + "b" является просто синтаксическим сахаром для StringBuilder.append ("a) .append (" b "), и так как вы можете .append (1), и он автоматически преобразует его в String, что вы видите.

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