Почему автобоксирование Java не распространяется на вызовы методов автоматически запакованных типов?

Я хочу преобразовать примитив в строку и попробовал:

myInt.toString();

Это не срабатывает с ошибкой:

int cannot be dereferenced

Теперь я понимаю, что примитивы не являются ссылочными типами (т. Е. Не объектом) и поэтому не могут иметь методов. Однако Java 5 представила автобоксирование и распаковку (а-ля C# ... что мне никогда не нравилось в C#, но это не относится к делу). Итак, с автобоксингом я ожидал, что приведенное выше преобразует myInt в Integer, а затем вызовет toString () для этого.

Более того, я считаю, что C# допускает такой вызов, если я не помню неправильно. Это просто досадный недостаток спецификации Java autoboxing / unboxing, или для этого есть веская причина?

Ответов (8)

Решение

Автоматическая упаковка / распаковка Java не позволяет вам разыменовать примитив, поэтому ваш компилятор предотвращает это. Ваш компилятор все еще знает myInt как примитив. На jcp.org есть статья об этой проблеме .

Автобоксинг в основном полезен во время присваивания или передачи параметров, позволяя вам передать примитив как объект (или наоборот) или назначить примитив объекту (или наоборот).

Так что, к сожалению, вам придется сделать это так: (Слава Патрику, я перешел на ваш путь)

Integer.toString(myInt);

Было бы полезно, если бы Java определила определенные статические методы для работы с примитивными типами и встроила в компилятор некоторый синтаксический сахар, чтобы

5.asInteger

было бы эквивалентно

some.magic.stuff.Integer.asInteger(5);

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

То же, что сказал Джастин, но вместо этого вам следует сделать следующее:

Integer.toString(myInt);

Это экономит выделение или два и более читабельно.

мне кажется недостатком спецификации

Недостатков больше, и это тонкая тема. Проверьте это :

public class methodOverloading{
   public static void hello(Integer x){
      System.out.println("Integer");
   }

   public static void hello(long x){
      System.out.println("long");
   }

   public static void main(String[] args){
      int i = 5;
      hello(i);
   }
}

Здесь будет напечатано "long" (сам не проверял), потому что компилятор выбирает расширение вместо автобокса. Будьте осторожны при использовании автобокса или не используйте его вообще!

Еще один способ сделать это - использовать:

String.valueOf(myInt);

Этот метод перегружен для каждого примитивного типа и Object . Таким образом, вам даже не нужно думать о том, какой тип вы используете. Реализации метода вызовут для вас соответствующий метод данного типа, например Integer.toString(myInt) .

См. http://java.sun.com/javase/6/docs/api/java/lang/String.html .

В C# целые числа не являются ссылочными типами, и их не нужно помещать в коробку для вызова ToString () . Они будут рассмотрены объекты в рамках (как ValueType, так что они имеют значение семантики), однако. В CLR методы примитивов вызываются «косвенной» загрузкой их в стек (ldind).

Действительный синтаксис, наиболее близкий к вашему примеру:

((Integer) myInt).toString();

Когда компилятор завершает работу, это эквивалентно

Integer.valueOf(myInt).toString();

Однако это не работает так же хорошо, как обычное использование, String.valueOf(myInt) потому что, за исключением особых случаев, он создает новый экземпляр Integer, а затем немедленно выбрасывает его, что приводит к дополнительному ненужному мусору. (Небольшой диапазон целых чисел кэшируется, и доступ осуществляется через массив.) Возможно, разработчики языка хотели воспрепятствовать такому использованию из соображений производительности.

Изменить: я был бы признателен, если бы те, кто проголосовал против, прокомментировали, почему это бесполезно.

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

Также интересно: «автобокс - это взлом на уровне компилятора» в Java. Автобокс - это, по сути, странный кладж, добавленный в Java. Прочтите этот пост, чтобы узнать, насколько это странно.