# 前言

​ 今天在写算法题的时候,发现了一个 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;

占的位数:好像很复杂,这个东西。

# 封装类

基本数据类型封装类
byteByte
shortShort
intInteger
longLong
floatFloat
doubleDouble
charCharacter
booleanBoolean

虽然在有些地方,我们看起来并没有用到封装类,但是基本上我们都一直在用,就比如最常用的各种数据结构中的泛型中,我们需要放入各种对象类。但是在实际运用中,我们在装入数据时可以通过装入其基本数据类型实现。

上图中的字符 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 所识别为对象,不会搞什么自动装箱 (数组也没有装箱这一说), 所以最后只能提示参数类型错误。