为什么有些语言需要装箱和拆箱?

2022-09-01 05:03:59

这不是什么是装箱和拆箱的问题,而是为什么像Java和C#这样的语言需要它?

我非常熟悉C++,STL和Boost。

在C++我可以很容易地写出这样的东西,

std::vector<double> dummy;

我有一些Java的经验,但我真的很惊讶,因为我不得不写这样的东西,

ArrayList<Double> dummy = new ArrayList<Double>();

我的问题是,为什么它应该是一个对象,在谈论泛型时,技术上很难包括基元类型?


答案 1

在谈论泛型时,技术上很难包含基元类型吗?

在Java的情况下,这是因为泛型的工作方式。在Java中,泛型是一种编译时技巧,可以防止您将对象放入.但是,Java 的泛型是通过类型擦除实现的:泛型类型信息在运行时丢失。这是出于兼容性原因,因为泛型是在Java的生命周期中相当晚才添加的。这意味着,在运行时,an 实际上是一个(或更好:在其所有方法中期望并返回的),它会在检索值时自动强制转换为。ImageArrayList<String>ArrayList<String>ArrayList<Object>ArrayListObjectString

但是由于 它不是从 派生的,你不能把它放在一个期望的 ArrayList 中(在运行时),你也不能把 一个 强制转换为。这意味着必须将基元包装到继承自 的类型中,如 。intObjectObjectObjectintintObjectInteger

例如,C# 的工作方式不同。C# 中的泛型在运行时也是强制实施的,并且不需要使用 .仅当您尝试存储值类型(如 引用类型变量(如 )时,才会在 C# 中装箱。由于在 C# 中继承自 C#,因此写入是完全有效的,但是 int 将被装箱,这是由编译器自动完成的(没有引用类型向用户或任何东西公开)。List<int>intobjectintObjectobject obj = 2Integer


答案 2

装箱和拆箱是一种必需品,源于语言(如C#和Java)实现其内存分配策略的方式。

某些类型在堆栈上分配,其他类型在堆上分配。为了将堆栈分配的类型视为堆分配类型,需要装箱将堆栈分配的类型移动到堆上。拆箱是相反的过程。

在 C# 中,堆栈分配的类型称为值类型(例如 和 ) 和堆分配类型称为引用类型(例如 和 )。System.Int32System.DateTimeSystem.StreamSystem.String

在某些情况下,能够将值类型视为引用类型是有利的(反射就是一个例子),但在大多数情况下,最好避免装箱和取消装箱。


推荐