• 春眠不觉晓,Java数据类型知多少?基础牢不牢看完本文就有数了


    文编|JavaBuild

    哈喽,大家好呀!我是JavaBuild,以后可以喊我鸟哥!俺滴座右铭是不在沉默中爆发,就在沉默中灭亡,一起加油学习,珍惜现在来之不易的学习时光吧,等工作之后,你就会发现,想学习真的需要挤时间,厚积薄发啦!

    我们知道Java是面向对象的静态型编程语言,在Java的世界里万物皆对象。但我认为是万物皆数据,世界由各种各样数据构建起来,我们通过程序去实现数据的增删改查、转入转出、加减乘除等等,不同语言的实现方式殊途同归。
    由此可见,数据对于程序语言的重要性,而在Java中用来规范数据的标准我们将其称之为“数据类型”,这便是我们今天的Topic!
    在下图中我们将Java中的数据类型分为三个部分:基本数据类型包装类型引用数据类型

    基本数据类型

    在Java中“boolean、char、byte、short、int、long、float 和 double”构建起了数据结构的基础,非常重要,也是很多公司面试的高频考点,所以,为了方便记忆,鸟哥整理了一份表格如下:

    类型名称 位数 字节 默认值 取值范围 包装类 缓存区间
    byte 8 1 0 -128 ~ 127 Byte -128~127
    short 16 2 0 -32768 (-2^15) ~ 32767 (2^15-1) Short -128~127
    int 32 4 0 -2147483648 ~ 2147483647 Integer -128~127
    long 64 8 0L -2^63 ~2^63 - 1 Long -128~127
    char 16 2 '\u0000' 0~65535 Character 0 ~127
    float 32 4 0f 1.4e-45 ~ 3.4e+38 Float
    double 64 8 0d 4.9e-324~1.798e+308 Double
    boolean 1 false true(1),false(0) Boolean

    字节与位的关系

    在计算机的物理存储中,一条电路线被称之为1位,二进制识别中为0(低电平)或1(高电平),英文中用bit表示,而8个bit组成一个字节,英文为Byte

    布尔类型的说明

    对于 boolean,官方文档未明确定义,它依赖于 JVM 厂商的具体实现。逻辑上理解是占用 1 位,但是实际中会考虑计算机高效存储因素。

    基本数据类型之间的转换规则

    基本数据类型之间也存在着转换关系,往往发生在表达式计算的过程中,而这种转换根据不同场景分为:自动类型转换&强制类型转换
    自动类型转换:Java编译器无需显示处理,一般由等级低的数据类型向等级高的数据类型转换,如int -> long。很明显,int所能存储的数据必定是long的子集,不存在数据丢失问题。

    等级由低到高
    byte -> short -> int -> long -> float -> double
    char -> int -> long -> float -> double
    int a = 3;
    double b = 1.5;
    // 自动类型转换:a 被转换为 double 类型
    double result = a * b;
    System.out.println("结果: " + result); // 输出:结果: 4.5

    强制类型转换:由高等级数据转为低等级数据时往往存在强制类型转换,这时候Java编译器认为存在隐患,需要程序员介入,显示的处理强转,潜在风险是数据丢失或精度丢失。

    由左到右需要强转
    double -> float -> long -> int -> char -> short -> byte
    double c = 10.1;
    // 强制类型转换:将 double 类型转换为 int 类型,精度丢失
    int d = (int) c;
    System.out.println("整数值: " + d); // 输出:整数值: 10

    转换规则如下

    = 右边先自动转换成表达式中最高级的数据类型,再进行运算。整型经过运算会自动转化最低 int 级别,如两个 char 类型的相加,得到的是一个 int 类型的数值。
    = 左边数据类型级别 大于 右边数据类型级别,右边会自动升级
    = 左边数据类型级别 小于 右边数据类型级别,需要强制转换右边数据类型
    char 与 short,char 与 byte 之间需要强转,因为 char 是无符号类型

    包装类型

    这八种基本类型都有对应的包装类分别为:Byte、Short、Integer、Long、Float、Double、Character、Boolean 。
    因为Java中一切皆对象,基本数据类型无法满足这个大口号,比如泛型、序列化、类型转换、高频数据区间的缓存等,故为了弥补,便诞生了8种基本数据类型对应的包装类型。

    包装类型与基本数据类型差异

    • 使用场景: 在Java中除了一些常量和局部变量的定义会用到基础数据类型外,绝大部分情况下均采用包装类型,如方法参数,对象属性等,且基本数据类型不能用于泛型,包装类型可以!
    • 默认值: 包装类型比基本类型多了一个非功能值:null,在不做任何赋值的情况下,包装类型的默认就是null,而基本数据类型都有相应的默认值,见上面表格。
    • 所占内存 因为包装类型是对象,会有一些对象头等信息,所以占用空间上要大于基本数据类型。
    • 比较方式 基本类型采用 == 号比较,比较的是值,而对于包装类型来说,==比较的其实是对象的内存地址,对象值的比较需要通过equals()方法完成。

    [注意]: 很多同学都以为基本数据类型存在栈中,包装类型作为对象存储在堆中,这个观点是有失偏颇的,如果基础数据类型的成员变量在没有被static关键字修饰的情况下,是存在的堆中的,只有局部变量被存在栈的局部变量表中!而全部对象都存在堆中,也是个不完整的答案,这里涉及到HotSpot中的逃逸分析,等讲到JVM时再展开说吧。

    自动装箱与拆箱

    在Java中不仅仅基本类型之间存在着转换,基本数据类型与包装类型之间同样存在着转换,在JDK1.5之前是不支持自动装箱与拆箱的,所以那时候需要通过显示的方法调用来实现转换,而JDK1.5开始,自动化程度提升了。
    装箱:基本类型转变为包装器类型的过程。
    拆箱:包装器类型转变为基本类型的过程。

    //JDK1.5之前是不支持自动装箱和自动拆箱的,定义Integer对象,必须
    Integer i = new Integer(8);
    //JDK1.5开始,提供了自动装箱的功能,定义Integer对象可以这样
    Integer i = 8;
    int n = i;//自动拆箱

    实现原理

    装箱是通过调用包装器类的 valueOf 方法实现的
    拆箱是通过调用包装器类的 xxxValue 方法实现的,xxx代表对应的基本数据类型。
    如int装箱的时候自动调用Integer的valueOf(int)方法;Integer拆箱的时候自动调用Integer的intValue方法。

    【需要注意的问题点】:
    1、整型的包装类 valueOf 方法返回对象时,在常用的取值范围内,会返回缓存对象。
    2、浮点型的包装类 valueOf 方法返回新的对象。
    3、布尔型的包装类 valueOf 方法 Boolean类的静态常量 TRUE | FALSE。

    Integer i1 = 100;
    Integer i2 = 100;
    Integer i3 = 200;
    Integer i4 = 200;
    System.out.println(i1 == i2);//true
    System.out.println(i3 == i4);//false
    Double d1 = 100.0;
    Double d2 = 100.0;
    Double d3 = 200.0;
    Double d4 = 200.0;
    System.out.println(d1 == d2);//false
    System.out.println(d3 == d4);//false
    Boolean b1 = false;
    Boolean b2 = false;
    Boolean b3 = true;
    Boolean b4 = true;
    System.out.println(b1 == b2);//true
    System.out.println(b3 == b4);//true

    以上代码中,我们已Integer为例展开解释一下,基本数据类型的包装类除了 Float 和 Double 之外,其他六个包装器类(Byte、Short、Integer、Long、Character、Boolean)都有常量缓存池。而Integer的缓存区间是-128~127。
    我们去看一下Integer类的缓存源码

    public static Integer valueOf(int i) {
    if (i >= IntegerCache.low && i <= IntegerCache.high)
    return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
    }
    private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static {
    // high value may be configured by property
    int h = 127;
    }
    }

    IntegerCache 这个静态内部类中设置了缓存区间,当我们通过valueOf()方法获取Integer对象时,会先去找该整数是否在缓存池中,有则直接返回,没有则新建并存入缓存池。
    这就解释了为什么第一个 == 号结果是true,而第二个为false,因为超出了缓存区间,每次都新建一个对象,而 == 号又是比较对象地址,对于两个不同的对象,地址肯定不一样啦。

    引用数据类型

    Java的数据类型除了8种基本数据类型和对应的包装类型外,还有一个分类为引用数据类型,在文章开头的树形图中已经分好,引用类型分为:数组,类和接口。
    那为什么叫他引用数据类型呢?在创建引用数据类型时,会在栈上给其引用句柄,分配一块内存,然后对象的信息存储在堆上,在程序调用的时候,通过栈上的引用句柄指向堆中的对象,从而获取想要的数据。
    因数组,类,接口都包含着太多内容,在后续的博客中会陆续详解,所以本文略做介绍,粗略感受一下。
    数组:

    int [] arrays = {1,2,3};
    System.out.println(arrays);
    // 打印结果:[I@2d209079

    打印结果中的一串内容,世界上是arrays的对象首地址,要想看到结果,需要调用java.lang.Object 类的 toString() 方法。
    类:

    public final class String
    implements java.io.Serializable, Comparable, CharSequence {
    /** The value is used for character storage. */
    private final char value[];
    }

    String是一个类,也是字符串的代表,所以它也是引用数据类型
    接口:

    List list = new ArrayList<>();
    System.out.println(list);

    List 是一个非常典型的接口,属于Java的一种集合,存储的元素是有序的、可重复的。

    【注意】

    1、包装类可以实现基本类型和字符串之间的转换,字符串转基本类型:parseXXX(String s);基本类型转字符串:String.valueOf(基本类型)。
    2、引用数据类型的默认值为 null,包括数组和接口。
    3、char a = 'h'char :单引号,String a = "hello" :双引号。
  • 相关阅读:
    使用 Bitnami PostgreSQL Docker 镜像快速设置流复制集群
    JeecgBoot 3.4.3-GA 版本发布,开源免费的企业级低代码平台
    AcWing 1211:蚂蚁感冒 ← 模拟题
    用JpaTransactionManager操作数据库事务
    通达信软件编程写一段抄底的源代码
    效率提升的好物分享
    web网页大作业:基于html设计与实现的茶文化网站12页(带psd)
    不用写一行代码!Python最强自动化神器!
    Docker下载Tomcat镜像并运行Tomcat容器
    element UI 组件封装--搜索表单(含插槽和内嵌组件)
  • 原文地址:https://www.cnblogs.com/JavaBuild/p/17962423