精华内容
下载资源
问答
  • 性质上根本不同点:int是基本数据类型、Integer是引用数据类型,它有自己的属性,方法 3.存储位置方式不同:int是存储在栈中,而Integer是存储在堆中,通过栈中的引用来调用对象 4.初始值不同int 默认是0,Integer...


    1.声明方式不同,int不需要new 、Integer需要new
    2.性质上根本不同点:int是基本数据类型、Integer是引用数据类型,它有自己的属性,方法
    3.存储位置和方式不同:int是存储在栈中,而Integer是存储在堆中,通过栈中的引用来调用对象
    4.初始值不同int 默认是0,Integer默认是null

    转载于:https://www.cnblogs.com/pecool/p/7965696.html

    展开全文
  • Java中包装类和基本数据类型区别

    前言

    在写项目的时候发现一个问题,

    public boolean connect(){
    }
    

    还有一种写法

    public Boolean connect(){
    }
    

    两种写法在运行中都无报错,那有何区别呢?

    引发思考:这里两种写法有什么区别?

    boolean 是 Java 的基本数据类型,Boolean 是 Java 的一个类。boolean 类型会在“赋零值”阶段给属性赋 false。而 Boolean 是一个类,会在“赋零值”阶段给对象赋 null。

    如果是静态属性,会在类加载时被赋值。如果是普通类属性,会在实例化对象时赋值。这两点可以了解一下“类加载机制”和“对象创建过程”。

    类加载机制:

    • 加载:根据类的全名获取类的二进制字节流,将类加载进内存并在堆中生成一个代表这个类的Class 对象,作为方法区数据的访问入口

    • 验证:验证class文件中的字节流是否符合JVM规范

    • 准备:在方法区中为类的静态属性分配内存,并初始化默认值(boolean 的默认值是falseBoolean 的默认值是null

    • 解析:将常量池中的符号引用转化为直接引用,可以理解为对象引用转成指针

    • 初始化:真正开始执行类中的代码,静态属性赋值和静态块

    对象实例化过程:

    • 检查类是否已经被加载(双亲委派)

    • 给对象分配内存空间(指针碰撞)

    • 零值初始化(false / null

    • 设置对象头(对象分代年龄等信息)

    • 执行 <init>方法(属性初始化,语句块和构造方法)

    所以说,Boolean只是被加载了,还没有被实例化,在被实例化之前并没有分配内存,所以是 null

    查看源码,看看 Boolean 的属性和构造方法,了解一下它如何包装 boolean
    在这里插入图片描述

    关于 Boolean 使用过程中有一个风险点,阿里巴巴Java开发手册中写的非常好
    在这里插入图片描述
    简单来说就是,boolean定义的属性一定要有值,如果 Boolean对象值为null,解包过程中就会出现NPE。

    NPE: NullPointerException,即空指针异常

    public class Main {
        public static void main(String[] args) {
            Integer n = null;
            int i = n;
        }
    }
    

    运行报错
    在这里插入图片描述

    想象一种场景:你女票问你:你爱我吗?但你没听清。如果你是Boolean 就会回答,我没听清(null),如果你是 boolean就会回答,*** (NPE)

    之后就会有个狗头被打爆。

    在这里插入图片描述

    参考:https://blog.csdn.net/mkii_hong/article/details/106109387

    包装类和基本类型

    什么是包装类?

    所谓包装类,就是将基本数据类型,用一个类进行了一层包装,可以按照引用类型进行使用。同时还提供了若干用来进行数据转换的操作。

    想要对基本类型数据进行更多的操作,最方便的方式就是将其封装成对象。为啥呢?因为在对象描述中就可以定义更多的属性和行为对该基本数据类型进行操作。
    基本数据类型的包装类是为了解决基本数据类型有些操作不方便带来的问题。

    Java在设计之初有一个基本原则:一切皆对象,一切的操作都要求用对象的形式进行描述。但是这里面就会出现一个矛盾,基本数据类型不是对象。那么为了符合于这种要求,所以最早的时候可以采用人为的方式来解决此问题。

    class MyInt {  // 一个类
        private int num;  // 这个类包装的基本数据类型
        // 构造的目的是为了将基本数据类型传递给对象
        public MyInt(int num) {  // 将基本类型包装类
            this.num = num;
        }
        public int intValue() {  // 将包装的数据内容返回
            return this.num;
        }
    }
    
    public class TestDemo {
        public static void main(String args[]) {
            MyInt mi = new MyInt(10);  // 将int包装为类
            int temp = mi.intValue();  // 将对象中包装的内容取出
            // 只有取出包装数据之后才可以进行计算
            System.out.println(temp * 2);  // 结果为20
        }
    }
    

    因为这样的实现是比较容易的,所以专门提供了一组包装类,来包装所有的基本类型,包装类由此而生。
    在这里插入图片描述
    包装的过程就称为装箱

    装箱和拆箱

    因为基本类型和包装类可以互相转换:

    int i = 100;
    Integer n = Integer.valueOf(i);
    int x = n.intValue();
    

    所以,Java编译器可以帮助我们自动在int和Integer之间转型:

    Integer n = 100; // 编译器自动使用Integer.valueOf(int)
    int x = n; // 编译器自动使用Integer.intValue()
    

    这种直接把int变为Integer的赋值写法,称为自动装箱(Auto Boxing),反过来,把Integer变为int的赋值写法,称为自动拆箱(Auto Unboxing)

    注意:自动装箱和自动拆箱只发生在编译阶段,目的是为了少写代码。

    包装类有以下用途

    1. 集合不允许存放基本数据类型,故常用包装类
    2. 包含了每种基本类型的相关属性,如最大值,最小值,所占位数等
    3. 作为基本数据类型对应的类类型,提供了一系列实用的对象操作,如类型转换,进制转换等

    基本类型与包装类型的区别

    1. 在Java中,一切皆对象,但八大基本类型却不是对象。

    2. 声明方式的不同,基本类型无需通过new关键字来创建,而包装类型需new关键字。

    3. 存储方式及位置的不同,基本类型是直接存储变量的值保存在堆栈中能高效的存取,包装类型需要通过引用指向实例,具体的实例保存在中。

    4. 初始值的不同,封装类型的初始值为null,基本类型的的初始值视具体的类型而定,比如int类型的初始值为0,boolean类型为false;

    5. 使用方式的不同,比如与集合类合作使用时只能使用包装类型。

    6. 什么时候该用包装类,什么时候用基本类型,看基本的业务来定:这个字段允允许null值,就需要使用包装类型,如果不允许null值,,使用基本类型就可以了,用到比如泛型和反射调用函数,就需要用包装类!

    所以最基本的一点区别是:Ingeter是int的包装类,int的初值为0,Ingeter的初值为null。除此之外还有区别,请看代码:

    public class TestInteger {
        public static void main(String[] args) {
            int i = 128;
            Integer i2 = 128;
            Integer i3 = new Integer(128);
            System.out.println(i == i2); //Integer会自动拆箱为int,所以为true
            System.out.println(i == i3); //true,理由同上
            Integer i4 = 127;//编译时被翻译成:Integer i4 = Integer.valueOf(127);
            Integer i5 = 127;
            System.out.println(i4 == i5);//true
            Integer i6 = 128;
            Integer i7 = 128;
            System.out.println(i6 == i7);//false
            Integer i8 = new Integer(127);
            System.out.println(i5 == i8); //false
            Integer i9 = new Integer(128);
            Integer i10 = new Integer(123);
            System.out.println(i9 == i10);  //false
        }
    }
    

    为什么i4和i5比是true,而i6和i7比是false呢?

    关键就是看valueOf()函数了,这个函数对于-128到127之间的数,会进行缓存, Integer i4 = 127时,会将127进行缓存,下次再写Integer i5 = 127时,就会直接从缓存中取,就不会new了。所以i4和i5比是true,而i6和i7比是false。

    而对于后边的i5和i8,以及i9和i10,因为对象不一样,所以为false。

    以上的情况总结如下

    1. 无论如何,Integernew Integer不会相等。不会经历拆箱过程,new出来的对象存放在堆,而非new的Integer常量则在常量池(在方法区),他们的内存地址不一样,所以为false。
    2. 两个都是非new出来的Integer,如果数在-128到127之间,则是true,否则为false。因为java在编译Integer i2 = 128的时候,被翻译成:Integer i2 = Integer.valueOf(128);而valueOf()函数会对-128到127之间的数进行缓存。
    3. 两个都是new出来的,都为false。还是内存地址不一样。
    4. int和Integer(无论new否)比,都为true,因为会把Integer自动拆箱为int再去比。
    展开全文
  • 前情提要上一篇中,通过一道常见的面试题(即:String、StringBuilder、StringBuffer的区别),引申到Java中基本类型和包装类的相关内容。在这一篇中,我们将解决上一篇中引申出来的问题——基本类型和包装类型到底有...

    前情提要

    上一篇中,通过一道常见的面试题(即:String、StringBuilder、StringBuffer的区别),引申到Java中基本类型和包装类的相关内容。在这一篇中,我们将解决上一篇中引申出来的问题——基本类型和包装类型到底有什么区别?

    首先,要弄明白这两者的区别,我们就必须要知道基本数据类型和包装类到底是啥?各自都有些什么特性?

    请注意,除非特别注明,否则本文篇中所涉及得到内容都是基于jdk1.8来说的。

    先来了解一下基本数据类型吧。

    关于基本数据类型

    基本数据类型到底是个啥?

    关于基本数据类型的定义,我翻了一些资料,至今没有在任何地方找到一个准确的描述。

    这里我就谈一下我个人的见解吧,如果有朋友觉得下面的内容有不妥的地方欢迎在评论区留下您的高见,大家共同进步!

    在一个变量定义后,该变量指向的只能是具体的数值而非内存地址。这样的变量就属于基本数据类型。

    这一块的内容后续会再来补充,由于不是主线,暂时搁置影响也不大。

    Java中基本数据类型有哪些

    在Java中,基本数据类型有8种,分别为:

    布尔类型:boolean

    字符类型:char

    整数类型:byte、short、int、long

    浮点类型:float、double

    各类型的详细信息如下表:

    类型描述

    名称

    位数

    字节数

    默认值

    布尔类型

    boolean

    -

    -

    false

    字符类型

    char

    16

    2

    'u0000'

    整数类型

    byte

    8

    1

    0

    整数类型

    short

    16

    2

    0

    整数类型

    int

    32

    4

    0

    整数类型

    long

    64

    8

    0L

    浮点类型

    float

    32

    4

    0f

    浮点类型

    double

    64

    8

    0d

    对于boolean而言,依赖于jvm厂商的具体实现。逻辑上理解是占用1位,但是实际中会考虑的因素较多。在此也不展开描述,如果有人问你究竟boolean占多少内存空间,你只需要回答:理论上1位(注意不是一个字节)就可满足需求,实际还要看jvm的实现。

    基本数据类型为什么不用new运算符?

    我们都知道new运算符可用于实例化一个对象,也就是给对象实例分配一块足够大的内存空间并返回指向该内存的引用。注意,这里所指的对象实际上是引用类型。引用对象开辟的内存空间一般是在堆中。

    相对于引用类型来说,值类型一般存放在栈上(作为成员变量的时候才会放在堆中)。因为虚拟机(根据虚拟机不同,boolean可能占用空间大小不同)对每一种基本类型的空间占用大小都是明确知晓的,所以不再需要new去开辟空间。

    实际中,Java的数据类型分为两种:值类型和引用类型,我们习惯于把所有引用类型都统称为对象。所以,基本数据类型不在我们理解的对象的定义范围内。

    关于包装类

    包装类的定义

    其实包装类的意义从名字就能看出一些端倪。啥叫包装,通俗了说就是把一个物体打包然后装起来。举个例子来说,比如今天我在网上买了一颗苹果,等我收到货的时候还是只有那一颗苹果吗?并不是,我拿到的是一个贴了有运单号的箱子,里面用了塑胶袋把苹果给包起来了。同理,包装类也是一样,每一个包装类里面都包了一种基本数据类型。作用也和这个例子类似,是为了让运输更方便,让苹果更安全,让我们操作更简单。

    包装类的种类

    八种基本类型都有自己对应的包装类,分别为:

    布尔类型:Boolean

    字符类型:Character

    整数类型:Byte、Short、Integer、Long

    浮点类型:Float、Double

    装箱和拆箱、包装类型的缓存机制

    下面我们以Integer为例,了解一下什么是装箱和拆箱,还有所谓的包装类的缓存机制到底是什么?首先,关于装箱和拆箱的概念如下:

    装箱——将基本类型用各自对应的包装(引用)类型包装起来:即基本类型->包装类型;

    拆箱——将包装类型转换为基本数据类型:即包装类型->基本类型;

    例如下面的代码将会发生装箱和拆箱的过程。

    public static void main(String[] args){

    // 装箱

    Integer packageObject = 100;

    // 拆箱

    int baseObject = packageObject;

    }

    编译上面的代码(javac命令),查看对应的.class文件的内容(javap命令)。

    public static void main(java.lang.String[]);

    descriptor: ([Ljava/lang/String;)V

    flags: ACC_PUBLIC, ACC_STATIC

    Code:

    stack=1, locals=3, args_size=1

    0: bipush 100

    2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

    5: astore_1

    6: aload_1

    7: invokevirtual #3 // Method java/lang/Integer.intValue:()I

    10: istore_2

    11: return

    LineNumberTable:

    line 9: 0

    line 11: 6

    line 12: 11

    可以看到装箱的时候用的是Integer的valueOf方法;而拆箱的时候用的是intValue方法。在Integer中找到这两个方法。

    valueOf方法的API说明如下:

    /**

    * Returns an {@code Integer} instance representing the specified

    * {@code int} value. If a new {@code Integer} instance is not

    * required, this method should generally be used in preference to

    * the constructor {@link #Integer(int)}, as this method is likely

    * to yield significantly better space and time performance by

    * caching frequently requested values.

    *

    * This method will always cache values in the range -128 to 127,

    * inclusive, and may cache other values outside of this range.

    *

    * @param i an {@code int} value.

    * @return an {@code Integer} instance representing {@code i}.

    * @since 1.5

    */

    因为篇幅原因,就不一步一步的点进去看了,有兴趣的朋友自行去翻源码吧。上面的内容已经足够说明问题了,上面的描述大概说了这些东西:

    该返回的是一个基于int(这个是入参,就是代码中定义的100)值的Integer的实例对象;

    首先会判断入参的范围在不在[-128,127]之间。

    如果不在这之间,则会调用构造方法返回一个新的Integer实例;

    如果在这个范围内,则会从缓存中取一个Integer对象返回;

    Integer所谓的缓存其实是在Integer类的内部定义了一个IntegerCache的class,IntegerCache里面持有一个静态并且final修饰的缓存数组,在一开始这个数组里面就已经存入了[-128,127]之间的整型值,当你用自动装箱的方式初始化一个Integer对象并且你的整型值在这个范围内的话,会自动从这个数组中找到对应的Integer对象返回给你,而不是重新创建一个Integer对象。

    下面再来看一下拆箱中遇到的intValue方法。

    intValue方法的API说明如下:

    /**

    * Returns the value of this {@code Integer} as an

    * {@code int}.

    */

    intValue方法的描述很简单,直接返回一个int类型的值。这个int值其实就是在Integer内部包装的基本数据类型(int)。

    到此,(Integer类的)装箱、拆箱以及缓存机制差不多咱们就已经揭开那层面纱了。事实上,八大包装类型中除了浮点类型的包装类(Double和Float)并没有实现缓存技术外,其他的包装类都实现了。

    Byte,Short,Integer,Long这四个包装类都提供了数值[-128,127]之间的相应类型的缓存;

    Character提供了数值在[0,127]之间的缓存;

    Boolean提供了取值在{True,False}之间的缓存;

    为什么浮点型不提供?因为浮点型的取值范围太广,不可能实现缓存。

    基本数据类型和包装数据类型常见的面试题

    (一)为什么List = new List();类似这样的代码会报错?

    答:因为基本数据类型不支持泛型。

    List支持泛型,但是泛型必须是对象。也就是说List支持所有继承自Object类的类型参数,但基本数据类型并没有继承自Object,所以基本数据类型并不是对象。

    (二)包装类缓存的常见题

    // 题目

    Integer i1 = 55;

    Integer i2 = 55;

    Integer i3 = new Integer(55);

    Integer i4 = new Integer(55);

    Integer i5 = new Integer(56);

    Integer i6 = 1;

    System.out.println("i1 = i2 ? " + (i1 == i2));

    System.out.println("i3 = i4 ? " + (i3 == i4));

    System.out.println("i5 = i4 + i6 ? " + (i5 == i4 + i6));

    System.out.println("56 = i4 + i6 ? " + (56 == i4 + i6));

    Double d1 = 1.0d;

    Double d2 = 1.0d;

    System.out.println("d1 = d2 ? " + (d1 == d2));

    // 答案

    i1 = i2 ? true

    i3 = i4 ? false

    i5 = i4 + i6 ? true

    56 = i4 + i6 ? true

    d1 = d2 ? false

    // 解析

    // 从缓存数组中取一个值为55的Integer实例

    Integer i1 = 55;

    // 从缓存数组中取一个值为55的Integer实例

    Integer i2 = 55;

    // 创建一个值为55的Integer实例

    Integer i3 = new Integer(55);

    // 创建一个值为55的Integer实例

    Integer i4 = new Integer(55);

    // 创建一个值为56的Integer实例

    Integer i5 = new Integer(56);

    // 从缓存数组中取一个值为1的Integer实例

    Integer i6 = 1;

    // 只要值相等,从缓存数组中取出来的一定是同一个实例

    System.out.println("i1 = i2 ? " + (i1 == i2));

    // 虽然值相同,但是属于两个不同的实例(因为遇到了两个new)

    System.out.println("i3 = i4 ? " + (i3 == i4));

    // Integer类不提供+的实现,所以i4和i6先拆箱为基本数据类型,因为i5要和基本类型比较,i5也只能拆箱

    System.out.println("i5 = i4 + i6 ? " + (i5 == i4 + i6));

    // 同上一个

    System.out.println("56 = i4 + i6 ? " + (56 == i4 + i6));

    Double d1 = 1.0d;

    Double d2 = 1.0d;

    // Double不提供缓存机制,每次都是new的新对象

    System.out.println("d1 = d2 ? " + (d1 == d2));

    (三)Integer类的缓存区间为什么是[-128,127],为什么不把范围定义的再广一些?

    事实上,针对于Integer类,我们可以通过改参数的方式来设置这个区间的上下限。那是不是意味着我的区间越大越好呢?

    并不是,看源码的时候就会知道,Integer类的缓存区间的每一个整型值都会被提前创建并加载到内存中去。换句话说,这个区间越大,你的内存就占用的越多。这是一个典型的时间和空间的抉择问题。缓存的意义就是拿空间换时间,但是你拿了太多的空间,可能换来的回报远远不是那点时间能补偿得了的。

    (四)在Java中存在i+1

    存在,所有的基本类型都有位数的限制,比如int是32位,那么int能表示的整型范围为[-2147483648,2147483647],即:[负2的31次幂,正2的31次幂-1]。当超过这个范围时,将发生溢出,溢出后该值将变为负数。

    int x = 2147483647;

    int y = x + 1;

    System.out.println(y);// 输出:-2147483648

    System.out.println("y < x ? " + (y < x));// 输出:y < x ? true

    关于为什么溢出后会变为负数,大家可自己演练一下。简单提一下,32位的有符号数,第一位是符号位(为0表示正数,为1表示负数)。所以32位能表示的最大的正数是[0111 1111 1111 1111 1111 1111 1111 1111],写成16进制就是0x7FFFFFFF。再加1,低位向高位进位,相加的结果变成[1000 0000 0000 0000 0000 0000 0000 0000],表示成16进制则为0x80000000。这个结果一看就是负数,因为最高位的符号位已经变成1了。至于为什么是-2147483648,就需要去算一下这个二进制串的补码了。

    扩展区域

    扩展区域主体

    这是一个没有实现的扩展。

    展开全文
  • 前情提要上一篇中,通过一道常见的面试题(即:String、StringBuilder、StringBuffer的区别),引申到Java中基本类型和包装类的相关内容。在这一篇中,我们将解决上一篇中引申出来的问题——基本类型和包装类型到底有...

    前情提要

    上一篇中,通过一道常见的面试题(即:String、StringBuilder、StringBuffer的区别),引申到Java中基本类型和包装类的相关内容。在这一篇中,我们将解决上一篇中引申出来的问题——基本类型和包装类型到底有什么区别?

    首先,要弄明白这两者的区别,我们就必须要知道基本数据类型和包装类到底是啥?各自都有些什么特性?

    请注意,除非特别注明,否则本文篇中所涉及得到内容都是基于jdk1.8来说的。

    先来了解一下基本数据类型吧。

    关于基本数据类型

    基本数据类型到底是个啥?

    关于基本数据类型的定义,我翻了一些资料,至今没有在任何地方找到一个准确的描述。

    这里我就谈一下我个人的见解吧,如果有朋友觉得下面的内容有不妥的地方欢迎在评论区留下您的高见,大家共同进步!

    在一个变量定义后,该变量指向的只能是具体的数值而非内存地址。这样的变量就属于基本数据类型。

    这一块的内容后续会再来补充,由于不是主线,暂时搁置影响也不大。

    Java中基本数据类型有哪些

    在Java中,基本数据类型有8种,分别为:

    布尔类型:boolean

    字符类型:char

    整数类型:byte、short、int、long

    浮点类型:float、double

    各类型的详细信息如下表:

    类型描述

    名称

    位数

    字节数

    默认值

    布尔类型

    boolean

    -

    -

    false

    字符类型

    char

    16

    2

    'u0000'

    整数类型

    byte

    8

    1

    0

    整数类型

    short

    16

    2

    0

    整数类型

    int

    32

    4

    0

    整数类型

    long

    64

    8

    0L

    浮点类型

    float

    32

    4

    0f

    浮点类型

    double

    64

    8

    0d

    对于boolean而言,依赖于jvm厂商的具体实现。逻辑上理解是占用1位,但是实际中会考虑的因素较多。在此也不展开描述,如果有人问你究竟boolean占多少内存空间,你只需要回答:理论上1位(注意不是一个字节)就可满足需求,实际还要看jvm的实现。

    基本数据类型为什么不用new运算符?

    我们都知道new运算符可用于实例化一个对象,也就是给对象实例分配一块足够大的内存空间并返回指向该内存的引用。注意,这里所指的对象实际上是引用类型。引用对象开辟的内存空间一般是在堆中。

    相对于引用类型来说,值类型一般存放在栈上(作为成员变量的时候才会放在堆中)。因为虚拟机(根据虚拟机不同,boolean可能占用空间大小不同)对每一种基本类型的空间占用大小都是明确知晓的,所以不再需要new去开辟空间。

    实际中,Java的数据类型分为两种:值类型和引用类型,我们习惯于把所有引用类型都统称为对象。所以,基本数据类型不在我们理解的对象的定义范围内。

    关于包装类

    包装类的定义

    其实包装类的意义从名字就能看出一些端倪。啥叫包装,通俗了说就是把一个物体打包然后装起来。举个例子来说,比如今天我在网上买了一颗苹果,等我收到货的时候还是只有那一颗苹果吗?并不是,我拿到的是一个贴了有运单号的箱子,里面用了塑胶袋把苹果给包起来了。同理,包装类也是一样,每一个包装类里面都包了一种基本数据类型。作用也和这个例子类似,是为了让运输更方便,让苹果更安全,让我们操作更简单。

    包装类的种类

    八种基本类型都有自己对应的包装类,分别为:

    布尔类型:Boolean

    字符类型:Character

    整数类型:Byte、Short、Integer、Long

    浮点类型:Float、Double

    装箱和拆箱、包装类型的缓存机制

    下面我们以Integer为例,了解一下什么是装箱和拆箱,还有所谓的包装类的缓存机制到底是什么?首先,关于装箱和拆箱的概念如下:

    装箱——将基本类型用各自对应的包装(引用)类型包装起来:即基本类型->包装类型;

    拆箱——将包装类型转换为基本数据类型:即包装类型->基本类型;

    例如下面的代码将会发生装箱和拆箱的过程。

    public static void main(String[] args){

    // 装箱

    Integer packageObject = 100;

    // 拆箱

    int baseObject = packageObject;

    }

    编译上面的代码(javac命令),查看对应的.class文件的内容(javap命令)。

    public static void main(java.lang.String[]);

    descriptor: ([Ljava/lang/String;)V

    flags: ACC_PUBLIC, ACC_STATIC

    Code:

    stack=1, locals=3, args_size=1

    0: bipush 100

    2: invokestatic #2 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;

    5: astore_1

    6: aload_1

    7: invokevirtual #3 // Method java/lang/Integer.intValue:()I

    10: istore_2

    11: return

    LineNumberTable:

    line 9: 0

    line 11: 6

    line 12: 11

    可以看到装箱的时候用的是Integer的valueOf方法;而拆箱的时候用的是intValue方法。在Integer中找到这两个方法。

    valueOf方法的API说明如下:

    /**

    * Returns an {@code Integer} instance representing the specified

    * {@code int} value. If a new {@code Integer} instance is not

    * required, this method should generally be used in preference to

    * the constructor {@link #Integer(int)}, as this method is likely

    * to yield significantly better space and time performance by

    * caching frequently requested values.

    *

    * This method will always cache values in the range -128 to 127,

    * inclusive, and may cache other values outside of this range.

    *

    * @param i an {@code int} value.

    * @return an {@code Integer} instance representing {@code i}.

    * @since 1.5

    */

    因为篇幅原因,就不一步一步的点进去看了,有兴趣的朋友自行去翻源码吧。上面的内容已经足够说明问题了,上面的描述大概说了这些东西:

    该返回的是一个基于int(这个是入参,就是代码中定义的100)值的Integer的实例对象;

    首先会判断入参的范围在不在[-128,127]之间。

    如果不在这之间,则会调用构造方法返回一个新的Integer实例;

    如果在这个范围内,则会从缓存中取一个Integer对象返回;

    Integer所谓的缓存其实是在Integer类的内部定义了一个IntegerCache的class,IntegerCache里面持有一个静态并且final修饰的缓存数组,在一开始这个数组里面就已经存入了[-128,127]之间的整型值,当你用自动装箱的方式初始化一个Integer对象并且你的整型值在这个范围内的话,会自动从这个数组中找到对应的Integer对象返回给你,而不是重新创建一个Integer对象。

    下面再来看一下拆箱中遇到的intValue方法。

    intValue方法的API说明如下:

    /**

    * Returns the value of this {@code Integer} as an

    * {@code int}.

    */

    intValue方法的描述很简单,直接返回一个int类型的值。这个int值其实就是在Integer内部包装的基本数据类型(int)。

    到此,(Integer类的)装箱、拆箱以及缓存机制差不多咱们就已经揭开那层面纱了。事实上,八大包装类型中除了浮点类型的包装类(Double和Float)并没有实现缓存技术外,其他的包装类都实现了。

    Byte,Short,Integer,Long这四个包装类都提供了数值[-128,127]之间的相应类型的缓存;

    Character提供了数值在[0,127]之间的缓存;

    Boolean提供了取值在{True,False}之间的缓存;

    为什么浮点型不提供?因为浮点型的取值范围太广,不可能实现缓存。

    基本数据类型和包装数据类型常见的面试题

    (一)为什么List = new List();类似这样的代码会报错?

    答:因为基本数据类型不支持泛型。

    List支持泛型,但是泛型必须是对象。也就是说List支持所有继承自Object类的类型参数,但基本数据类型并没有继承自Object,所以基本数据类型并不是对象。

    (二)包装类缓存的常见题

    // 题目

    Integer i1 = 55;

    Integer i2 = 55;

    Integer i3 = new Integer(55);

    Integer i4 = new Integer(55);

    Integer i5 = new Integer(56);

    Integer i6 = 1;

    System.out.println("i1 = i2 ? " + (i1 == i2));

    System.out.println("i3 = i4 ? " + (i3 == i4));

    System.out.println("i5 = i4 + i6 ? " + (i5 == i4 + i6));

    System.out.println("56 = i4 + i6 ? " + (56 == i4 + i6));

    Double d1 = 1.0d;

    Double d2 = 1.0d;

    System.out.println("d1 = d2 ? " + (d1 == d2));

    // 答案

    i1 = i2 ? true

    i3 = i4 ? false

    i5 = i4 + i6 ? true

    56 = i4 + i6 ? true

    d1 = d2 ? false

    // 解析

    // 从缓存数组中取一个值为55的Integer实例

    Integer i1 = 55;

    // 从缓存数组中取一个值为55的Integer实例

    Integer i2 = 55;

    // 创建一个值为55的Integer实例

    Integer i3 = new Integer(55);

    // 创建一个值为55的Integer实例

    Integer i4 = new Integer(55);

    // 创建一个值为56的Integer实例

    Integer i5 = new Integer(56);

    // 从缓存数组中取一个值为1的Integer实例

    Integer i6 = 1;

    // 只要值相等,从缓存数组中取出来的一定是同一个实例

    System.out.println("i1 = i2 ? " + (i1 == i2));

    // 虽然值相同,但是属于两个不同的实例(因为遇到了两个new)

    System.out.println("i3 = i4 ? " + (i3 == i4));

    // Integer类不提供+的实现,所以i4和i6先拆箱为基本数据类型,因为i5要和基本类型比较,i5也只能拆箱

    System.out.println("i5 = i4 + i6 ? " + (i5 == i4 + i6));

    // 同上一个

    System.out.println("56 = i4 + i6 ? " + (56 == i4 + i6));

    Double d1 = 1.0d;

    Double d2 = 1.0d;

    // Double不提供缓存机制,每次都是new的新对象

    System.out.println("d1 = d2 ? " + (d1 == d2));

    (三)Integer类的缓存区间为什么是[-128,127],为什么不把范围定义的再广一些?

    事实上,针对于Integer类,我们可以通过改参数的方式来设置这个区间的上下限。那是不是意味着我的区间越大越好呢?

    并不是,看源码的时候就会知道,Integer类的缓存区间的每一个整型值都会被提前创建并加载到内存中去。换句话说,这个区间越大,你的内存就占用的越多。这是一个典型的时间和空间的抉择问题。缓存的意义就是拿空间换时间,但是你拿了太多的空间,可能换来的回报远远不是那点时间能补偿得了的。

    (四)在Java中存在i+1

    存在,所有的基本类型都有位数的限制,比如int是32位,那么int能表示的整型范围为[-2147483648,2147483647],即:[负2的31次幂,正2的31次幂-1]。当超过这个范围时,将发生溢出,溢出后该值将变为负数。

    int x = 2147483647;

    int y = x + 1;

    System.out.println(y);// 输出:-2147483648

    System.out.println("y < x ? " + (y < x));// 输出:y < x ? true

    关于为什么溢出后会变为负数,大家可自己演练一下。简单提一下,32位的有符号数,第一位是符号位(为0表示正数,为1表示负数)。所以32位能表示的最大的正数是[0111 1111 1111 1111 1111 1111 1111 1111],写成16进制就是0x7FFFFFFF。再加1,低位向高位进位,相加的结果变成[1000 0000 0000 0000 0000 0000 0000 0000],表示成16进制则为0x80000000。这个结果一看就是负数,因为最高位的符号位已经变成1了。至于为什么是-2147483648,就需要去算一下这个二进制串的补码了。

    扩展区域

    扩展区域主体

    这是一个没有实现的扩展。

    展开全文
  • 什么时候该用包装类,什么时候用基本类型,看基本的业务来定:这个字段允不允许null值,如果允许null值,则必然要用封装类,否则使用基本数据类型就可以了。用到比如泛型反射调用函数.,就必须用包装类。 ...
  • 包装类和基本数据类型之间有什么区别? 1、声明方式不同,基本类型不适用new关键字,而包装类型需要使用new关键字来在堆中分配存储空间; 2、存储方式及位置不同,基本类型是直接将变量值存储在堆栈中,而包装类型是...
  • 首先看一下几个测试题,验证一下java中对基本类型和包装类型的理解,看看最后输出的答案对不对,答案在这篇博客中哦://第一题: 基本类型和包装类型int a = 100;Integer b= 100;System.out.println(a==b);//第二题: ...
  • 基本类型和包装类区别

    万次阅读 2018-03-24 16:02:52
    区别: 1.基本类型存储在栈里,包装类型存储在堆里。因为栈的效率更高,所以保留了基本类型。 2.包装类是对象,拥有方法字段,对象的调用是引用对象的地址。... 基本类型包装类 以及其默认值,包装...
  • 包装类和基本类型

    2020-10-13 12:57:27
    什么是包装类 所谓包装类,就是能够直接将简单类型的变量表示为一个...基本类型与包装类型的区别 1、在Java中,一切皆对象,但八大基本类型却不是对象。 2、声明方式的不同,基本类型无需通过new关键字来创建,而封装类
  • Java的类型分为两部分,一个是基本类型(primitive),如int、double等八种基本数据类型;...基本类型包装类型的主要区别在于以下三个方面:1、基本类型只有值,而包装类型则具有与它们的值不同的同一性(iden...
  • 基本类型只有值,而包装类型则具有与它们的值不同的...泛型不支持基本类型,作为集合中的元素、键值直接使用包装类(否则会发生基本类型的自动装箱消耗性能)。如:只能写 ArrayList<Integer>,不能写 List...
  • int 是基本类型,直接存数值Integer是,产生对象时用一个引用指向这个对象Java把内存划分成两种:一种是栈内存,另一种是堆内存在函数中定义的一些基本类型的变量对象的引用变量都是在函数的栈内存中分配而实际...
  • 1.基本数据类型和包装类区别 这部分主要是加强对包装类的整体感官
  • 包装类和基本类的区别 1.包装类型可以为 null,而基本类型不可以 它使得包装类型可以应用于 POJO 中,而基本类型则不行 POJO:简单无规则的 Java 对象,只有属性字段以及 setter 和 getter 方法,示例如下。 class ...
  • 1、int是基本数据类型,Integer是包装类, 2、int则是直接存储数据值 ,Integer是对象的引用,(它有自己的内置方法) 3、Integer的默认值是null,int的默认值是0。 4、Integer 有缓存Integer[] cache [-128~127]...
  • 首先看一下几个测试题,验证一下java中对基本类型和包装类型的理解,看看最后输出的答案对不对,答案在这篇博客中哦://第一题: 基本类型和包装类型int a = 100;Integer b= 100;System.out.println(a==b);//第二题: ...
  • 1.包装类可以为null,基本类型不可以 根据《阿里巴巴Java开发手册》,数据库查询结果可以为null,如果是基本类型在自动拆箱时会抛出 NullPointerException 异常 2.包装类型可以用于泛型,基本类型不可以 泛型要求能...
  • 在实际的开发中,包装类一定会是我们要用到的,用的最多的是在简单Java类中,而且使用包装类的最大的一个好处就是其默认值是null,这就使得与数据库的操作中显得十分方便(尤其是在外键数据的处理上)。但是除了简单...
  • java中数据类型主要有两种:1、基本的数据类型:long,int,byte,float,double,这些只是基本的数据类型,并不是对象2、对象类型:Long,Integer,Byte,Float,Double以及其他所有的java对象对于Intergerint,Integer是...
  • Integer与int的区别包装类和基本数据类型区别) 1. 默认值  int默认值为0,Integer的默认值为null。推论:Integer既可以表示null又可以表示0 2. 包装类中提供了该类型相关的很多算法操作方法  如把十进制...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,544
精华内容 617
关键字:

包装类和基本类型区别