Javac 和基元:装箱与非装箱

发布于 2024-11-09 16:45:03 字数 893 浏览 8 评论 0原文

我的问题是:为什么原始类型必须包装在对象中,而编译器也可以为您做好设置?

  1. 对原始值 x 的方法的调用可以从 x.call() 转换为 X.call(x) - 这就是我在下面尝试说明的内容。
  2. 泛型不会在运行时保留(对吗?),因此您不需要在运行时访问类信息 - 您可以简单地将 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?

  1. 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.
  2. 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

断肠人 2024-11-16 16:45:03

我认为您的意思是 Integer.toHexString,而不是 Ints.toHexString。后者不是 java.lang 的一部分,编译器无法了解它的任何信息。

理论上,如果 Java 语言指定了这样的转换,编译器可以将 (a + b).toHexString() 的调用转换为 Integer.toHexString(a + b) 。 (例如,将 int aInteger 的自动装箱指定为 Integer.valueOf(a)。)

我猜想Java 语言维护者认为这对于 Java 程序员来说太“神奇”了——在所有版本的 Java 中,基本类型都没有方法或字段。一般来说,Java 的设计是为了避免语法糖——这就是为什么它通常比大多数其他语言更冗长的原因。

I presume you meant Integer.toHexString, not Ints.toHexString. The latter is not part of java.lang and the compiler would have no way to know anything about it.

In theory, the compiler could translate calls of (a + b).toHexString() to Integer.toHexString(a + b), if the Java language specifies such a translation. (For example, auto-boxing of an int a to an Integer is specified to be Integer.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.

恰似旧人归 2024-11-16 16:45:03

因此,我们可以将原始类型调用的方法映射到其包装类型的静态方法,很好。

这根本与装箱/拆箱无关,它只是以另一种方式编写相同方法调用的语法糖 - 并且只有相当少量的方法,这些方法在包装类中预定义。

当您想要将原始值视为对象时,装箱是必要的,例如:

  • 将其传递给仅接受对象的方法
  • 将其放入对象类型的变量中
  • 从必须将其返回的方法中返回它返回对象

这些特殊(但非常重要)的情况是:

  • 将其放入对象数组
  • 将其放入集合

拆箱 如果我们得到这样一个装箱的基元并希望拥有它的纯形式,那么拆箱是必要的,例如在调用返回对象的方法之后,或者从变量获取值之后。

在 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:

  • pass it to a method which only accepts objects
  • put it in a variable of object type
  • return it from a method which has to return objects

Special (but quite important) cases of these are:

  • put it into an object array
  • put it into a collection

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 or toXXX(). Now it is done automatically whenever necessary (autoboxing).

我家小可爱 2024-11-16 16:45:03

编译器会做什么?

List<Integer> list = new ArrayList<Integer>();
list.add(5);
int i = list.get(0);

这里需要一个 Integer 实例,因此需要装箱/拆箱。

What would the compiler do for

List<Integer> list = new ArrayList<Integer>();
list.add(5);
int i = list.get(0);

You need an instance of Integer here, hence the need for boxing/unboxing.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文