java中数据类型有两类

  1. 基本数据类型
  2. 引用类型

    基本数据类型

    整数型

  • byte - 8bit
  • short - 16bit
  • int - 32bit
  • long - 64bit 【赋值时一般在数字后加上 L(大小写都可以,建议大写与数字1或字母i大写区分开)】

    浮点型

  • float - 32bit 【直接赋值时必须在数字后加上 F(大小写都可以)】

  • double - 64bit【d/D】

    字符型

  • char - 16bit

    布尔型

  • boolean - 1byte/4byte【只有true或false值,有人疑问为什么boolean类型有两个不同的字节,下方会讲解到

《Java虚拟机规范》一书中的描述:“虽然定义了boolean这种数据类型,但是只对它提供了非常有限的支持。在Java虚拟机中没有任何供boolean值专用的字节码指令,Java语言表达式所操作的boolean值,在编译之后都使用Java虚拟机中的int数据类型来代替,而boolean数组将会被编码成Java虚拟机的byte数组,每个元素boolean元素占8位”。这样我们可以得出boolean类型占了单独使用是4个字节,在数组中又是1个字节。 虚拟机为什么要用int来代替boolean呢?为什么不用byte或short,这样不是更节省内存空间吗。大多数人都会很自然的这样去想,我同样也有这个疑问,经过查阅资料发现,使用int的原因是,对于当下32位的处理器来说,一次处理数据是32位(这里不是指的是32/64位系统,而是指CPU硬件层面),具有高效存取的特点。 根据http://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html官方文档的描述: boolean: The boolean data type has only two possible values: true and false. Use this data type for simple flags that track true/false conditions. This data type represents one bit of information, but its “size” isn’t something that’s precisely defined. 布尔类型:布尔数据类型只有两个可能的值:真和假。使用此数据类型为跟踪真/假条件的简单标记。这种数据类型就表示这一点信息,但是它的“大小”并不是精确定义的。 可以看出,boolean类型没有给出精确的定义,《Java虚拟机规范》给出了4个字节,和boolean数组1个字节的定义,具体还要看虚拟机实现是否按照规范来,所以1个字节、4个字节都是有可能的。这其实是运算效率和存储空间之间的博弈,两者都非常的重要。


基本数据类型和引用类型的区别

  1. 概念层次
    1. 基本类型:变量名指向具体值
    2. 引用类型:变量名指向存数据对象的内存地址
  2. 内存层次
    1. 基本类型:变量在声明后,jvm会立即给它分配内存空间
    2. 引用类型:变量在声明后不会立即分配内存空间,只储存一个内存地址(类似于C的指针)
  3. 判断是否相等
    1. 基本类型:使用时需要赋值具体值,使用==判断
    2. 应用类型:使用时可以赋值null,判断一般使用equals方法

      包装类,装箱、拆箱

  • Java为每一种基本数据类型都提供了对应的包装类

    • Byte => bye
    • Short => short
    • Integer => int
    • Long => long
    • Float => float
    • Double => double
    • Character => char
    • Boolean =>boolean

      引入包装类的目的就是:提供一种机制,使得基本数据类型可以与引用类型互相转换

  • 装箱【将基本数据类型转化为引用类型】

    • 装箱过程是通过调用包装类的 valueOf 方法实现的。
  • 拆箱【将引用类型转化为基本数据类型】
    • 拆箱过程是通过调用包装类的 xxxValue 方法实现的(xxx 代表对应的基本数据类型)。
  • 自动装箱、自动拆箱
    • 基本数据(Primitive)型的自动装箱(boxing)拆箱(unboxing)自 JDK 5 开始提供的功能。

自动装箱与拆箱的机制可以让我们在 Java 的变量赋值或者是方法调用等情况下使用原始类型或者对象类型更加简单直接。 因为自动装箱会隐式地创建对象,如果在一个循环体中,会创建无用的中间对象,这样会增加 GC 压力,拉低程序的性能。所以在写循环时一定要注意代码,避免引入不必要的自动装箱操作。

  1. Integer num = 10; // 自动装箱,没有通过new的方式创建对象
  2. Integer num2 = new Integer(10) // 非自动装箱

Java 对于自动装箱和拆箱的设计,依赖于一种叫做享元模式的设计模式 扩展:https://www.cnblogs.com/dolphin0520/p/3780005.html

装箱、拆箱的应用

  • 一种最普通的场景是:调用一个含类型为 Object 参数的方法,该 Object 可支持任意类型(因为 Object 是所有类的父类),以便通用。当你需要将一个值类型(如 int)传入时,需要使用 Integer 装箱。
  • 另一种用法是:一个非泛型的容器,同样是为了保证通用,而将元素类型定义为 Object。于是,要将值类型数据加入容器时,需要装箱。
  • 当 == 运算符的两个操作,一个操作数是包装类,另一个操作数是表达式(即包含算术运算)则比较的是数值(即会触发自动拆箱的过程)。

    装箱、拆箱的注意点

  1. 装箱操作会创建对象,频繁的装箱操作会造成不必要的内存消耗,影响性能。所以应该尽量避免装箱
  2. 基础数据类型的比较操作使用 ==,包装类的比较操作使用 equals 方法