一、八种基本数据类型
基本类型 | 大小(字节) | 默认值 | 封装类 |
---|---|---|---|
boolean | - | false | Boolean |
byte | 1 | (byte)0 | Byte |
short | 2 | (short)0 | Short |
char | 2 | ‘\u0000(null)’ | Character |
int | 4 | 0 | Integer |
float | 4 | 0.0f | Float |
double | 8 | 0.0d | Double |
long | 8 | 0L | Long |
1、除以上8种基本数据类型外的数据类型均为引用数据类型(数组,接口,类,枚举…)
2、虽然定义了boolean这种数据类型,但在Java虚拟机中没有任何供boolean值专用的字 节码指令,在编译之后都使用Java虚拟机中的int数据类型来代替
3、基本类型之间转换(boolean类型与所有其他7种类型都不能进行转换)
- 高转低(强制转换,有可能丢失精度)
- 低转高(自动转换,不丢失精度)
从低到高排序:byte <(short=char)< int < long < float < double
二、基本数据类型和包装类
1、包装类
基本数据类型 | 包装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
boolean | Boolean |
char | Character |
- 针对Java的8种基本数据类型定义相应的引用数据类型即包装类
- Java的基本数据类型自动装箱成为引用数据类型,便有了类的特性就可以调用封装好的方法(如求最大值,成绩判断为缺考还是0分等),涉及到对象的操作也更加方便。
2、自动装箱和自动拆箱
- 自动装箱:把基本数据类型转成相应包装类对象
Integer i = new Integer(5); //构造器
Double d = new Double("10.00"); //字符串参数构造器
- 自动拆箱:把包装类对象转成相应基本数据类型
//调用包装类相应的xxxValue(),xxx为基本数据类型
Double d = new Double("1.23");
double value = d.doubleValue();
3、基本数据类型,包装类和String类的转换
三、Integer的缓冲机制
1、分析一下代码的结果
查看Integer源码看到有一个静态方法valueOf()使用的缓冲技术把一定范围内的对象提前初始化了。
public static Integer valueOf(int i) {
if (i >= IntegerCache.low && i <= IntegerCache.high)
//i在[-128,127]
return IntegerCache.cache[i + (-IntegerCache.low)];
//其它范围
return new Integer(i);
}
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 =
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() {}
}
分析:valueOf()方法体把一定范围的整数都使用了同一个缓存类获取对象,从IntegerCache类中看到当high没有初始化的话会使用higt=h(127)给high初始化,则这时候把[-128,127]范围内的Integer对象都提前实例化了。因此在这个范围内Integer创建的对象只要数值相同都是同一个对象,在范围外的对象都是新创建的对象。
此外查看Short源码发现也含有静态方法valueOf使其也具备缓冲机制。但是并没有提供调整机制,固定把范围定在[-128,127]。
* @param s a short value.
* @return a {@code Short} instance representing {@code s}.
* @since 1.5
*/
public static Short valueOf(short s) {
final int offset = 128;
int sAsInt = s;
if (sAsInt >= -128 && sAsInt <= 127) { // must cache
return ShortCache.cache[sAsInt + offset];
}
return new Short(s);
}
2、调整Integer的缓冲范围
上面说到Integer的缓存类的上限是可以设置的,尝试设置到[-128,255]。使得上面c == d的输出结果为true。
1)设置运行参数-Djava.lang.Integer.IntegerCache.high=255
2)通过反射获取high的值可看到上限已增加到255
3)给test3方法添加参数后再次运行
四、基本数据类型和引用数据类型传值
方法形参是基本数据类型(不改变值),方法形参是引用数据类型且方法体改变的是对象的数据内容(改变值)。注意:如果方法体改变的是引用类型的指向则不会改变值。
@Test
public void test1() {
int value = 10;
System.out.println("调用方法前value = " + value);
pass(value);
System.out.println("调用方法后value = " + value);
}
/*
输出结果:
调用方法前value = 10
调用方法后value = 10
*/
@Test
public void test2() {
Person p = new Person("pdd", 3);
System.out.println("调用方法前age = " + p.getAge());
pass(p);
System.out.println("调用方法后age = " + p.getAge());
}
/*
输出结果:
调用方法前age = 3
调用方法后age = 18
*/
public void pass(int value) {
value = 0;
}
public void pass(Person p) {
p.setAge(18);
}
@AllArgsConstructor
@Data
class Person {
private String name;
private int age;
}