重学Java(二):对象无处不在

本系列文章内容来自于《Thinking in Java》作者的最新续作《On Java》基础卷,作者根据最新 Java 8、11、17的内容,重讲了Java的编程思想,值得初学者阅读。

操作对象

Java将一切都视为对象,但实际操作的其实是该对象的引用,再由引用来修改对象信息。

一种安全的做法是,始终在创建引用时就进行初始化

1
2
String s; 
String s = "asdf";

首行代码中,创建了一个引用,但这个引用还没有连接对象,直接使用起来会有问题。

第二行代码可以看到,字符串可以用带引号的文本进行初始化。

创建对象

引用的作用是关联对象。通常使用 new 关键字来创建对象。

数据存储方式

  1. 寄存器。这是最快的存储方式,因为数据会直接保存在CPU中,但是程序员无法直接控制寄存器的分配,因为寄存器数量是有限的。
  2. 栈(Stack)。数据保存在随机顺序存储器(RAM)中,处理器通过栈指针操作数据,在效率上仅次于寄存器。在栈上的所有对象都要明确其生命周期,灵活性上稍有限制。对象引用保存在栈中。
  3. 堆(Heap)。数据也保存在 RAM 中,用于存储所有 Java 对象。编译器不关心位于堆上的对象存在多久,使用较为灵活。但分配和清理堆存储时花费时间略高于栈。
  4. 常量存储区。
  5. 非 RAM 存储。一个例子是序列化对象,指的是转换为字节流并能发送到其他机器上的对象;另一个例子是持久化对象,也就是保存在磁盘上的对象,这些对象能转换为其他形式保存到其他媒介中,也能在需要的时候重新转换为 RAM 对象。

注意:对基本类型来说,无需使用 new 关键字创建基本类型的变量,而是直接创建一个“自动变量”,也不是引用。基本类型变量会在栈上保存它的值。

基本类型(有符号) 大小 最小值 最大值 包装类
char 16位,2个字节 \u0000(0) \uffff(65535) Char
byte 8位,1个字节 -128 127 Byte
short 16位 -32768 32767 Short
int 32位 -2^31^ 2^31^ - 1 Int
long 64位 -2^63^ 2^63^ - 1 Long
float 32位 IEEE 754 IEEE 754 Float
double 64位 IEEE 754 IEEE 754 Double

除了以上几个基本类型,还有 boolean 类型,其包装类为 Boolean。通过包装类型可以将基本类型呈现为位于堆上的非原始对象。自动装箱和拆箱机制能够将基本类型对象和包装类对象自动转换。

高精度数字

  • BigInteger:支持任意精度的整数。
  • BigDecimal:支持任意精度的浮点数

数组

创建一个用于放置对象的数组时,实际数组内包含的是引用,这些引用会被自动初始化为 null 值,即这些引用并未指向任何一个对象。操作引用前需确保其指向了某个对象。

作用域

Java对象的生命周期和基本类型有所不同。当使用new创建一个对象时,该对象在其作用域结束后依然存在,而其引用则会在作用域结束后消失。

垃圾收集器会监视所有通过new创建的对象,并及时发现哪些对象不再被引用。然后就会释放这部分对象占用的内存,使这些内存可以用于其他新对象。垃圾回收机制解决了由于程序员忘记释放内存而导致的内存泄漏问题。

创建类

大多数面向对象编程语言会使用 class 关键字描述对象种类。

字段

当定义类时,可以为其定义两种元素:字段和方法。

当一个类的字段是基本类型时,即便你没有初始化这些字段,它们也会拥有默认值:

基本类型(有符号) 默认值
char \u0000(null)
byte (byte)0
short (short)0
int 0
long 0L
float 0.0f
double 0.0d
boolean false

这一特点确保了基本类型的字段一定被初始化。但这种机制并不会应用于局部变量(如在方法内部的变量),因为局部变量不是类的字段,使用前必须赋值。

方法、参数和返回值

方法最基础的部分包括方法名、参数、返回值以及方法体。方法名和参数列表共同构成了方法签名。方法签名是方法的唯一标识符。

Java中的方法只能作为类的一部分而存在。除static方法外,方法只能通过对象调用。

除基本数据类型外,一般情况下,给方法参数传递对象,实际上就是对象的引用。

当返回值的类型是void时,使用return关键字的作用是退出该方法。

编写并运行Java程序

名称可见性

为了清晰地描述库的名称,Java语言使用的方法是将互联网域名反转使用。因为域名是唯一的,所以不会产生冲突。

这种机制确保了所有文件都有其对应的命名空间,同时文件里定义的类都有唯一对应的标识符。但这种方式也会为源代码管理产生挑战。

通过空文件夹层层嵌套而形成的这种文件夹结构,其作用不只是为了对应反转的URL,通常用于保存一些表明文件夹内容的数据。

使用其他组件

Java消除了所谓的前向引用,即即使类稍后在文件中才会定义,依然可以在文件的上文中使用这个类。

import语句的作用是通知编译器导入一个指定位置的包,即放置各种类的库。

static 关键字

使用static的字段或方法不依赖于任何对象。非static的字段和方法必须基于指定的对象。不能在没有具体对象的前提下,使用static方法直接调用非static成员或方法。

编写程序

所有Java文件都会导入一个特定的库,即java.lang。里面有一些我们不用额外导入就能使用的类,如System、String等。

Java文件中必须存在一个与该文件同名的类。如果需要创建一个能独立运行的程序,文件同名的类中还要包含一个程序启动的入口方法 main() 方法。

main() 方法的参数是一个 String 对象的数组,用于获取控制台的输入。

运行程序

1
2
javac Helloworld.java   # 编译,将.java文件编译成.class字节码文件
java Helloworld # 解释,自动获取路径下与类名Helloworld同名的class字节码文件,并运行其中的main方法

未完待续