Java基础之神奇的包装类(一)

1. 导读

JAVA中针对八种基本数据类型提供了相对应的包装类, 今天主要基于几个问题来分享下个人对于包装类的理解, 本期先分享下面两个问题:
.1 什么是包装类? 有了基本类型, 为什么还需要有包装类;
.2 包装类干了什么?

2. 什么包装类

众所周知, JAVA提供了八种基本类型, 同时也对这八种基本类型做了相应的封装, 形成了八种包装类:

基本类型 封装类型
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Char
boolean Boolean

其实void在JAVA也是一种数据类型, 也有对应的包装类Void, 只是我们无法对其进行操作, 也就没有放在上面的表格中了;

3. 为什么需要包装类

JAVA是面相对象的编程语言; 那么要理解面相对象, 首先需要知道这个对象是什么? 我的理解是:
.1 对象具有自己的属性以及行为;
.2 对象可以通过自己的行为或者动作向外界传递信息;
那么面相对象就是通过对象之间的信息交互来实现整个程序的功能; 而封装, 继承 和 多态是语言层面的强制约束;
有了面相对象编程的概念, 我们再来看为什么JAVA需要包装类;
.1 包装类在基本类型的基础上做了封装, 使其有了自身的行为; 那么有了行为有什么好处呢? 我们举个例子来说明:

    public static void main(String[] args) {
        int simpleData = 1;
        Integer wrapperData = 1;
        LOGGER.info(String.format("基本类型的比较结果:%s", simpleData == wrapperData));
        LOGGER.info(String.format("包装类型的比较结果:%s", wrapperData.equals(simpleData)));
        LOGGER.info(String.format("基本类型转String:%s", String.valueOf(simpleData)));
        LOGGER.info(String.format("包装类型转String:%s", wrapperData.toString()));
    }

通过int和Integer举例, 展示了基本类型和包装类型的判断和转String的区别:为什么达到同一个目的, 基本类型需要借助其他手段来实现; 而包装类却可以通过自身的动作达到, 这就是基本类型和包装类型的不同, 这也是面相过程与面相对象的区别: 面相过程需要自己实现需求, 面相对象则是调用目标对象对应的方法即可;

.2 初始化的不同: 未赋值时, 基本数据类型默认是0, 而封装类型默认是null; 当需要区分赋值与未赋值时, 封装类型就显得十分友好了; 比如在构建更新实体时, 有个字段是0, 就需要判断他的原始值是0还是需要更新成0; 而null则没有这种烦恼了;

.3 前面说过JAVA是面相对象的语言, 其很多设计都是针对对象来的, 比如HashMap的设计, 在插入时, 需要先调用插入key的Object::equals, 但是基本数据类型是没有行为的, 意味着基本数据类型无法作为HashMap的key; 如果没有封装类, 我们就无法实现用数值类型作为key了;

故而为何需要封装类?
.1 JAVA是面相对象的语言, 其语言设计初衷就需要"万物皆对象", 故需要对基本数据类型再次封装;
.2 JAVA内部很多实现需要调用对象相对应的动作, 而基本数据类型不是对象, 为了使用这些实现, 需要封装对象;

4. 包装类干了什么

这8个包装类大同小异, 我们以比较特殊的Integer来举例;

    public final class Integer extends Number implements Comparable<Integer> {
    /**
     * A constant holding the minimum value an {@code int} can
     * have, -2<sup>31</sup>.
     */
    @Native public static final int   MIN_VALUE = 0x80000000;

    /**
     * A constant holding the maximum value an {@code int} can
     * have, 2<sup>31</sup>-1.
     */
    @Native public static final int   MAX_VALUE = 0x7fffffff;
    ...
     /**
     * The value of the {@code Integer}.
     *
     * @serial
     */
    private final int value;

从上面的代码可看出, Integer的一些设计:
.1 Integer类是final的, 其底层存值的value也是final的; 这个设计和String是一样的, Integer也就是不可变的;
.2 Integer也设置了int相同的最大最小值, 因为Integer是基于int做的封装, 故而仍然存在溢出问题(当赋的值大于Integer.MAX_VALUE时, 发生溢出);

再来关注下Integer::equals, Integer重写了Object的equals方法:

    public boolean equals(Object obj) {
        if (obj instanceof Integer) {
            return value == ((Integer)obj).intValue();
        }
        return false;
    }

.1 如果传入对象是Integer类型的, 比较两者的value是相等;
.2 如果是非Integer类型的, 直接返回false;
.3 这里没有先比对两者的堆地址, 因为只有两者是同一个对象时才会直接返回true; 这个概率比较小(一般没人会自己比较自己吧), 所以直接省略了这一步;

继续关注Integer::hashCode的实现:

    public static int hashCode(int value) {
        return value;
    }

Integer::hashCode直接返回了当前的值(hashCode返回的是个int类型的值, 直接返回Integer的值好像也没啥不对);
按这个逻辑, Long::hashCode是不是直接强转成int返回的呢? 因为精度问题, Long::hashCode做了特殊处理:

    public static int hashCode(long value) {
        return (int)(value ^ (value >>> 32));
    }

Long::hashCode并不是如我们猜想的那样设计的:
.1 先把value右移32位, 因为long是64位的, 右移32位就把左边边的值都置为0了;
.2 再与原始值进行异或, 将得出的结果强转成int类型;
.3 至于为什么这么设计, 主要是以为int是32位的, 如果采用Integer::hashCode的方法, 那么当右边32位都是0时, 不管左边的32位是何值, 在转为int时, 左边32位都被摸除, 得出的结果都是0; 这样的方式显然会有很大的碰撞;
.4 故而Long::hashCode采用了低位32异或高位32的方式来获取hashCode;Double::hashCode的实现也是采用的这种方式;

Integer是实现了Compareable接口的, 我们来看下Integer::compareTo:

     public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }

.1 使用了三目运算符; 第一层先判断是否小于, true则返回-1;
.2 第二层判断是否相等, true则返回0, 反之则返回1;
.3 如果两个Integer是相等的, 那么调用Integer::equals 和 Integer::compareTo的结果是一样的;

本期基于上面两个问题分享了个人对于封装类的理解, 如果上面有不当之处, 欢迎指正; 如果看了觉的有益处, 烦请点赞转发吧, 感谢;

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容