这一章从最宽泛的基础上介绍了对象的一些特性,如果你刚接触 Java ,那么过一遍就好,如果想深入,还是那句话,直接去看 《深入理解Java虚拟机》 ,那本书真是从对象的存储,对象的创建,对象的清除,以及清除算法都给你整的明明白白。

所以这一章还是照例,高度浓缩总结一下,我顺便在添点个人的理解。

对象操纵

Java 中对象分为引用和实体,我们经常在类使用组合模式 —— 定义一个其他类的引用,像下面这样:

// 家庭
public class Family {
  // 家庭是由人组成的,这里定义了一个 "人" 的引用,但是这并不代表真实的对象
  // 只有将引用指向一个对象之后,才能通过这个引用去操作真实的对象
  // 就像遥控器与电视机进行配对,配对成功之后才能用遥控器去操作电视机
  People people;
  
  // 在这里将引用指向一个真正的对象,完成引用的初始化
  public void initPeoPle () {
    people = new People("名字","身高","兴趣爱好...");
  }
}

同时对于最常用的对象 —— String 来说,Java 也支持直接通过字面量的方式来创建对象:

// 家庭
public class Family {
  // 通过字面量的方式创建了一个 String 对象的初始化
  private String name = "小明的家"
}

对象创建

Java 中创建对象的几种方法:

  • 最基础的 —— 使用关键字 new 来创建一个对象的实例
String name = new String("张三")
  • 使用反射来创建一个对象 —— 我们只要知道类的全限定名,就可以使用反射来调用构造方法创建类的实例,这种方式通常在框架中使用
Class clazz = Class.forName("包名+类名");
Class类型 o = (Class类型) clazz.getConstructor().newInstance();

数据存储

这里作者简单介绍了一下 计算机 中哪些地方可以进行数据存储:

  • 寄存器(Registers) : 属于 CPU 内部的一块存储区域,速度最快,Java 并没有直接控制寄存器的权力。
  • 栈内存(Stack) : 位于常规内存 RAM 中,速度也很快,仅次于寄存器。Java 在栈上只保存对象的引用,而没有保存对象的真正数据。
  • 堆内存(Heap) :也位于 RAM ,保存 Java 真正的对象数据,使用 new 命令时会自动在堆上进行内存分配。
  • 常量存储(Constant storage) : 位于 ROM ,直接被保存在代码中。
  • 非 RAM 存储(Non-RAM storage) : 存放于程序之外的数据,对象被持久化之后可以存放在磁盘上,也可以在另外一台机器上,这里指的是序列化之后的二进制对象。

Java 中的基本类型数据

Java 中并不是一切数据都是对象,对于那些高频使用的数据,Java 将它们称为 基础类型数据 ,Java 并不通过 new 操作创建这些数据,而是直接将基础类型数据存放在 栈 中。

Java 规定了每种基础类型数据占用内存的大小,并且不随硬件的变化而变化。

基本类型大小最小值最大值包装类型
booleanBoolean
char16 bitsUnicode 0Unicode 2^16 -1Character
byte8 bits-128+127Byte
short16 bits- 215+ 2^15-1Short
int32 bits- 2^31+ 2^31 -1Integer
long64 bits- 2^63+ 2^63 -1Long
float32 bitsIEEE754IEEE754Float
double64 bitsIEEE754IEEE754Double
voidVoid

Java 中的数值类型分正负,基本类型和包装类型会在编译器的帮助下完成自动转换工作,我们称为 拆箱/装箱。

高精度数值

浮点数运算由于计算机结构会存在精度问题,于是在 Java 中如果涉及金融计算等,需要使用 BigIntegerBigDecimal 类进行对应的运算。

数组的存储

数组也是 Java 中非常重要的数据类型之一,它属于 引用类型 ,也就是数组并不属于基本类型数据。

Java 中的集合框架中比如可变列表,链表 等类就是在数组的基础上封装构建起来的数据结构。

当我们创建对象数组时,实际上创建的是一个对应对象的 引用数组,每个引用的初始值都是 null ,所以在使用数组之前需要对其元素进行赋值。

代码注释

Java 中注释分为以下几种:

//  单行注释

/**
* 多行注释
*/


对象清理

对象被使用完之后会被垃圾回收器回收,至于怎样判断 什么是 「垃圾」,以及具体怎样回收,还是建议直接看虚拟机相关的书来的更直接。

作用域

Java 中作用域由大括号进行决定:

// 下面是一个代码块
{
  // 定义一个 int 类型的变量 x 
  int x = 12;
  // 在代码块中嵌套一个代码块
  {
    // 定义 int 类型的变量 q
    int q = 96;
    // 在这里同样可以使用变量 x
  }
  // 在这里只能使用 x ,不能使用 q
}

对象作用域

// 下面是一个代码块
{
  String s = new String("a string");
}
// 超出对象 s 的作用域

Java 中的垃圾回收器会对创造出来的对象是否仍旧有用做判断,无用的对象会被回收。

类的创建

类型

Java 中使用 class 来定义类 ,一个 .java 文件中只能有一个 public 的 class 类,且类名与文件名相同。

字段

字段可以看做是类的状态,或是描述类的元信息:

class Dog {
  // 名称
	private String name;
  // 年龄
  private int age;
  // ... 其他狗的属性
}

基本类型默认值:

类中定义的成员变量在类初始化时会有一个默认值:

基本类型初始值
booleanfalse
char\u0000 (null)
byte(byte) 0
short(short) 0
int0
long0L
float0.0f
double0.0d

这个机制是为了保证基本类型的字段始终能被初始化,可以减少 Bug 的出现,但是我们仍然需要手动给字段赋值最好。

方法中的局部变量没有初始值。

方法使用

方法、或是 函数 ,都是对象所拥有的能力,或者是对象对外提供的服务,方法包括:

  • 方法返回值类型,如果没有则是 void
  • 方法 名
  • 方法参数列表

其中 方法名 + 参数列表 组成了 方法签名,签名与方法的重载息息相关。

既然方法是在对象中定义的,那么调用方法就需要获得对象的实例:

[对象引用].[方法名](方法入参 1,2,3)

参数列表

参数是方法需要的信息,比如你要实现一个下载图片的方法,那么你需要知道这幅图片在哪里,也就是具体的 urlurl 就是方法的入参。

参数列表可以是0个或多个,参数的顺序不同会重载为不同的方法,但是不建议这样做,因为调用的时候非常容易出错。

有返回值的方法需要使用 return 来将对应类型的值反回:

boolean flag() { 
    return true; 
}

double naturalLogBase() { 
    return 2.718; 
}

void nothing() {
     return;
}

void nothing2() {

}

而如果一个方法没有返回值,只是一个纯粹的处理流程,则不需要显式的写 return ,或者也可以使用 return 提前结束流程,比如某个条件不成立时,直接 return 则方法结束。

程序编写

介绍了一些编写 Java 程序方面的机制。

命名可见性

作者这里说了很多,但是 Java 实际上就是通过 来切割不同的命名空间,包名是唯一的,小写。

使用其他组件

这里指的是使用其他类,需要使用 import 关键字导入其他类,这样才知道具体使用哪个类。

例如:

import java.util.ArrayList

static 关键字

Java 中 是作为一类对象的外观以及行为的描述。 通过 new 来为对象分配真正的存储空间,但是这也存在某种缺陷:

  • 只想为特定字段分配一个共享空间,而这个空间与具体创建的对象没有关联,甚至不创建对象你也想让这个类具有这个属性
  • 创建一个与类无关的方法,即使没有对象,也要能够调用这个方法。

在语法上 static 关键字 满足了上述两点条件。 Java 中被 static 修饰的字段叫静态字段,方法叫静态方法,静态的字段/方法 与对象无关,它们是属于类的属性。

所以调用静态方法时可以:

类名.方法名();

static 修饰的方法无需创建对象就可以直接通过类的引用来调用方法,而 Java 程序的整个入口 main 方法正是一个静态方法。

小试牛刀

这里作者给了一个打印当前日期的例子:

import java.util.Date;

public class HelloDate {
  public static void main(String[] args) {
    System.out.println("Hello, it's: ");
    System.out.println(new Date());
  }
}

编译和运行

Java 的源文件是 .java 文件,但是源文件是不能直接运行的,编译器将源文件编译为 .class 字节码文件后被 JVM 虚拟机加载并执行

编程风格

Java 中 变量和方法一般采用驼峰命名法,即小写字母开头,第二个单词开始首字母大写。

小结

这一章应该算是介绍了一个语言基本的语法方法面的一些知识。

Q.E.D.

知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议

最是人间留不住,曾是惊鸿照影来。