2010-01-25 84 views
27

在很高的层次上,我知道我们需要使用它们各自的包装类在Java集合中使用它们来“包装”原始数据类型,例如int和char。我想了解Java集合如何工作在低级别问:“为什么我们需要将原始数据类型包装为对象以便能够在集合中使用它们?”我事先感谢您的帮助。Java:为什么需要包装类?

+0

可能的重复[为什么Java中有包装类?](http://stackoverflow.com/questions/3579035/why-are-there-wrapper-classes -in-java) – nbro 2015-01-01 20:25:56

回答

18

在虚拟机级别,这是因为与引用类型(如java.lang.Object及其派生类型)相比,基本类型在内存中的表示方式非常不同。例如Java中的基本int在内存中只有4个字节,而一个Object本身至少占用8个字节,再加上另外4个字节来引用它。这种设计是CPU可以更有效地处理原始类型这一事实的简单反映。

所以你的问题“为什么需要包装类型”的一个答案是因为它使能的性能改进。

但是对于程序员来说,这样的区分会增加一些不受欢迎的认知开销(例如,不能在集合中使用int和float)。实际上,通过隐藏这种区别很可能进行语言设计---许多脚本语言做到这一点,CLR就是这么做的。从1.5开始,Java也是如此。这是通过让编译器以静默方式在原始表示和对象表示之间插入必要的转换(通常称为装箱/拆箱)来实现的。)

所以另一个回答你的问题是,“不,我们不需要它”,因为编译器会自动为你,并在一定程度上你可以忘记这是怎么回事幕后。

+1

您可以详细说明基本类型和引用类型是如何通过JVM存储在内存中的吗? – 2010-01-25 19:18:48

+2

@Midnight Blue - 阅读第一个答案(作者:Jon Skeet):http://stackoverflow.com/questions/2099695/java-array-is-stored-in-stack-or-heap。它更详细地解释了事物如何存储在JVM中以及何时存储。 – 2010-01-25 19:23:00

+0

@Justin N. - 感谢您的链接 – 2010-01-25 19:26:22

31

由于Java集合只能存储对象引用(因此您需要将基元存储在集合中)。

阅读关于Autoboxing的此短文,了解更多信息。

如果你想在细节坚韧的细节,它几乎可以归结为以下几点:

本地原语存储在堆栈。 Collections通过对Heap中Object的内存位置的引用来存储它们的值。为了获得一个本地基元的引用,你必须将该值(堆栈上的值并将其包装在Heap上存储)。

3

原始数据类型不能作为内存地址引用。这就是为什么我们需要用作原始值的占位符的包装器。这些值可以被突变和访问,重组,排序或随机化。

+1

咦? Java没有指针。 – BalusC 2010-01-25 19:11:07

+1

你写道:“这些值然后可以变异”。对于Java中的原始对象包装器,这实际上并不正确。它们都是不变的。 – Asaph 2010-01-25 19:13:53

+0

引用基本上是一个指针,只是更多一点限制。在我看来,他们应该把它称为指针而不是引用,因为“参考”这个术语非常具有误导性。 – helpermethod 2010-01-25 19:23:35

1

那么,原因是Java集合没有区分原始对象和对象。它将它们全部处理为Object,因此它将需要一个包装器。您可以轻松构建自己的不需要包装的集合类,但最终必须为每个类型char,int,float,double等构建一个乘以集合类型(Set,Map,列表,及其实施)。

你能想象这是多么无聊吗?实际上,它对于大多数应用程序使用无包装的性能几乎可以忽略不计。然而,如果你需要非常高的性能,一些原始集合的库也可用(例如http://www.joda.org/joda-primitives/

+0

集合的区分非常好:如果您尝试使用java基元,它们可以很好地处理对象并为编译错误打耳光! – 2010-01-25 19:24:17

4

要将集合类中的基元类型值存储,我们需要包装类。

1

收藏以泛型为基础。 Collection Framework旨在收集,存储和操作任何类的数据。所以它使用泛型类型。通过使用泛型,它能够存储您的声明中指定名称的ANY CLASS的数据。

现在,我们在其中要原始数据存储在其中收集的工作方式相同的方式不同的场景。我们无法使用ArrayList,HashSet等Collection类来存储原始数据,因为Collection类只能存储对象。因此,为了在Collection中存储基本类型,我们提供了包装类。

0

包装类提供了与相应数据类型相关的有用方法,您可以在某些情况下使用相应的数据类型。

一个简单的例子。考虑一下,

Integer x=new Integer(10); 
//to get the byte value of 10 
x.byteValue(); 

//but you can't do this, 
int x=10; 
x.byteValue(); //Wrong! 

你能明白这一点吗?

0

如果已知某个变量保持代表null的特定位模式或可用于查找Java虚拟机对象头的信息,并且读取给定引用的对象头的方法将固有地陷入如果考虑到与null相关联的位模式,那么JVM可以在假设有一个的情况下访问变量所标识的对象。如果一个变量可能包含某些不是有效引用但不是特定位模式的东西,则任何试图使用该变量的代码都必须首先检查它是否标识了一个对象。这会大大减慢JVM。

如果ObjectAnything衍生,并从Object派生类对象,而是来自Anything派生不同的类继承的原语,然后在64位实现它可能是实际地说,可能的比特的约3/4图案将代表double值低于2^512,它们中的1/8来表示范围+/- 1,152,921,504,606,846,975 long值,数十亿表示任何其他primitve的任何可能的值,并且1/256来识别对象。对Anything类型的东西的多种操作将比Object类型的操作要慢,但这种操作不会非常频繁;在尝试使用它之前,大多数代码最终会将Anything转换为更具体的类型;存储在Anything中的实际类型将需要在投射前进行检查,但在演员执行后不需要进行检查。然而,如果没有区分引用堆类型的变量,而不是区分持有“任何”引用的变量,那么将无法避免使开销远远超过其他方法或应该进行的延伸。

0

很像String类,包装器提供额外的功能,并启用程序员做更多的数据存储的过程。所以,以同样的方式的人使用String类一样....

String uglyString = "fUbAr"; String myStr = uglyString.toLower();

也是如此,它们可以与包装。类似的想法。

这是除了Bharat上面提到的集合/泛型的打字问题外。

0

阅读所有的答案,但没有一个真正解释它只是通俗的术语。

包装类包装(封装)围绕一个数据类型(可以是任何原始数据类型如int,焦炭,字节长),并使其成为一个对象

这里有几个原因需要包装类:

  1. 允许null值。
  2. 可以在收集诸如ListMap使用等
  3. 能在它接受Object类型的参数的方法中使用。

    Integer wrapperInt = new Integer("10"); 
    
  4. 使所有可用的函数Object类具有诸如clone()equals()hashCode()toString()

包装器类:

  • 能像使用new ClassName()像其他对象的对象被创建可以通过两种方式创建:

    1. 使用构造函数:

      Integer i = new Integer("1"); //new object is created 
      
    2. 使用valueOf()静态运营商:

      Integer i = Integer.valueOf("100"); //100 is stored in variable 
      

    它建议使用创建的包装类的第二种方式,因为它需要较少的内存作为新对象未创建。

  • 0

    因为int不属于任何类。 我们将数据类型(int)转换为对象(Interger)

    相关问题