Почему Java Autoboxing не распространяется на вызовы методов для типов Autoboxed?

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

myInt.toString();

Это терпит неудачу с ошибкой:

int cannot be dereferenced

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

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

8 ответов

Решение

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

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

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

Integer.toString(myInt);

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

Integer.toString(myInt);

Это сохраняет распределение или два и более читабельно.

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

String.valueOf(myInt);

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

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

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

Есть еще недостатки, и это тонкая тема. Проверьте это:

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" (сам не проверял), потому что компилятор выбирает расширение вместо автобокса. Будьте осторожны при использовании автобокса или не используйте его вообще!

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

((Integer) myInt).toString();

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

Integer.valueOf(myInt).toString();

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

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

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

5.asInteger

будет эквивалентно

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

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

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

Также интересно: "Autoboxing - это хак на уровне компилятора" в Java. Автобокс - это в основном странный ключ, добавленный в Java. Проверьте этот пост для более подробной информации о том, как это странно.

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

Другие вопросы по тегам