int 基本数据类型 0 指向常量池
Integer 封装对象 null 指向堆
Integer --> int 的时候可能出现nullException
Integer有哪些方法?静态,非静态 拆装箱调用什么方法?自动拆装箱发生在什么时间?
Integer value = Integer.valueOf(22); //装箱
int i1 = Integer.parseInt("22");
int i = value.intValue(); //拆箱
装箱场景:Integer i = 1 // 反编译等价于 Integer i = Integer.valueOf(1);
拆箱: int j = i + 1// 反编译等价于 int j = i.intValue() + 1;
所以拆装箱发生于编译时期
valueOf源码
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
return IntegerCache.cache[i + (-IntegerCache.low)];
return new Integer(i);
}
IntegerCache 是私有静态内部类,缓存-128-127的对象,需要的时候调用,代码如下:
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
// like:-XX:AutoBoxCacheMax=N
int h = 127;
String integerCacheHighPropValue =
sun.misc.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() {}
}
明显知道更大的数会被频繁使用,可以借用下面配置:
-XX:AutoBoxCacheMax=N
为什么需要原始类型int ?
在Java语言中,new一个对象存储在堆里,我们通过栈中的引用来使用这些对象;但是对于经常用到的一系列类型如int,如果我们用new将其存储在堆里就不是很有效——特别是简单的小的变量。所以就出现了基本类型,同C++一样,Java采用了相似的做法,对于这些类型不是用new关键字来创建,而是直接将变量的值存储在栈中,因此更加高效。
对象在内存中的存储
对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。
对象头包括两部分信息,第一部分用于存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等,这部分数据的长度在32位和64位的虚拟机(未开启压缩指针)中分别为32bit和64bit,官方称它为"Mark Word"。
对象头的另外一部分是类型指针,即对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例。并不是所有的虚拟机实现都必须在对象数据上保留类型指针,换句话说,查找对象的元数据信息并不一定要经过对象本身。另外,如果对象是一个Java数组,那在对象头中还必须有一块用于记录数组长度的数据,因为虚拟机可以通过普通Java对象的元数据信息确定Java对象的大小,但是从数组的元数据中却无法确定数组的大小。
接下来的实例数据部分是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。无论是从父类继承下来的,还是在子类中定义的,都需要记录起来。
第三部分对齐填充并不是必然存在的,也没有特别的含义,它仅仅起着占位符的作用。由于HotSpot VM的自动内存管理系统要求对象起始地址必须是8字节的整数倍,换句话说,就是对象的大小必须是8字节的整数倍。
原始类型和包装对象是否线程安全?
都不安全,如果需要线程安全,推荐使用AtomicInteger,原理见:
https://blog.youkuaiyun.com/h2604396739/article/details/86720618
基本数据类型和包装类,推荐用那个?
基本数据类型和包装类的开销还是有差距的,对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)和对齐填充(Padding)。
不管是内存还是处理速度,其实基本数据类型都是更优的选择。
int的最大值是多少
2进制到16进制
f=1111 f=15
4字节,32位,有符号 最大值为7fffffff
65535 2的16进制的最大数