Naf*_*Kay 157 java primitive autoboxing jdk1.5 primitive-types
从Java 5开始,我们已经对原始类型进行了装箱/拆箱,因此它int被包装成java.lang.Integer等等.
我最近看到了很多新的Java项目(肯定需要一个至少版本为5的JRE,如果不是6个),int而不是java.lang.Integer使用后者,尽管使用后者要方便得多,因为它有一些帮助方法可以转换到long的值等.
为什么有些人仍然在Java中使用原始类型?有什么实际好处吗?
cor*_*iKa 380
在Joshua Bloch的Effective Java,第5项:"避免创建不必要的对象"中,他发布了以下代码示例:
public static void main(String[] args) {
Long sum = 0L; // uses Long, not long
for (long i = 0; i <= Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
}
Run Code Online (Sandbox Code Playgroud)
运行需要43秒.将Long带入原语使其降至6.8秒......如果这表明我们为什么使用原语.
缺乏本土价值平等也是一个问题(.equals()相比之下相当冗长==)
对于biziclop:
class Biziclop {
public static void main(String[] args) {
System.out.println(new Integer(5) == new Integer(5));
System.out.println(new Integer(500) == new Integer(500));
System.out.println(Integer.valueOf(5) == Integer.valueOf(5));
System.out.println(Integer.valueOf(500) == Integer.valueOf(500));
}
}
Run Code Online (Sandbox Code Playgroud)
结果是:
false
false
true
false
Run Code Online (Sandbox Code Playgroud)
编辑 为什么(3)返回true和(4)返回false?
因为它们是两个不同的对象.最接近零的256个整数[-128; 缓存由JVM缓存,因此它们返回相同的对象.但是,超出该范围,它们不会被缓存,因此会创建一个新对象.为了使事情变得更复杂,JLS要求缓存至少 256个flyweights.如果需要,JVM实现者可以添加更多,这意味着它可以在最近的1024被缓存并且所有这些都返回true的系统上运行... #awkward
Hei*_*upp 82
自动装箱可能导致难以发现NPE
Integer in = null;
...
...
int i = in; // NPE at runtime
Run Code Online (Sandbox Code Playgroud)
在大多数情况下,null赋值in比上面的要少得多.
Dan*_*ker 40
原始类型:
int x = 1000;
int y = 1000;
Run Code Online (Sandbox Code Playgroud)
现在评估:
x == y
Run Code Online (Sandbox Code Playgroud)
是的true.不足为奇.现在尝试盒装类型:
Integer x = 1000;
Integer y = 1000;
Run Code Online (Sandbox Code Playgroud)
现在评估:
x == y
Run Code Online (Sandbox Code Playgroud)
是的false.大概.取决于运行时.这个理由够了吗?
xeh*_*puk 35
除了性能和内存问题,我还想提出另一个问题:List界面将被破坏int.
问题是重载remove()方法(remove(int)vs. remove(Object)). remove(Integer)总是会决定调用后者,因此你无法通过索引删除元素.
另一方面,尝试添加和删除时存在一个陷阱int:
final int i = 42;
final List<Integer> list = new ArrayList<Integer>();
list.add(i); // add(Object)
list.remove(i); // remove(int) - Ouch!
Run Code Online (Sandbox Code Playgroud)
Tom*_*don 27
你能想象一下吗?
for (int i=0; i<10000; i++) {
do something
}
Run Code Online (Sandbox Code Playgroud)
用java.lang.Integer循环?java.lang.Integer是不可变的,因此循环中的每个增量都会在堆上创建一个新的java对象,而不是仅使用单个JVM指令递增堆栈上的int.表演将是恶魔般的.
我真的不同意使用java.lang.Integer比使用int更方便.反之.自动装箱意味着你可以使用int,否则你将被迫使用Integer,java编译器会负责插入代码来为你创建新的Integer对象.Autoboxing就是允许你在编译器中插入相关的对象结构时使用一个期望Integer的int.它绝不会首先消除或减少对int的需求.通过自动装箱,您可以获得两全其美的效果.当您需要基于堆的Java对象时,会自动为您创建一个Integer,并且当您进行算术和本地计算时,您可以获得int的速度和效率.
Pet*_*ego 19
基本类型有很多速度快:
int i;
i++;
Run Code Online (Sandbox Code Playgroud)
整数(所有数字和字符串)都是不可变类型:一旦创建,就无法更改.如果i是Integer,i++则会创建一个新的Integer对象 - 在内存和处理器方面要贵得多.
biz*_*lop 16
首先,习惯.如果你用Java编写了八年,你就会积累相当多的惯性.如果没有令人信服的理由,为什么要改变呢?这并不是说使用盒装基元带来任何额外的优势.
另一个原因是断言这null不是一个有效的选择.将两个数字或一个循环变量的总和声明为是毫无意义和误导Integer.
它的性能方面也是如此,而性能差异在许多情况下并不重要(尽管它很糟糕),没有人喜欢编写可以更快速地编写代码的代码我们已经以前.
Paŭ*_*ann 12
顺便说一句,Smalltalk只有对象(没有基元),但他们已经优化了它们的小整数(不是全部使用32位,只有27位或者这样),不分配任何堆空间,而只是使用特殊的位模式.此外,其他常见对象(true,false,null)也有特殊的位模式.
因此,至少在64位JVM(具有64位指针命名空间)上应该可以没有任何Integer,Character,Byte,Short,Boolean,Float(和小Long)的对象(除了这些创建之外)通过显式new ...()),只有特殊的位模式,可以非常有效地由普通操作员操纵.
我不敢相信没有人提到我认为最重要的原因:"int"是这样,键入比"Integer"容易得多.我认为人们低估了简洁语法的重要性.性能并不是避免它们的真正原因,因为大多数时候使用数字都在循环索引中,并且在任何非平凡的循环中无论是使用int还是Integer,递增和比较这些都不会产生任何成本.
另一个给出的原因是你可以获得NPE,但使用盒装类型非常容易避免(只要你总是将它们初始化为非空值,就可以避免它).
另一个原因是(new Long(1000))==(new Long(1000))是假的,但这只是说".equals"对盒装类型没有语法支持的另一种方式(不像运算符<,> ,=等等,所以我们回到"更简单的语法"的原因.
我认为Steve Yegge的非原始循环示例很好地说明了我的观点:http: //sites.google.com/site/steveyegge2/language-trickery-and-ejb
想想这个:你经常使用具有良好语法的语言中的函数类型(比如任何函数语言,python,ruby甚至是C),而java必须使用Runnable和Callable等接口来模拟它们.无名的课程.
几个理由不摆脱原始:
如果它被淘汰,任何旧程序都不会运行.
必须重写整个JVM才能支持这个新东西.
您需要存储使用更多内存的值和引用.如果你有一个庞大的字节数组,使用byte's'远远小于使用Byte's'.
int i然后声明做什么i会导致没有问题,但是声明Integer i然后做同样会导致NPE.
考虑以下代码:
Integer i1 = 5;
Integer i2 = 5;
i1 == i2; // Currently would be false.
Run Code Online (Sandbox Code Playgroud)
会是假的.操作员必须超载,这将导致重大的重写.
对象包装器比它们的原始对应物慢得多.
对象比原始类型重得多,因此原始类型比包装类的实例更有效.
基元类型非常简单:例如,int是32位,在内存中占用32位,可以直接操作.Integer对象是一个完整的对象,它(像任何对象一样)必须存储在堆上,并且只能通过它的引用(指针)来访问.它很可能也占用超过32位(4字节)的内存.
也就是说,Java在原始类型和非原始类型之间有区别这一事实也是Java编程语言时代的标志.较新的编程语言没有这种区别; 这种语言的编译器足够智能,如果您使用简单值或更复杂的对象,就可以自行计算出来.
例如,在Scala中没有原始类型; 有一个类Int用于整数,而Int是一个真实的对象(你可以使用方法等).当编译器编译代码时,它在幕后使用原始int,因此使用Int与在Java中使用原始int一样高效.
除了其他人所说的,原始局部变量不是从堆中分配的,而是在堆栈上分配的.但是对象是从堆中分配的,因此必须进行垃圾回收.
小智 5
int loops = 100000000;
long start = System.currentTimeMillis();
for (Long l = new Long(0); l<loops;l++) {
//System.out.println("Long: "+l);
}
System.out.println("Milliseconds taken to loop '"+loops+"' times around Long: "+ (System.currentTimeMillis()- start));
start = System.currentTimeMillis();
for (long l = 0; l<loops;l++) {
//System.out.println("long: "+l);
}
System.out.println("Milliseconds taken to loop '"+loops+"' times around long: "+ (System.currentTimeMillis()- start));
Run Code Online (Sandbox Code Playgroud)
在Long周围循环'100000000'的毫秒数:468
在长时间内循环"100000000"次的毫秒数:31
在旁注中,我不介意看到这样的东西发现它进入Java.
Integer loop1 = new Integer(0);
for (loop1.lessThan(1000)) {
...
}
Run Code Online (Sandbox Code Playgroud)
for循环自动将loop1从0增加到1000或
Integer loop1 = new Integer(1000);
for (loop1.greaterThan(0)) {
...
}
Run Code Online (Sandbox Code Playgroud)
for循环自动将loop1 1000减少为0.
| 归档时间: |
|
| 查看次数: |
69661 次 |
| 最近记录: |