Java 必知必会——什么是对象引用?按值传递 OR 按引用传递?

1. 什么是对象?

任何事物都可以作为一个对象,一台电脑、一部手机等等等等。

在面向对象程序设计的 Java 中,程序是由对象组成的,对象包含了描述其状态的数据(属性)和可以执行的操作(方法),因此,每个对象都可以表示具体的事物或者抽象的规则、计划或事件。

类是构造对象的模板或蓝图,可以将类比作制造手机的流水线,而对象就是一台台手机。

由类构造对象的过程被称为创建类的实例,因此,也可以把对象称作实例。

2. 什么是对象引用?

每种语言都有自己的数据处理方式,因此,必须注意将要处理的数据是什么类型。

直接操作元素?还是某种基于特殊语法的间接表示(例如 C/C++ 的指针)来操作对象。

所有这些在 Java 中都进行了简化,一切都被视为对象。因此,可以采用一种统一的语法。

尽管将一切都 “ 看作 ” 对象,但操作的标识符实际是指向一个对象的 “ 引用 ”。

​ ——《Java 编程思想》

Java 中创建的对象都被放在成为 “ 堆 ” 的系统存储区中,对象都通过 “ 对象引用 ” 来访问。

一个类的变量持有一个对象,实际上是对该对象的引用。当变量不在引用任何对象时,该对象的引用就为 “ null ”。

具体来解释一下对象的创建:

Phone phone = new Phone();

通常会认为 phone 就是 Phone 类的对象。实际上phone 是创建 Phone 类的对象的引用。

这个表述实际上执行的操作:

  1. new Phone() 是在内存中为对象开辟空间。其实也就是 new 关键字表示在内存的 堆(heap) 上为对象开辟空间,该空间保存了对象的属性和方法。
  2. Phone phonephone 指代一个 Phone 对象,被称为 对象引用实际上phone 并不是对象本身,而是一个类似执行对象的指针。phone 存在于内存的 栈(stack) 中。
  3. 当用等号赋值时,是将右侧 new Phone() 在堆中创建对象的地址赋给对象引用 phone

为什么要这样操作?简单来讲,有以下几种优点:

  1. 栈的读取速度比堆块,但栈上存储的数据受到有效范围的限制。

  2. 一个对象引用可以赋值给另一个对象引用,此时复制的实际上是对象的地址。因此,一个对象可以由多个对象引用,减少对内存的消耗。

    Phone phone1 = new Phone();
    Phone phone2;
    phone2 = phone1; // phone1 与 phone2 引用的是同一个对象,对phone1修改,phone2也会随之修改
    

3. 对象引用意味着 Java 是按引用传递?

首先回顾一下,将参数传递给方法的两种情况:

  • 按值调用:表示方法接收的是调用者提供的值。
  • 按引用调用:表示方法接收的是调用者提供的变量地址。

一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。

方法参数有两种类型:

基本数据类型:不能修改值调用所对应的变量值。

public static void add(int a, int b) {
    a = a + b; // a = 3
} 
int a = 1;
int b = 2;
add(a, b);
// a = 1

对象引用

@Getter
@Setter
@AllArgsConstructor
class Phone {
    private Double price;

    public void discount() {
        price = price * 0.7;
    }
}

Phone phone1 = new Phone(2000.00);
phone1.discount();
System.out.println(phone1.getPrice()); // 1400.00

从结果来看,似乎方法已经修改了 phoneprice,变量值已经发生了改变。

实际上,方法拿到的是 phone 对象引用的拷贝,也就是复制了一个对象地址,因此方法中对phone 属性 price 的修改,也会会作用 phone1 对象引用上。

那么,方法是否能改变对象引用的地址呢?

实际操作一下:

Phone phone1 = new Phone(2000.00);
modifyPhone(phone1);
System.out.println(phone1.getPrice()); // 2000.00

public static void modifyPhone(Phone phone) {
    phone = new Phone(1000.00);
    System.out.println(phone.getPrice()); // 1000.00
}

结果很明显,方法是不能改变对象引用的地址

换句话说,Java 程序设计语言总是按值调用。不要被 “ 对象引用 ” 这四个字迷惑了双眼,错误地认为 Java 对对象采用的是引用调用。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值