为什么Java自动装箱不能扩展到自动装箱types方法的方法调用?
我想将一个原语转换成一个string,我试过:
myInt.toString();
这失败了,错误:
int cannot be dereferenced
现在,我得到的原语不是引用types(即不是一个对象),所以不能有方法。 然而,Java 5引入了自动装箱和拆箱(一个C#…我从来不喜欢的C#,但这是旁边的点)。 所以与自动装箱,我期望上述将myInt转换为一个整数,然后调用toString()。
此外,我相信C#允许这样的通话,除非我记错了。 这只是Java的自动装箱/拆箱规格的一个不幸的缺点,还是有一个很好的理由呢?
Java autoboxing / unboxing没有达到允许你解引用原语的程度,所以你的编译器会阻止它。 你的编译器仍然知道myInt
是一个原语。 在jcp.org上有一篇关于这个问题的文章 。
自动装箱在分配或parameter passing过程中非常有用 – 允许您将原语作为对象传递(反之亦然),或者将对象分配给对象(反之亦然)。
所以不幸的是,你必须这样做:(荣誉帕特里克,我切换到你的方式)
Integer.toString(myInt);
同上贾斯廷说,但你应该这样做,而不是:
Integer.toString(myInt);
它节省了一个或两个分配,更具可读性。
另一种方法是使用:
String.valueOf(myInt);
这个方法对每一个原始types和Object
都是重载的。 这样你甚至不必考虑你正在使用的types。 该方法的实现将为您调用给定types的适当方法,例如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”会被打印(我自己也没有检查过),因为编译器select了自动装箱。 使用自动装箱时请务必小心,否则请勿使用!
最接近你的例子的有效句法是
((Integer) myInt).toString();
当编译器结束时,这相当于
Integer.valueOf(myInt).toString();
然而,这并不像传统用法String.valueOf(myInt)
,因为除了特殊情况,它会创build一个新的Integer实例,然后立即抛出,导致更多的不必要的垃圾。 (一小部分整数被caching,并且通过一个数组访问来访问。)也许语言devise者为了性能的原因想要阻止这种使用。
编辑:我会很感激,如果downvoter(s)会评论为什么这是没有帮助的。
在C#中,整数既不是引用types,也不必为了ToString()被调用而被装箱。 但是,它们被认为是框架中的对象(作为ValueType,因此它们具有值语义)。 在CLR中,基元上的方法通过“间接”加载到堆栈(ldind)来调用。
正如大家所指出的,自动装箱可以让你简化一些代码,但是你不能假装原始代码是复杂的types。
另外有趣的是:Java中的“autoboxing是编译器级别的黑客攻击” 。 自动装箱基本上是添加到Java上的一个奇怪的kludge。 看看这个post ,了解它有多奇怪的更多细节。
如果Java定义了某些静态方法来操作原始types,并在编译器中构build了一些语法糖,那将是有帮助的
5.asInteger
将相当于
some.magic.stuff.Integer.asInteger(5);
我不认为这样的特性会导致与现有规则下编译的任何代码不兼容,并且在很多情况下这将有助于减less语法混乱。 如果Java是自动复制被解引用的原语,那么人们可能会认为它是将解引用语法映射到静态方法调用(这实际上是.NET中发生的事情),因此用这种forms编写的操作不会比等价的静态方法调用。 添加一个鼓励人们编写不好的代码的新语言特性(例如自动装箱解除引用的原语)似乎不是一个好主意,尽pipe允许使用解引用样式的方法。