Java自动装箱为什么不扩展到自动装箱类型的方法的方法调用?
我想将原语转换为字符串,然后尝试执行以下操作:
myInt.toString();
失败并显示以下错误:
int cannot be dereferenced
现在,我知道原语不是引用类型(即,不是对象),因此不能具有方法。但是,Java 5引入了自动装箱和拆箱功能(一种C#...我在C#中从未喜欢过,但这不重要)。因此,对于自动装箱,我希望上面的方法将myInt转换为Integer,然后在其上调用toString()。
此外,除非我记错了,否则我相信Callow会打这样的电话。这仅仅是Java自动装箱/拆箱规范的不幸缺点,还是有充分的理由呢?
解决方案
回答
Java自动装箱/拆箱的程度无法允许我们取消引用原语,因此编译器会禁止它。编译器仍将myInt
理解为原语。 jcp.org上有一篇有关此问题的论文。
自动装箱主要在分配或者参数传递期间很有用-允许我们将基元作为对象传递(反之亦然),或者将基元分配给对象(反之亦然)。
所以不幸的是,我们必须这样做:(向Patrick致敬,我转而使用方式)
Integer.toString(myInt);
回答
与贾斯汀说的话一样,但我们应该这样做:
Integer.toString(myInt);
它可以节省一两个分配,并且可读性更好。
回答
seems like a shortcoming of the specification to me
还有很多缺点,这是一个微妙的话题。看一下这个:
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);
对于每个基本类型和"对象",此方法都将重载。这样,我们甚至不必考虑所使用的类型。方法的实现将为我们调用给定类型的适当方法,例如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上的一个奇怪的麻烦。查看这篇文章,了解有关它有多奇怪的更多信息。