Почему 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).