我在阅读更多Joel关于软件的内容时,看到Joel Spolsky提到了一种特定类型的程序员需要知道Java/C#(面向对象编程语言)中int
和Integer
之间的区别。
那么,这两者有什么区别呢?
我在阅读更多Joel关于软件的内容时,看到Joel Spolsky提到了一种特定类型的程序员需要知道Java/C#(面向对象编程语言)中int
和Integer
之间的区别。
那么,这两者有什么区别呢?
在Java中,int是一种基本类型,而Integer是一个对象。这意味着,如果您创建了一个新的Integer:
Integer i = new Integer(6);
您可以在i上调用一些方法:
String s = i.toString();//sets s the string representation of i
当使用 int 时:
int i = 6;
您不能对其调用任何方法,因为它只是一个基本类型。 因此:
String s = i.toString();//will not work!!!
会产生错误,因为int不是一个对象。
int是Java中很少有的原始类型之一(与char和其他一些类型一起)。我不确定百分之百,但我认为Integer对象基本上只有一个int属性和大量与该属性交互的方法(例如toString()方法)。因此,Integer是使用int的一种高级方式(就像String可能是使用一组字符的高级方式一样)。
我知道Java不是C,但由于我从未在C中编程过,这是我能找到的最接近答案的方式。
我将在上面提供的精彩回答基础上添加一些内容,讨论装箱和拆箱,以及这如何适用于Java(虽然C#也有)。我仅使用Java术语,因为我对此更加熟悉。
正如答案所提到的,int
只是一个数字(称为未包装类型),而Integer
是一个对象(其中包含数字,因此是包装类型)。在Java术语中,这意味着(除了不能在int
上调用方法之外),您不能将int
或其他非对象类型存储在集合(List
,Map
等)中。为了存储它们,您必须先将它们装箱成相应的包装类型。
从Java 5开始,有一种称为自动装箱和自动拆箱的东西,允许在幕后完成装箱/拆箱。对比一下:Java 5版本:
Deque<Integer> queue;
void add(int n) {
queue.add(n);
}
int remove() {
return queue.remove();
}
Java 1.4或更早版本(也没有泛型):
Deque queue;
void add(int n) {
queue.add(Integer.valueOf(n));
}
int remove() {
return ((Integer) queue.remove()).intValue();
}
需要注意的是,尽管Java 5版本中代码很简短,但两个版本都生成相同的字节码。因此,虽然自动装箱和自动拆箱非常方便,因为您可以写更少的代码,但这些操作实际上会在幕后发生,并带有相同的运行时成本,因此您仍然必须意识到它们的存在。
希望这可以帮助到您!
由于其他帖子中的一些描述与 C# 有关的技术细节不太准确,因此我在这里发帖。
正确的说法:int
是 System.Int32
的别名。
错误的说法:float
不是 System.Float
的别名,而是 System.Single
的别名。
在 C# 编程语言中,int
是保留关键字,是 System.Int32
值类型的别名。
然而,float
和 Float
并不相同,正确的系统类型是 System.Single
。有一些类似的类型也有保留关键字,但这些关键字并不直接匹配类型名称。
在 C# 中,“int
”和“System.Int32
”,以及其他一些关键字/系统类型对之间没有区别,除了定义枚举时。在枚举中,您可以指定要使用的存储大小,在这种情况下,只能使用保留关键字,而不能使用系统运行时类型名称。
int 变量中的值是存储在堆栈、内存中还是作为引用堆对象存储取决于上下文和如何使用它。
在方法中的声明:
int i;
定义一个类型为 System.Int32
的变量 i
,它可以在寄存器或堆栈上运行,具体取决于编译器的优化。同样的声明语句如果出现在一个类型(结构体或类)中,则会定义成员字段。如果出现在方法参数列表中,则会定义一个参数,其存储选项与局部变量相同。(请注意,如果你开始涉及迭代器方法,这段话将不再适用,这是完全不同的情况)
要获取一个堆对象,可以使用装箱操作:
object o = i;
这将在堆上创建一个内容盒子复制i
。在IL中,您可以直接访问堆对象上的方法,但在C#中,您需要将其强制转换回int,这将创建另一个副本。因此,在C#中很难更改堆上的对象,而不创建新的包装了新int值的盒子副本。(呃,这一段并不那么容易阅读。)
关于Java 1.5和自动装箱,在比较整数对象时会出现一个重要的“怪异”情况。
在Java中,值为-128到127的整数对象是不可变的(也就是说,对于一个特定的整数值,比如23,在你程序中实例化的所有整数值为23的Integer对象指向完全相同的对象)。
例如,下面的代码返回true:
Integer i1 = new Integer(127);
Integer i2 = new Integer(127);
System.out.println(i1 == i2); // true
虽然这会返回false:
Integer i1 = new Integer(128);
Integer i2 = new Integer(128);
System.out.println(i1 == i2); // false
== 操作符是按引用比较(变量是否指向同一对象)。
这个结果可能因所使用的JVM而异。Java 1.5中自动装箱的规范要求整数(-128到127)始终装箱到相同的包装器对象。
解决方案?=)在比较Integer对象时,应始终使用Integer.equals()方法。
System.out.println(i1.equals(i2)); // true
更多信息请查看java.net,示例请参考bexhuff.com
127
是从 sun.misc.VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
获取的。 - KNU在Java中,JVM有两种基本类型:1)原始类型和2)引用类型。int是原始类型,而Integer是类类型(这是引用类型的一种)。
原始值不与其他原始值共享状态。变量的类型为原始类型时,它始终保存该类型的原始值。
int aNumber = 4;
int anotherNum = aNumber;
aNumber += 6;
System.out.println(anotherNum); // Prints 4
对象是动态创建的类实例或数组。引用值(通常只是引用)是指向这些对象和特殊的null引用的指针,该引用不引用任何对象。同一对象可能有许多引用。
Integer aNumber = Integer.valueOf(4);
Integer anotherNumber = aNumber; // anotherNumber references the
// same object as aNumber
public int add(int a, int b) {
return a + b;
}
final int two = 2;
int sum = add(1, two);
变量two以原始整数类型2传递。而在
public int add(Integer a, Integer b) {
return a.intValue() + b.intValue();
}
final Integer two = Integer.valueOf(2);
int sum = add(Integer.valueOf(1), two);
@WolfmanDragon: 按引用传递的方式可以这样实现:
public void increment(int x) {
x = x + 1;
}
int a = 1;
increment(a);
// a is now 2
public void increment(Integer x) {
x = Integer.valueOf(x.intValue() + 1);
}
Integer a = Integer.valueOf(1);
increment(a);
// a is now 2
现在你看到区别了吗?
使用包装类有许多原因:
e.g. int i=10;
Integer用于创建整型数据类型的引用变量。
Integer a = new Integer();
你是否曾经编程过?那么 (int) 是你可以为变量设置的原始类型之一(就像 char,float 等)。
但是 Integer 是一个包装类,你可以使用它对 int 变量执行一些函数操作(例如将其转换为字符串或反之亦然...),但请注意包装类中的方法是静态的,因此你可以随时使用它们而无需创建 Integer 类的实例。 简而言之:
int x;
Integer y;
x和y都是int类型的变量,但y被一个Integer类包装,并有多个你可以使用的方法。如果你需要调用Integer包装类的一些函数,你可以简单地这样做。
Integer.toString(x);
请注意,x和y都是正确的,但如果你只想将它们用作原始类型,请使用简单形式(用于定义x)。