Существует ли перегрузка операторов в Java? - PullRequest
4 голосов
/ 04 ноября 2011

Я просто хочу знать одну простую вещь в Java. Давайте рассмотрим следующий сегмент кода на Java.

int x=10;
String temp="x = "+x;
System.out.println(temp);

совершенно допустимо в Java и выдает результат, x = 10 в виде строки.


Хотя переменная x имеет тип int , она автоматически преобразуется в тип String (тип оболочки). Как Java делает это? Существует ли какая-либо или где-то перегрузка операторов в Java, как в примере выше, как в C ++ и C #?, Хотя она была удалена из Java. Какая конкретная концепция используется здесь для преобразования x в строку. Единственное, что я хочу знать


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

Ответы [ 3 ]

9 голосов
/ 04 ноября 2011

Компилятор преобразует эту фразу ("x =" + x) в StringBuilder для внутреннего использования и использует .append (int) для "добавления" целого числа в строку.

Чтобы выйти за рамки практического «как Java это делает», я приму совет Стивена и приведу теоретическое. Концептуально каждое значение в конкатенации сначала преобразуется в строку, а затем конкатенируется. Нули объединяются как слово «ноль».

Из спецификации языка Java :

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

Любой тип может быть преобразован в тип String путем преобразования строки. Ценность х примитивного типа Т сначала преобразуется в опорное значение, как будто давая его в качестве аргумента для создания соответствующего экземпляра класса выражение:

Если T булево, тогда используйте новый булево (x). Если T - символ, тогда используйте новый Характер (х). Если T является байтом, коротким или целым числом, используйте новое целое число (x). Если T длинный, затем используйте новый Long (x). Если T - float, тогда используйте новый Float (x). Если T двойное, то используйте новый Double (x). Это эталонное значение тогда преобразован в тип String путем преобразования строки. Теперь только ссылка значения должны быть рассмотрены. Если ссылка является нулевой, это преобразуется в строку «null» (четыре символа ASCII n, u, l, l). В противном случае преобразование выполняется как будто путем вызова метод toString ссылочного объекта без аргументов; но если результат вызова метода toString равен нулю, тогда строка "пусто" используется вместо.

Метод toString определяется изначальным классом Object; много классы переопределяют его, в частности, Boolean, Character, Integer, Long, Float, Двойной и струнный.

15.18.1.2 Оптимизация конкатенации строк

Реализация может выбрать выполнение преобразования и объединения за один шаг, чтобы избежать создания, а затем отказаться от промежуточного Строковый объект. Для увеличения производительности повторяющейся строки конкатенации, компилятор Java может использовать класс StringBuffer или аналогичная техника для уменьшения количества промежуточных строковых объектов которые создаются путем оценки выражения. Для примитивных типов, реализация также может оптимизировать создание оболочки объект путем преобразования непосредственно из примитивного типа в строку.

Оптимизированная версия на самом деле не будет выполнять полное преобразование строк вначале.

Это хорошая иллюстрация оптимизированной версии, используемой компилятором, хотя и без преобразования примитива, где вы можете видеть, как компилятор превращает вещи в StringBuilder в фоновом режиме:

http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/

Этот код Java:

public static void main(String[] args) {
    String cip = "cip";
    String ciop = "ciop";
    String plus = cip + ciop;
    String build = new StringBuilder(cip).append(ciop).toString();
}

Создает это - посмотрите, как два стиля объединения приводят к одному и тому же байт-коду:

 L0
    LINENUMBER 23 L0
    LDC "cip"
    ASTORE 1
   L1
    LINENUMBER 24 L1
    LDC "ciop"
    ASTORE 2
// cip + ciop
   L2
    LINENUMBER 25 L2

    NEW java/lang/StringBuilder
    DUP
    ALOAD 1
    INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;

    ASTORE 3
    // new StringBuilder(cip).append(ciop).toString()
   L3
    LINENUMBER 26 L3

    NEW java/lang/StringBuilder
    DUP
    ALOAD 1
    INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
    ALOAD 2
    INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
    INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;

    ASTORE 4
   L4
    LINENUMBER 27 L4
    RETURN

Компилятор преобразовал "cip + ciop" в "новый StringBuilder (cip) .append (ciop) .toString ()". Другими словами, «+» фактически является сокращением для более многословной идиомы StringBuilder.

1 голос
/ 04 ноября 2011

Java поддерживает ограниченную перегрузку операторов ... для встроенных операторов с определенными комбинациями (примитивных) типов операндов. Основные случаи:

  • Арифметические операторы имеют перегрузки для различных типов числовых примитивов. Оператор '+' дополнительно перегружен для объединения строк.

  • '&', '|', '^' и '!' операторы перегружены для (без короткого замыкания) логических и побитовых интегральных операций.

Однако Java не поддерживает какую-либо форму определенных программистом операторов или перегрузку операторов.


Ответы, в которых говорится, что перегрузка - это «магия компилятора» или что «это делает компилятор», не имеют смысла. Спецификация языка Java говорит, что он является частью языка, что он означает, и (в значительной степени) определяет, как он должен быть реализован.


Как указывает другой ответ, автобокс / распаковка и другие вещи (строго говоря) преобразования и не перегружены. Так, например:

int j = ...
Integer i = ...
j = j + i;

При этом используется перегрузка (int, int) оператора '+' и автоматическая распаковка для преобразования второго операнда в int.

byte b = ...
j = j + b;

При этом используется перегрузка (int, int) оператора '+' и используется приведение для преобразования второго операнда в целое число.

Обратите внимание, что JLS определяет правила, которые определяют, какая перегрузка оператора используется на основе (начальных) типов операндов. Итак, во втором примере JLS предписывает использовать перегрузку (int, int) для «+», а не перегрузку (byte, byte).

0 голосов
/ 04 ноября 2011

Это все волшебство компилятора. Вы не можете выполнять перегрузку операторов в Java.

скрещивает пальцы и надеется, что это не ужасно неправильно и принесет мне 20 голосов

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