Java中的数字包装类

时间:2010-01-09 00:32:10

标签: java

我来自PHP世界,我很困惑在java中声明对象时如何思考。

所以传统上你喜欢这样:

 Rectangle rect = new Rectangle();

原因rect是Rectangle数据类型。

根据java教程页面,数字包装类是Number的子类。 所以它是一个类但是当你实例化时,教程就是这样的:

 Integer x;
 x = 12;

为什么它不像传统方式那样:

 Integer x = new Integer(12);
 or
 Integer x = new Integer();

这是另一个例子:

 String s = new Integer(i).toString();

所以这里是一个String对象。我得到了。但你得到了新的整数(i)。为什么新的?它在这里意味着什么以及当它向构造函数发送'i'时会发生什么。我在哪里可以看到构造函数在java API中使用参数做了什么?

很多问题,但无法在网上找到解释它的来源。

5 个答案:

答案 0 :(得分:10)

首先,您可以使用原始类型:

int x = 12;
double d = 3.3456;

其次,您可以选择对这些数字使用对象包装器:

Integer x = new Integer(12);
Double d = new Double(3.3456);

第三,如果你想要字符串表示,你只需使用:

即可
String s = Integer.toString(12);

或只是:

int x;
String s = "x = " + x;

甚至是printf()语法:

int x = 12;
String s = String.format("x = %d", x);

最后,自版本5以来的Java支持自动装箱和拆箱,如果你不期待它可能会让你感到困惑。例如:

Integer i = 1234; // autoboxes int to Integer

int i = new Integer(1234); // autounboxes Integer to an int

除非需要Number包装,否则只需使用基本类型。使用它们的最常见原因是将它们放入集合(List s等)。

答案 1 :(得分:7)

您在第一个示例中看到的内容称为autoboxing / autounboxing。 Java(从版本5开始)将自动在5Integer.valueOf(5)之间进行转换,后者从int原语构造类型为Integer的包装器。但后者(Integer x = new Integer(12))绝对正确。

但是,如果你想写5.toString()之类的东西,它在第二种情况下不会那样工作。仅当将基元分配给包装器类型,或者在期望包装器类型的位置传递基元时,才会发生自动装箱。原始类型不是对象,因此没有要引用的属性。

Re:“为什么是新的”,这是因为Java中的所有引用(非原始)类型都是在堆上动态分配的。所以(除了autoboxing),获得Integer(或其他引用类型)的唯一方法是为一个显式分配空间。

答案 2 :(得分:2)

其他答案尚未解决的一些事情:

Integer x = new Integer();

这不起作用,因为Integer类没有no-args构造函数(结果对象的int值是什么?)。

String s = new Integer(i).toString();
  

所以这里是一个String对象。我   得到。但你得到了新的整数(i)。为什么   新?这是什么意思和什么   当它发送'i'时发生   构造函数。我在哪里可以看到什么   构造函数正在做的   java API中的参数?

它与上面的含义相同:创建Integer对象,将变量i的内容(可能是循环索引)作为构造函数参数传递,然后生成对象的{{1}调用方法,它产生数字的字符串表示。

至于您可以在哪里查找这些内容,Java API doc详细介绍了标准API的所有方面。如果这还不够,Sun的JDK会附带标准API的完整源代码。安装JDK时,您可以选择获取此源代码,大多数IDE都允许您轻松跳转到它。

答案 3 :(得分:1)

除了对象之外,Java还包括原始数据类型,如boolean,byte,int,long,char,float,double。所有这些都以小写字母表示,并与字面值一起使用。这些总是按值传递。

还可以使用匹配的Number对象Boolean,Byte,Integer,Long等,它们像所有对象一样,通过引用传递。因为这些是对象而不是基元,所以需要注意不同的性能含义和特征。

现代Java具有自动装箱和自动拆箱功能,可以在原语和对象之间进行静默转换,允许使用语法Integer i = 5将原语5自动放入对象Integer }。以前,您必须使用原始int i = 5或基于显式对象的语法Integer i = new Integer(5)而不是现在混合类型。

答案 4 :(得分:1)

这种奇怪的行为:

Integer x;
x = 12;

归因于java autoboxing

一些历史:

在Java 1.5之前,它是不允许的。你有原语(int, char, byte, boolean, float, double,long),Java世界的其余部分是类(包括相应的包装器:Integer, Character, Byte, Booelan, Float, Double, Long)。

Java的核心数据结构与Objects一起使用,因此如果您需要将数字存储到列表中,则必须“包装”您的值(包装器只是包含基本类型的常规类)

例如,这可能是我自己的int包装器:

 public class Entero { // integer in spanish... :P 
     private final int wrappedInt;

     public Entero( int i ) {
         this.wrappedInt = i;
     }

     public int getEntero() {
         return wrappedInt;
     }
 }

没什么好看的,一般来说就是如何实现“包装”类(当然有很多实用方法)

所以,再次,如果你想在List(只包含Objects)中使用它,你将不得不:

 List list = // get the list from somewhere.... 
 list.add( new Integer( 1024 ) ); // wrap it
 .... 
 // use the list and at some point iterate it:
 Iterator iterator = list.iterator();
 while( iterator.hasNext() ) {
     Integer e = ( Integer ) iterator.next(); // unwrap it
     i = e.intValue();
 }

致电

 list.add( 1024 )

直接无法进行,因为1024int字面值,而不是对象。

多年来,这些代码就是这样编写的。

由于Java 1.5添加了基本上是语法糖的自动装箱,现在“new Integer(i)/ integer.intValue()”由编译器注入引擎盖,代码变为:

list.add( 1024 ); // wrapped in the compiled code in the the .class file that is.
....
Iterator i = list.iterator();
while( i.hasNext() ) {
    int i = ( Integer ) i.next(); // unwrapped for you by the compiler under the hood
}

从源代码中删除包装过程。

此外,使用泛型,您还保存了转换:

 List<Integer> list = .... // <- you still have to say the list is of "Integers" not "int"

 .... 
 Iterator<Integer> i = list.iterator(); // The iterator has to use the "<Integer>"  generic mark
 while( i.hasNext() ){
     int x = i.next(); // but you can get the value directly. 
 }

基本上,泛型是一个标记,说“检查使用的是这种类型,不再打扰我”,但泛型是另一个主题。