Javac 和基元:装箱与非装箱
我的问题是:为什么原始类型必须包装在对象中,而编译器也可以为您做好设置?
- 对原始值 x 的方法的调用可以从 x.call() 转换为 X.call(x) - 这就是我在下面尝试说明的内容。
- 泛型不会在运行时保留(对吗?),因此您不需要在运行时访问类信息 - 您可以简单地将 Integer 的每个实例替换为 int 并按上面的方式重写方法调用,然后结束与可执行代码。
所以基本上,我要问的是:我在这里错过了什么?
一段时间以来我一直想知道这个问题:为什么 Java 编译器不能将...翻译
int a = 482;
int b = 12;
System.out.println((a + b).toHexString());
成以下代码...
int a = 482;
int b = 12;
System.out.prinln(Ints.toHexString(a + b));
从而消除装箱和拆箱的全部需要?
(因此,将方法调用编译为(静态)函数调用,并保留 Int.class 的单个实例以备不时之需 - 例如在调用 Ints.getClass(_) 之后?)
为了清楚起见,添加了注释:
@Adam:不,我不认为这会导致 装箱/拆箱。该示例尝试 来说明基元是如何存在的 被视为语言中的对象, 但由编译器作为原语。 这将消除(轻微) 运行时的开销,以及令人困惑的 语言中的东西。因此 想要的问题正是:为什么 不是非常有才华的编译器吗 开发人员选择这个解决方案吗?因为如果他们不这样做,那里 我一定是明显不可能的 没有看到。我想知道什么 这是。 – 佩皮恩
My question is: why do primitive types have to be wrapped in an object, when it is also a possibility to have the compiler set things right for you?
- calls to a primitive value x's methods can be translated from x.call() to X.call(x) - this is what I try to illustrate below.
- generics aren't kept around at runtime (right?), so it isn't the case that you need to access class information at runtime - you could simply replace every instance of Integer by int and rewrite method calls as above, and end up with executable code.
So basically, what I'm asking is: what am I missing here?
I've been wondering about this for some time: Why can't the Java compiler translate...
int a = 482;
int b = 12;
System.out.println((a + b).toHexString());
...to the following code...
int a = 482;
int b = 12;
System.out.prinln(Ints.toHexString(a + b));
...and thus remove the entire need for boxing and unboxing?
(Thus, compile method calls to (static) function calls, and keep a single instance of Int.class around in case it's needed - e.g. after a call of Ints.getClass(_)?)
Comment added for clarity:
@Adam: No, I do not think it causes
boxing/unboxing. The example attempts
to illustrate how primitives could be
treated as objects in the language,
but as primitives by the compiler.
This would remove the (slight)
overhead in runtime, and a confusing
thing in the language. Therefore the
intended question was exactly: why
didn't the extremely talented compiler
developers pick this solution? Because if they didn't, there
must be a clear impossibility that I'm
not seeing. And I'd like to know what
it is. – Pepijn
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
我认为您的意思是
Integer.toHexString
,而不是Ints.toHexString
。后者不是 java.lang 的一部分,编译器无法了解它的任何信息。理论上,如果 Java 语言指定了这样的转换,编译器可以将
(a + b).toHexString()
的调用转换为Integer.toHexString(a + b)
。 (例如,将int a
到Integer
的自动装箱指定为Integer.valueOf(a)
。)我猜想Java 语言维护者认为这对于 Java 程序员来说太“神奇”了——在所有版本的 Java 中,基本类型都没有方法或字段。一般来说,Java 的设计是为了避免语法糖——这就是为什么它通常比大多数其他语言更冗长的原因。
I presume you meant
Integer.toHexString
, notInts.toHexString
. The latter is not part ofjava.lang
and the compiler would have no way to know anything about it.In theory, the compiler could translate calls of
(a + b).toHexString()
toInteger.toHexString(a + b)
, if the Java language specifies such a translation. (For example, auto-boxing of anint a
to anInteger
is specified to beInteger.valueOf(a)
.)I guess the Java language maintainers decided that that is too "magical" for Java programmers---in all versions of Java, primitive types do not have methods or fields. Java, in general, is designed to avoid syntactic sugar---that is why it's generally more verbose than most other languages.
因此,我们可以将原始类型调用的方法映射到其包装类型的静态方法,很好。
这根本与装箱/拆箱无关,它只是以另一种方式编写相同方法调用的语法糖 - 并且只有相当少量的方法,这些方法在包装类中预定义。
当您想要将原始值视为对象时,装箱是必要的,例如:
这些特殊(但非常重要)的情况是:
拆箱 如果我们得到这样一个装箱的基元并希望拥有它的纯形式,那么拆箱是必要的,例如在调用返回对象的方法之后,或者从变量获取值之后。
在 Java 5(或 1.5)之前,我们必须通过
.valueOf()
方法或toXXX()
手动完成所有装箱和拆箱操作。现在,只要有必要,它就会自动完成(自动装箱)。So, we could map methods called on primitive types to static methods of their wrapper types, fine.
This does not relate to boxing/unboxing at all, it is only syntactic sugar to write the same method call in another way - and only a quite small number of methods, these predefined in the wrapper classes.
Boxing is necessary when you want to treat a primitive value as an object, for example:
Special (but quite important) cases of these are:
Unboxing is necessary if we got such a boxed primitive and want to have the pure form of it, for example after calling a method which returns objects, or taking the value from a variable.
Before Java 5 (or 1.5), we had to do all this boxing and unboxing manually, by the
.valueOf()
method ortoXXX()
. Now it is done automatically whenever necessary (autoboxing).编译器会做什么?
这里需要一个 Integer 实例,因此需要装箱/拆箱。
What would the compiler do for
You need an instance of Integer here, hence the need for boxing/unboxing.