Difference between wrapper class and primitive type in Java

This article has participated in the "Newcomer Creation Ceremony" event to start the road of gold creation together.

foreword

I found a problem when writing the project,

public boolean connect(){
}

There is another way of writing

public Boolean connect(){
}

The two writing methods do not report errors during operation, so what is the difference?

Provoking thinking: What is the difference between the two writings here?

boolean is a basic data type in Java, and Boolean is a class in Java. The boolean type will assign false to the property during the "assign zero" phase. And Boolean is a class that assigns null to objects during the "assign zero" phase.

If it is a static property, it will be assigned when the class is loaded. If it is a normal class property, it will be assigned when the object is instantiated. These two points can learn about "class loading mechanism" and "object creation process".

Class loading mechanism:

  • Loading: Obtain the binary byte stream of the class according to the full name of the class, load the class into memory and generate an Classobject representing the class in the heap as the access entry for the data in the method area

  • Validation: Verify classthat the byte stream in the file conforms to the JVMspecification

  • Preparation: allocate memory for the static properties of the class in the method area, and initialize the default value ( booleanthe default value of false, Booleanthe default value of null)

  • Analysis: Convert the symbolic reference in the constant pool into a direct reference, which can be understood as converting an object reference into a pointer

  • Initialization: actually start executing the code in the class, static property assignments and static blocks

Object instantiation process:

  • Check if the class has been loaded (parent delegation)

  • Allocate memory space for an object (pointer collision)

  • zero-initialization ( false / null)

  • Set the object header (object generation age and other information)

  • Execute <init> methods (property initialization, statement blocks and constructors)

So, Boolean is just loaded, not yet instantiated, and no memory is allocated before being instantiated, so it is null

Check out the source code to see the properties and constructors of Boolean and see how it wraps 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)

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

在这里插入图片描述

参考:blog.csdn.net/mkii_hong/a…

包装类和基本类型

什么是包装类?

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

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

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再去比。

Guess you like

Origin juejin.im/post/7118378864002203678