码出高效:Java开发手册-第2章(12)

简介: 本章开始讲解面向对象思想,并以Java 为载体讲述面向对象思想在具体编程语言中的运用与实践。当前主流的编程语言有50 种左右,主要分为两大阵营:面向对象编程与面向过程编程。面向对象编程(Object-Oriented Programming,OOP)是划时代的编程思想变革,推动了高级语言的快速发展和工业化进程。OOP 的抽象、封装、继承、多态的理念使软件大规模化成为可能,有效地降低了软件开发成本、维护成本和复用成本。面向对象编程思想完全不同于传统的面向过程编程思想,使大型软件的开发就像搭积木一样隔离可控、高效简单,是当今编程领域的一股势不可......

2.7 数据类型

2.7.1 基本数据类型

      虽然Java 是面向对象编程语言,一切皆是对象,但是为了兼容人类根深蒂固的数据处理习惯,加快常规数据的处理速度,提供了9 种基本数据类型,它们都不具备对象的特性,没有属性和行为。基本数据类型是指不可再分的原子数据类型,内存中直接存储此类型的值,通过内存地址即可直接访问到数据,并且此内存区域只能存放这种类型的值。Java 的9 种基本数据类型包括boolean、byte、char、short、int、long、float、double 和refVar。前8 种数据类型表示生活中的真假、字符、整数和小数,最后一种refVar 是面向对象世界中的引用变量,也叫引用句柄。本书认为它也是一种基本数据类型。前8 种都有相应的包装数据类型,除char 的对应包装类名为Character,int 为Integer 外,其他所有对应的包装类名就是把首字母大写即可。这8种基本数据类型的默认值、空间占用大小、表示范围及对应的包装类等信息如表2-4所示。

      默认值虽然都与0 有关,但是它们之间是存在区别的。比如,boolean 的默认值以0 表示的false,JVM 并没有针对boolean 数据类型进行赋值的专用字节码指令,boolean flag = false 就是用ICONST_0,即常数0 来进行赋值;byte 的默认值以一个字节的0 表示,在默认值的表示上使用了强制类型转化;float 的默认值以单精度浮点数0.0f 表示,浮点数的0.0 使用后缀f 和d 区别标识;char 的默认值只能是单引号的'\u0000'表示NUL,注意不是null,它就是一个空的不可见字符,在码表中是第一个,其码值为0,与'\n' 换行之类的不可见控制符的理解角度是一样的。注意,不可以用双引号方式对char 进行赋值,那是字符串的表示方式。在代码中直接出现的没有任何上下文的0 和0.0 分别默认为int 和double 类型,可以使用JDK10 的类型推断证明:var a=0; Long b=a; 代码编译出错,因为在自动装箱时,0 默认是int 类型,自动装箱为Integer,无法转化为Long 类型。

表2-4 基本数据类型

3.jpg

      所有数值类型都是有符号的,最大值与最小值如表2-4 所示。因为浮点数无法表示零值,所以表示范围分为两个区间:正数区间和负数区间。表2-4 中的float 和double 的最小值与最大值均指正数区间,它们对应的包装类并没有缓存任何数值。

      引用分成两种数据类型:引用变量本身和引用指向的对象。为了强化这两个概念的区分,本书把引用变量(Reference Variable)称为refVar,而把引用指向的实际对象(Referred Object)简称为refObject。

      refVar 是基本的数据类型,它的默认值是null,存储refObject 的首地址,可以直接使用双等号== 进行等值判断。而平时使用refVar.hashCode() 返回的值,只是对象的某种哈希计算,可能与地址有关,与refVar 本身存储的内存单元地址是两回事。作为一个引用变量,不管它是指向包装类、集合类、字符串类还是自定义类,refVar 均占用4B空间。注意它与真正对象refObject 之间的区别。无论refObject 是多么小的对象,最小占用的存储空间是12B(用于存储基本信息,称为对象头),但由于存储空间分配必须是8B 的倍数,所以初始分配的空间至少是16B。

      一个refVar 至多存储一个refObject 的首地址,一个refObject 可以被多个refVar存储下它的首地址,即一个堆内对象可以被多个refVar 引用指向。如果refObject 没有被任何refVar 指向,那么它迟早会被垃圾回收。而refVar 的内存释放,与其他基本数据类型类似。

      基本数据类型int 占用4 个字节,而对应的包装类Integer 实例对象占用16 个字节。这里可能会有人问:Integer 里边的代码就只占用16B ?这是因为字段属性除成员属性int value 外,其他的如MAX_VALUE、MIN_VALUE 等都是静态成员变量,在类加载时就分配了内存,与实例对象容量无关。此外,类定义中的方法代码不占用实例对象的任何空间。IntegerCache 是Integer 的静态内部类,容量占用也与实例对象无关。由于refObject 对象的基础大小是12B,再加上int 是4B,所以Integer 实例对象占用16B,按此推算Double 对象占用的存储容量是24B,示例代码如下:

class RefObjDemo {

      // 对象头最小占用空间12 个字节(第1 处)

      // 下方4 个byte 类型分配后,对象占用大小是16 个字节

      byte b1;

      byte b2;

      byte b3;

      byte b4;

      // 下方每个引用变量占用是4 个字节,共20 个字节

      Object obj1;

      Object obj2;

      Object obj3;

      Object obj4;

      Object obj5;

      // RefObjOther 实例占用空间并不计算在本对象内,依然只计算引用变量大小4个字节

      RefObjOther o1 = new RefObjOther();

      RefObjOther o2 = new RefObjOther();

      // 综上,RefObjDemo 对象占用:12B + (1B×4) + (4B×5) + (4B×2) = 44 个字节

      // 取8 的倍数为48 个字节

}

class RefObjOther {

      // double 类型占用8 个字节,但此处是数组引用变量

      // 所以对象头12B + 4B = 16B,并非是8012 个字节

      // 这个数组引用的是double[] 类型,指向实际分配的数组空间首地址

      // 在new 对象时,已经实际分配空间

      double[] d = new double[1000];

}

      在上述示例代码中,第1 处提到的对象头最小占用空间为12 个字节,其内部存储的是什么信息呢?下面来分析其内部结构,如图2-10 所示,对象分为三块存储区域。

4.jpg

图2-10 对象头的内部结构

(1)对象头(Object Header)

      对象头占用12 个字节,存储内容包括对象标记(markOop)和类元信息(klassOop)。对象标记存储对象本身运行时的数据,如哈希码、GC 标记、锁信息、线程关联信息等,这部分数据在64 位JVM 上占用8 个字节,称为“Mark Word”。为了存储更多的状态信息,对象标记的存储格式是非固定的(具体与JVM 的实现有关)。类元信息存储的是对象指向它的类元数据(即Klass)的首地址,占用4 个字节,与refVar 开销一致。

 (2)实例数据(Instance Data)

      存储本类对象的实例成员变量和所有可见的父类成员变量。如Integer 的实例成员只有一个private int value,占用4 个字节,所以加上对象头为16 个字节;再如,上述示例代码的RefObjDemo 对象大小为48 个字节,一个子类RefObjSon 继承RefObjDemo,即使子类内部是空的,new RefObjSon 的对象也是占用48 个字节。

(3)对齐填充(Padding)

      对象的存储空间分配单位是8 个字节,如果一个占用大小为16 个字节的对象,增加一个成员变量byte 类型,此时需要占用17 个字节,但是也会分配24 个字节进行对齐填充操作。


相关文章
|
5天前
|
存储 Java 数据库连接
使用Java开发桌面应用程序
使用Java开发桌面应用程序
14 0
|
5天前
|
Java API 开发工具
java与Android开发入门指南
java与Android开发入门指南
12 0
|
5天前
|
分布式计算 负载均衡 Java
构建高可用性Java应用:介绍分布式系统设计与开发
构建高可用性Java应用:介绍分布式系统设计与开发
8 0
|
5天前
|
前端开发 安全 Java
使用Spring框架加速Java开发
使用Spring框架加速Java开发
24 0
|
5天前
|
前端开发 JavaScript Java
Java与Web开发的结合:JSP与Servlet
Java与Web开发的结合:JSP与Servlet
8 0
|
5天前
|
设计模式 算法 Java
设计模式在Java开发中的应用
设计模式在Java开发中的应用
16 0
|
5天前
|
监控 Java Maven
揭秘Java Agent技术:解锁Java工具开发的新境界
作为JDK提供的关键机制,Java Agent技术不仅为Java工具的开发者提供了一个强大的框架,还为性能监控、故障诊断和动态代码修改等领域带来了革命性的变革。本文旨在全面解析Java Agent技术的应用场景以及实现方式,特别是静态加载模式和动态加载模式这两种关键模式。
27 0
|
6天前
|
存储 Java 开发者
探索Java开发中触发空指针异常的场景
作为一名后端开发者在Java编程的世界中,想必大家对空指针并不陌生,空指针异常是一种常见而又令人头疼的问题,它可能会在我们最不经意的时候突然出现,给我们的代码带来困扰,甚至导致系统的不稳定性,而且最可怕的是有时候不能及时定位到它的具体位置。针对这个问题,我们需要深入了解触发空指针异常的代码场景,并寻找有效的方法来识别和处理这些异常情况,而且我觉得空指针异常是每个Java开发者都可能面临的挑战,但只要我们深入了解它的触发场景,并采取适当的预防和处理措施,我们就能够更好地应对这个问题。那么本文就来分享一下实际开发中一些常见的触发空指针异常的代码场景,并分享如何有效地识别和处理这些异常情况。
20 1
探索Java开发中触发空指针异常的场景
|
6天前
|
传感器 人工智能 前端开发
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
智慧校园电子班牌,坐落于班级的门口,适合于各类型学校的场景应用,班级学校日常内容更新可由班级自行管理,也可由学校统一管理。让我们一起看看,电子班牌有哪些功能呢?
58 4
JAVA语言VUE2+Spring boot+MySQL开发的智慧校园系统源码(电子班牌可人脸识别)Saas 模式
|
14天前
|
Java 索引
Java String应用与开发
Java String应用与开发
22 0