码出高效: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 个字节进行对齐填充操作。


相关文章
|
1月前
|
Java
Java开发实现图片URL地址检验,如何编码?
【10月更文挑战第14天】Java开发实现图片URL地址检验,如何编码?
62 4
|
30天前
|
监控 Java 测试技术
Java开发现在比较缺少什么工具?
【10月更文挑战第15天】Java开发现在比较缺少什么工具?
34 1
|
1月前
|
Java
Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
【10月更文挑战第14天】Java开发实现图片地址检验,如果无法找到资源则使用默认图片,如何编码?
56 2
|
11天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
24 4
|
12天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
35 4
|
23天前
|
开发框架 JavaScript 前端开发
HarmonyOS UI开发:掌握ArkUI(包括Java UI和JS UI)进行界面开发
【10月更文挑战第22天】随着科技发展,操作系统呈现多元化趋势。华为推出的HarmonyOS以其全场景、多设备特性备受关注。本文介绍HarmonyOS的UI开发框架ArkUI,探讨Java UI和JS UI两种开发方式。Java UI适合复杂界面开发,性能较高;JS UI适合快速开发简单界面,跨平台性好。掌握ArkUI可高效打造符合用户需求的界面。
75 8
|
18天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
18天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
36 2
|
18天前
|
监控 Java 数据库连接
在Java开发中,数据库连接管理是关键问题之一
在Java开发中,数据库连接管理是关键问题之一。本文介绍了连接池技术如何通过预创建和管理数据库连接,提高数据库操作的性能和稳定性,减少资源消耗,并简化连接管理。通过示例代码展示了HikariCP连接池的实际应用。
18 1
|
27天前
|
Java 大数据 API
别死脑筋,赶紧学起来!Java之Steam() API 常用方法使用,让开发简单起来!
分享Java Stream API的常用方法,让开发更简单。涵盖filter、map、sorted等操作,提高代码效率与可读性。关注公众号,了解更多技术内容。