22 个回答
这个问题,还是直接看Java官方的文档就行了。
文档里面说:
Autoboxing is the automatic conversion that the Java compiler makes between the primitive types and their corresponding object wrapper classes.
自动装箱(拆箱也是)是 Java编译器 提供的原始类型和它的包装类之间转化的功能。
注意看,自动装箱和拆箱是 Java编译器 的功能,并不是运行时的。
至于编译器如何做到的,文档里面给了例子,以Integer 个int 之间相互转化为例,int 转 Integer:
// 编写的代码
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(i);
// Java 编译器把上面的代码转换成了下面的样子
List<Integer> li = new ArrayList<>();
for (int i = 1; i < 50; i += 2)
li.add(Integer.valueOf(i));
反过来,Integer 转 int:
// 编写的代码
public static int sumEven(List<Integer> li) {
int sum = 0;
for (Integer i: li)
if (i % 2 == 0)
sum += i;
return sum;
// 编译器把上面的代码转化成了下面的样子
public static int sumEven(List<Integer> li) {
int sum = 0;
for (Integer i : li)
if (i.intValue() % 2 == 0)
sum += i.intValue();
return sum;
}
所以简单起来总结就是一句话:
Java中int和Integer互转,原理是Java编译器帮你调用了包装类的valueOf() 和 intValue() 两个方法。
本质上,就是个语法糖。
参考:
最后,欢迎关注我的个人网站:
请大家在回答这种基础的问题前,先亲自去反编译看一看,而不是在这里误导别人。
对于这段代码:
class Main {
public static void main(String[] args) {
Integer a = 0;
int b = a;
Double c = 0.0;
double d = c;
}
无论是Java8还是Java11,我编译出来的字节码都是这个结果:
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: (0x0009) ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=6, args_size=1
0: iconst_0
1: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
4: astore_1
5: aload_1
6: invokevirtual #3 // Method java/lang/Integer.intValue:()I
9: istore_2
10: dconst_0
11: invokestatic #4 // Method java/lang/Double.valueOf:(D)Ljava/lang/Double;
14: astore_3
15: aload_3
16: invokevirtual #5 // Method java/lang/Double.doubleValue:()D
19: dstore 4
21: return
LineNumberTable:
line 3: 0
line 4: 5
line 5: 10
line 6: 15
line 7: 21
翻译成人话就是这样:
class Main {
public static void main(String[] args) {
Integer a = Integer.valueOf(0);
int b = a.intValue();
Double c = Double.valueOf(0.0);
double d = c.doubleValue();
}
题主你有兴趣的话可以把这一段也反编译看一看,和上面是一模一样的,无论Java11还是Java8,这两段代码的编译结果没有任何区别。
基本类型自动装箱,就是编译期自动调用对应封装类的静态方法
valueOf
;封装类的自动拆箱,就是编译期自动调用
java.lang.Number
对应子类的实例成员方法。
至于封装类的构造函数?
看看这个:
package java.lang;
public final class Integer extends Number implements Comparable<Integer> {
// ...
* Constructs a newly allocated {@code Integer} object that
* represents the specified {@code int} value.
* @param value the value to be represented by the
* {@code Integer} object.
* @deprecated
* It is rarely appropriate to use this constructor. The static factory
* {@link #valueOf(int)} is generally a better choice, as it is
* likely to yield significantly better space and time performance.
@Deprecated(since="9")
public Integer(int value) {
this.value = value;
// ...
}
再看看这个:
package java.lang;
public final class Double extends Number implements Comparable<Double> {
// ...
* Constructs a newly allocated {@code Double} object that
* represents the primitive {@code double} argument.
* @param value the value to be represented by the {@code Double}.
* @deprecated
* It is rarely appropriate to use this constructor. The static factory
* {@link #valueOf(double)} is generally a better choice, as it is
* likely to yield significantly better space and time performance.
@Deprecated(since="9")
public Double(double value) {
this.value = value;
// ...
}
封装类的构造函数全部都从Java9开始就过时了,你们竟然还在这里教别人用
new
?
那就来吧,来看看为什么说别用
new
:
package java.lang;
public final class Integer extends Number implements Comparable<Integer> {
// ...
* Cache to support the object identity semantics of autoboxing for values between
* -128 and 127 (inclusive) as required by JLS.
* The cache is initialized on first usage. The size of the cache
* may be controlled by the {@code -XX:AutoBoxCacheMax=<size>} option.
* During VM initialization, java.lang.Integer.IntegerCache.high property
* may be set and saved in the private system properties in the
* jdk.internal.misc.VM class.
private static class IntegerCache {
static final int low = -128;
static final int high;
static final Integer cache[];
static {
// high value may be configured by property
int h = 127;
String integerCacheHighPropValue =
VM.getSavedProperty("java.lang.Integer.IntegerCache.high");
if (integerCacheHighPropValue != null) {
try {
int i = parseInt(integerCacheHighPropValue);
i = Math.max(i, 127);
// Maximum array size is Integer.MAX_VALUE
h = Math.min(i, Integer.MAX_VALUE - (-low) -1);
} catch( NumberFormatException nfe) {
// If the property cannot be parsed into an int, ignore it.
high = h
cache = new Integer[(high - low) + 1];
int j = low;
for(int k = 0; k < cache.length; k++)
cache[k] = new Integer(j++);
// range [-128, 127] must be interned (JLS7 5.1.7)
assert IntegerCache.high >= 127;
private IntegerCache() {}
* Returns an {@code Integer} instance representing the specified
* {@code int} value. If a new {@code Integer} instance is not
* required, this method should generally be used in preference to
* the constructor {@link #Integer(int)}, as this method is likely
* to yield significantly better space and time performance by
* caching frequently requested values.
* This method will always cache values in the range -128 to 127,
* inclusive, and may cache other values outside of this range.
* @param i an {@code int} value.
* @return an {@code Integer} instance representing {@code i}.
* @since 1.5
@HotSpotIntrinsicCandidate
public static Integer valueOf(int i) {