# 前言
今天在写算法题的时候,发现了一个 javaSE 的问题,就是关于基本数据类型和其封装类之间的关系,在转换之间出现了一些困惑。
以下为其截图。
(第一层括弧实际是定义了一个匿名内部类 (Anonymous Inner Class),第二层括弧实际上是一个实例初始化块 (instance initializer block),这个块在内部匿名类构造时被执行)
在上面可以看到,我们的 new char 并不能够被自动转化为 new Character,而前面的 char 字段则可以,这让我有些疑惑,于是我便又回顾了 javaSE 部分终于的到解答。
# 基本数据类型
那么我们先来看看 java 的基本数据类型,我们能快速的想到 int double 这些我们以前在其他语言就认识的老朋友。怎么说呢,java 作为一个面向对象的编程语言,这种基本数据类型并不具备对象的性质,没有方法和一些属性。根据网上说法,这是为了顺应大众的习惯,并且有些简单问题的确可以快速的解决。
这里就先介绍一下这些基本数据类型吧
# 1.byte
占的位数:byte 数据类型占八位;
最小值为:-128(-2^7);
最大值为:127(2^7-1);
默认值为:0;
# 2.short
占的位数:short 数据类型占 16 位;
最小值为:-32768(-2^15);
最大值为:32767(2^15 - 1);
默认值为:0;
# 3.int
占的位数:int 数据类型占 32 位;
最小值为:-2,147,483,648(-2^31);
最大值为:2,147,483,647(2^31 - 1);
默认值为:0;
一般整型变量默认为 int 型;
# 4.long
占的位数:long 数据类型占 64 位;
最小值为:-9,223,372,036,854,775,808(-2^63);
最大值为:9,223,372,036,854,775,807(2^63 -1);
默认值为:0L;
# 5.float
占的位数:单精度,占 32 位;
最小值为:1.4E - 45;
最大值为:3.4028235E38;
默认值为:0.0f;
# 6.double
占的位数:双精度,占 64 位;
最小值为:4.9E-324;
最大值为:1.7976931348623157E308;
默认值为:0.0d;
# 7. char
占的位数:char 类型是一个单一的 16 位 Unicode 字符;
最小值: \u0000(即为 0);
最大值: \uffff(即为 65,535);
char 数据类型可以存储任何字符;
# 8.boolean
两个取值:false 和 true;
默认值:false;
占的位数:好像很复杂,这个东西。
# 封装类
基本数据类型 | 封装类 |
---|---|
byte | Byte |
short | Short |
int | Integer |
long | Long |
float | Float |
double | Double |
char | Character |
boolean | Boolean |
虽然在有些地方,我们看起来并没有用到封装类,但是基本上我们都一直在用,就比如最常用的各种数据结构中的泛型中,我们需要放入各种对象类。但是在实际运用中,我们在装入数据时可以通过装入其基本数据类型实现。
上图中的字符 c 正是完成了这个过程,所以这中间发生了什么呢。
# 拆箱和装箱
如果按照规范,要创建一个 Integer 对象,我们按照创建类的格式。
Integer integer = new Integer(10); |
但是现在 java 提供了自动装箱的功能:
Integer integer =10; |
同理,也存在着自动拆箱:
int i =integer; //i=10 |
所以,可以看出在现在 java 使用中,我们可以自动的将基本类型转换为其包装类,也可以把包装类在转化为基本类型。
然后其实其实现过程是分别调用了
Integer.valueOf(10); // 装箱 |
integer.intValue(); // 拆箱 |
其中两者都不难理解,但是 valueOf () 方法的实现比较有意思。
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() {} | |
} | |
// 可以看出 Integer 包装类也是有缓冲池的。 | |
public static Integer valueOf(int i) { | |
if (i >= IntegerCache.low && i <= IntegerCache.high) | |
return IntegerCache.cache[i + (-IntegerCache.low)]; | |
return new Integer(i); | |
} |
# 问题解答
最终说了这么多,今天遇到的问题始终还是没有很好解答,为什么我的 Character 没有自动转换呢?其实如果我们仔细看看就可以知道。
HashMap<>() 的 <> 需要存放对象的原因是,需要我们提供 hashcode () 和 equals () 方法,如果我们想存放我们自定义的类,我们也需要自己重写 hashcode () 和 equals () 方法,这就是为什么不支持基本数据类型的原因 (需要装箱)。
然后再来看看 java 中的数组,数组这个东西在 java 中是似乎可以看成对象的。
首先
1. 数组本身也具有 hashcode () 和 equals () 方法
2. 数组是可以向上转换为 Object 类型。
3. 同时也符合引用这一概念。
所以现在似乎可以得出答案了:
这里首先识别到的不会是我的 char 数组中的 char,而是整个数组。由于数组可以被 HashMap 所识别为对象,不会搞什么自动装箱 (数组也没有装箱这一说), 所以最后只能提示参数类型错误。