Java 基础教程

引用数据类型

在 Java 语言中,除八种基本的数据类型外,其他的数据类型统称为引用类型(Reference Type),包括类、接口、数组、枚举和注解类型。之所以称为引用类型,是因为这些类型的数据在保存和使用过程中采用了“引用”的方式,与基本数据类型的情况完全不同。

“引用类型”(Reference Type)也称为“复合类型”(Complex Type)或“构造类型”(Constructed Type)。

一个基本类型数据只占有一个定长的连续存储空间,保存单一的值。如下:

int a = 10;

上面语句运行时,系统会在内存中为声明的变量 a 分配 32 位存储空间,且将值设置为 10。如果是引用类型,则数据存储的情况就要复杂得多。如下:

// 定义用户实体类
public class User {
    /** 用户ID */
    private int id = -1;
    /** 用户姓名 */
    private String name = "";

    public User(int id) {
        this.id = id;
    }

    public String show() {
        return "id=" + id + " name=" + name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

// 使用定义的用户实体类
public class TestReferenceType {

    public static void main(String[] args) {
        User user;
        user = new User(100);
        user.setName("Tom");
        System.out.println(user.show());
    }

}

输出结果:

id=100 name=Tom

运行上面代码时,执行时如下:

(1)User user; // 系统为新声明的变量 user 分配长度为 32 位存储空间,此时变量 user 尚未被赋值,不能使用。

(2)user = new User(100); // 系统执行该语句等号右边的表达式,使用 new 操作符调用 User 的构造方法创建一个 User 类的对象,注意:对象的创建过程后续将详细介绍。

(3)user.setName("Tom"); // 调用 user 变量的连个 set 方法,为 user 设置 id 和 name 属性。

(4)System.out.println(user.show()); // 调用 user 变量的 show() 方法显示设置的 id 和 name 属性值。

对象的创建步骤

(1)为新建对象分配存储空间并进行初始化

为一个对象分配空间也就是为其封装的所有属性分配存储空间。可以简单地认为一个 Java 对象占用的存储空间大小就是其所有属性所需要的存储空间总和。分配存储空间后,系统将自动对新建对象的所有属性进行默认初始化,规则如下表:

属性类型默认初始值
byte
0
short
0
int
0
long
0L
char
'\u0000'
float
0.0F
double
0.0D
boolean
false
引用类型null

默认初始化操作是系统强制进行的,程序员无法进行干预或者取消,实际上是将所有属性对应的存储空间的二进制位全部设置为0。其中,null 是一个 Java  关键字,可以作为一个特殊的常量值被赋值给任何引用类型变量,它表示一个空的引用 —— 即不指向任何对象。上面示例默认初始化后内存图如下:

注意:此时变量和新建对象之间还没有建立任何联系

(2)对新建对象进行显示初始化

显示初始化也是对新建对象的属性赋值,其值来自于属性在声明时被指定的缺省值。如下:

public class User {
    /** 用户ID */
    private int id = -1;
    /** 用户姓名 */
    private String name = "";
}

上面语句中,显示初始化 id 为 -1,name 为空字符串。上面示例显示化初始化后内存如下图:

注意:如果属性在声明时未指定缺省值,则不对其进行显示初始化。

(3)执行构造体中的语句

上面示例中用如下代码创建 User 对象:

user = new User(100);

该构造方法中的 this.id = id; 语句执行时将实参 100 赋值给 id 属性,至此新对象的创建工作才算完成。此时这个新建对象和先前声明的变量 user 间还是没有建立任何关联。上面示例执行完构造函数后内存如下图:

接下来该执行第二条语句中的赋值操作:

user = new User(100);

上面语句中,将新创建的 User 对象赋值给 user 变量,此时两者存在了关联关系。内存结构如下图:

在前面我们介绍过一个变量的地址空间仅为 4Byte(32位),那么它是怎样装下引用对象的呢?实际上赋值给 user 变量的并不是新建对象封装的具体信息,而是该对象的哈希码值 —— 每一个 Java 对象都对应一个唯一的整数编号作为其内部表示,以实现对 Java 对象的快速检索。例如:

User user;
user = new User(100);
user.setName("Tom");
System.out.println(user.show());
System.out.println(Integer.toHexString(user.hashCode()));

输出结果:

id=100 name=Tom
3764951d

上面代码可知,user 对象的哈希代码十六进制为 3764951d。由于哈希码值能够用来定位一个对象,因为也被称为对象的“句柄”(Handle)。

由于变量 user 记录了一个对象的“句柄”,因而我们就可以通过 user 找到对象并进行操作。变量 user 和真正对象之间的这种关系我们称为“引用(Reference)”—— user 变量引用了该对象,因此我们称 user 为引用类型变量。user 变量是对 Java 对象的一个引用,user 变量占用的 32 位存储空间为引用空间。

说说我的看法
全部评论(
没有评论
关于
本网站属于个人的非赢利性网站,转载的文章遵循原作者的版权声明,如果原文没有版权声明,请来信告知:hxstrive@outlook.com
公众号