为什么Java自动装箱不会扩展到自动装箱类型方法的方法调用?

时间:2008-08-07 01:05:15

标签: java autoboxing

我想将原语转换为字符串,我尝试了:

myInt.toString();

失败并显示错误:

int cannot be dereferenced

现在,我得到的原语不是引用类型(即不是Object),所以不能有方法。然而,Java 5引入了自动装箱和拆箱(一个C#......我在C#中从未喜欢过,但这不是重点)。因此,使用自动装箱,我希望上面的内容将myInt转换为Integer,然后调用toString()。

此外,我相信C#允许这样的电话,除非我记错了。这只是Java自动装箱/拆箱规范的一个不幸的缺点,还是有充分的理由呢?

8 个答案:

答案 0 :(得分:45)

Java autoboxing / unboxing不会允许您取消引用原语,因此编译器会阻止它。您的编译器仍然将myInt视为基元。在jcp.org有一篇关于这个问题的论文。

在分配或参数传递期间,自动装箱主要是有用的 - 允许您将基元作为对象传递(反之亦然),或者将基元传递给对象(反之亦然)。

所以不幸的是,你必须这样做:(荣誉帕特里克,我改用你的方式)

Integer.toString(myInt);

答案 1 :(得分:27)

与贾斯汀所说的相同,但你应该这样做:

Integer.toString(myInt);

它可以保存一两个分配,并且更具可读性。

答案 2 :(得分:15)

另一种方法是使用:

String.valueOf(myInt);

对于每种基本类型和Object,此方法都会重载。这样你甚至不必考虑你正在使用的类型。该方法的实现将为您调用给定类型的适当方法,例如Integer.toString(myInt)

请参阅http://java.sun.com/javase/6/docs/api/java/lang/String.html

答案 3 :(得分:9)

  

似乎是一个缺点   给我的规范

还有更多缺点,这是一个微妙的话题。检查this

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”(我自己没有检查过),因为编译器选择扩大自动装箱。使用自动装箱时要小心,或者根本不使用它!

答案 4 :(得分:5)

最接近您的示例的有效语法是

((Integer) myInt).toString();

当编译器完成时,这相当于

Integer.valueOf(myInt).toString();

然而,这并不像传统的用法String.valueOf(myInt)那样好,因为除了特殊情况,它会创建一个新的Integer实例,然后立即抛出它,导致更多不必要的垃圾。 (缓存了一小部分整数,并通过数组访问进行访问。)语言设计人员可能出于性能原因而不鼓励这种用法。

编辑:如果downvoter(s)会评论为什么这没有用,我会很感激。

答案 5 :(得分:1)

在C#中,整数既不是引用类型也不是必须加框,以便调用 ToString()。然而,它们 被认为是框架中的对象(作为ValueType,因此它们具有值语义)。在CLR中,通过“间接”将它们加载到堆栈(ldind)来调用基元上的方法。

答案 6 :(得分:1)

正如大家所指出的那样,自动装箱可以让你简化一些代码,但你不能假装原语是复杂的类型。

同样有趣:Java中的"autoboxing is a compiler-level hack"。 Autoboxing基本上是一个添加到Java上的奇怪的kludge。查看this post了解有关它有多奇怪的详细信息。

答案 7 :(得分:1)

如果Java定义了某些静态方法来操作基本类型并在编译器中内置了一些语法糖,那将会很有帮助

5.asInteger

等同于

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

我认为这样的功能不会导致与根据当前规则编译的任何代码不兼容,并且在许多情况下它将有助于减少语法混乱。如果Java是被解除引用的autobox原语,人们可能会认为它正在将解除引用语法映射到静态方法调用(这实际上是.NET中发生的事情),因此以这种形式编写的操作并不比它更昂贵。等效的静态方法调用。添加一个鼓励人们编写错误代码的新语言功能(例如自动装箱解除引用的原语)似乎不是一个好主意,尽管允许使用解引用方式。