题
我想将原语转换为字符串,我尝试过:
myInt.toString();
此操作失败并出现以下错误:
int cannot be dereferenced
现在,我知道基元不是引用类型(即不是对象),因此不能有方法。然而,Java 5 引入了自动装箱和拆箱(类似于 C#...我在 C# 中从来不喜欢它,但这不是重点)。因此,通过自动装箱,我希望上面的代码将 myInt 转换为 Integer,然后调用 toString() 。
此外,我相信 C# 允许这样的调用,除非我记错了。这只是 Java 的自动装箱/拆箱规范的一个不幸的缺点,还是有充分的理由?
解决方案
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 实例,然后立即将其丢弃,从而导致更多不必要的垃圾。(一小部分整数被缓存,并通过数组访问进行访问。)也许出于性能原因,语言设计者希望阻止这种用法。
编辑:如果投反对票的人能评论一下为什么这没有帮助,我将不胜感激。
在 C# 中,整数既不是引用类型,也不必装箱才能使用 ToString() 被称为。他们 是 但是,考虑了框架中的对象(作为 ValueType,因此它们具有值语义)。在 CLR 中,基元上的方法是通过“间接”将它们加载到堆栈 (ldind) 来调用的。
正如每个人都指出的那样,自动装箱可以让您简化一些代码,但您不能假装基元是复杂类型。
同样有趣的是: “自动装箱是一种编译器级黑客” 在爪哇。自动装箱基本上是添加到 Java 上的一个奇怪的组合。查看 这个帖子 了解更多关于它有多奇怪的细节。
如果 Java 定义了某些静态方法来对基本类型进行操作,并在编译器中内置了一些语法糖,那么这将会很有帮助
5.asInteger
将相当于
some.magic.stuff.Integer.asInteger(5);
我认为这样的功能不会导致与在当前规则下编译的任何代码不兼容,并且在许多情况下它将有助于减少语法混乱。如果 Java 自动装箱取消引用的原语,人们可能会认为它将取消引用语法映射到静态方法调用(这实际上是 .NET 中发生的情况),因此以这种形式编写的操作并不比等效的静态方法调用。添加新的语言功能会鼓励人们编写糟糕的代码(例如自动装箱解引用原语)似乎不是一个好主意,尽管允许解引用样式的方法可能是一个好主意。