我来自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中使用参数做了什么?
很多问题,但无法在网上找到解释它的来源。
答案 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开始)将自动在5
和Integer.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 )
直接无法进行,因为1024
是int
字面值,而不是对象。
多年来,这些代码就是这样编写的。
由于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.
}
基本上,泛型是一个标记,说“检查使用的是这种类型,不再打扰我”,但泛型是另一个主题。