怒肝俩月,新鲜出炉史上最有趣的Java小白手册,第一版,每个 Java 初学者都应该收藏(7)

简介: 怒肝俩月,新鲜出炉史上最有趣的Java小白手册,第一版,每个 Java 初学者都应该收藏

六、Java 到底是值传递还是引用传递


将参数传递给方法有两种常见的方式,一种是“值传递”,一种是“引用传递”。C 语言本身只支持值传递,它的衍生品 C++ 既支持值传递,也支持引用传递,而 Java 只支持值传递。


01、值传递 VS 引用传递


首先,我们必须要搞清楚,到底什么是值传递,什么是引用传递,否则,讨论 Java 到底是值传递还是引用传递就显得毫无意义。


当一个参数按照值的方式在两个方法之间传递时,调用者和被调用者其实是用的两个不同的变量——被调用者中的变量(原始值)是调用者中变量的一份拷贝,对它们当中的任何一个变量修改都不会影响到另外一个变量。


而当一个参数按照引用传递的方式在两个方法之间传递时,调用者和被调用者其实用的是同一个变量,当该变量被修改时,双方都是可见的。


Java 程序员之所以容易搞混值传递和引用传递,主要是因为 Java 有两种数据类型,一种是基本类型,比如说 int,另外一种是引用类型,比如说 String。


基本类型的变量存储的都是实际的值,而引用类型的变量存储的是对象的引用——指向了对象在内存中的地址。值和引用存储在 stack(栈)中,而对象存储在 heap(堆)中。


image.png


之所以有这个区别,是因为:


栈的优势是,存取速度比堆要快,仅次于直接位于 CPU 中的寄存器。但缺点是,栈中的数据大小与生存周期必须是确定的。

堆的优势是可以动态地分配内存大小,生存周期也不必事先告诉编译器,Java 的垃圾回收器会自动收走那些不再使用的数据。但由于要在运行时动态分配内存,存取速度较慢。


02、基本类型的参数传递


众所周知,Java 有 8 种基本数据类型,分别是 int、long、byte、short、float、double 、char 和 boolean。它们的值直接存储在栈中,每当作为参数传递时,都会将原始值(实参)复制一份新的出来,给形参用。形参将会在被调用方法结束时从栈中清除。


来看下面这段代码:


public class PrimitiveTypeDemo {
    public static void main(String[] args) {
        int age = 18;
        modify(age);
        System.out.println(age);
    }
    private static void modify(int age1) {
        age1 = 30;
    }
}


1)main 方法中的 age 是基本类型,所以它的值 18 直接存储在栈中。


2)调用 modify() 方法的时候,将为实参 age 创建一个副本(形参 age1),它的值也为 18,不过是在栈中的其他位置。


3)对形参 age 的任何修改都只会影响它自身而不会影响实参。


image.png


03、引用类型的参数传递


来看一段创建引用类型变量的代码:


Writer writer = new Writer(18, "沉默王二");

1

writer 是对象吗?还是对象的引用?为了搞清楚这个问题,我们可以把上面的代码拆分为两行代码:


Writer writer;

writer = new Writer(18, "沉默王二");

1

2

假如 writer 是对象的话,就不需要通过 new 关键字创建对象了,对吧?那也就是说,writer 并不是对象,在“=”操作符执行之前,它仅仅是一个变量。那谁是对象呢?new Writer(18, "沉默王二"),它是对象,存储于堆中;然后,“=”操作符将对象的引用赋值给了 writer 变量,于是 writer 此时应该叫对象引用,它存储在栈中,保存了对象在堆中的地址。


每当引用类型作为参数传递时,都会创建一个对象引用(实参)的副本(形参),该形参保存的地址和实参一样。


来看下面这段代码:


public class ReferenceTypeDemo {
    public static void main(String[] args) {
        Writer a = new Writer(18);
        Writer b = new Writer(18);
        modify(a, b);
        System.out.println(a.getAge());
        System.out.println(b.getAge());
    }
    private static void modify(Writer a1, Writer b1) {
        a1.setAge(30);
        b1 = new Writer(18);
        b1.setAge(30);
    }
}


1)在调用 modify() 方法之前,实参 a 和 b 指向的对象是不一样的,尽管 age 都为 18。


image.png


2)在调用 modify() 方法时,实参 a 和 b 都在栈中创建了一个新的副本,分别是 a1 和 b1,但指向的对象是一致的(a 和 a1 指向对象 a,b 和 b1 指向对象 b)。


image.png


3)在 modify() 方法中,修改了形参 a1 的 age 为 30,意味着对象 a 的 age 从 18 变成了 30,而实参 a 指向的也是对象 a,所以 a 的 age 也变成了 30;形参 b1 指向了一个新的对象,随后 b1 的 age 被修改为 30。


image.png


修改 a1 的 age,意味着同时修改了 a 的 age,因为它们指向的对象是一个;修改 b1 的 age,对 b 却没有影响,因为它们指向的对象是两个。


程序输出的结果如下所示:


30

18


果然和我们的分析是吻合的。


相关文章
|
6月前
|
设计模式 安全 Java
面向对象编程的精髓:Java设计模式 - 原型模式(Prototype)完全参考手册
【4月更文挑战第7天】原型模式是OOP中的创建型设计模式,用于通过复制现有实例创建新实例,尤其适用于创建成本高或依赖其他对象的情况。它包括Prototype接口、ConcretePrototype实现和Client客户端角色。优点是性能优化、避免子类化和动态增加产品族。实现包括定义原型接口、实现具体原型和客户端调用克隆方法。最佳实践涉及确保克隆正确性、选择深拷贝或浅拷贝及考虑线程安全。但需注意克隆方法管理、性能开销和循环引用等问题。在Java中,实现Cloneable接口和覆盖clone方法可实现原型模式。
77 4
|
6月前
|
网络协议 Java Maven
Java自救手册
Java自救手册
85 2
|
6月前
|
算法 Java
「译文」Java 垃圾收集参考手册(四):Serial GC
「译文」Java 垃圾收集参考手册(四):Serial GC
|
6月前
|
算法 Java PHP
「译文」Java 垃圾收集参考手册(一):垃圾收集简介
「译文」Java 垃圾收集参考手册(一):垃圾收集简介
|
5月前
|
Java 开发者
【技术成长日记】Java 线程的自我修养:从新手到大师的生命周期修炼手册!
【6月更文挑战第19天】Java线程之旅,从新手到大师的进阶之路:始于创建线程的懵懂,理解就绪与运行状态的成长,克服同步难题的进阶,至洞悉生命周期的精通。通过实例,展示线程的创建、运行与同步,展现技能的不断提升与升华。
39 2
|
5月前
|
Java 数据安全/隐私保护
Java基础手册二(类和对象 对象创建和使用 面向对象封装性 构造方法与参数传递 this关键字 static关键字 继承 多态 方法覆盖 final关键字 访问控制权限修饰符)
Java基础手册二(类和对象 对象创建和使用 面向对象封装性 构造方法与参数传递 this关键字 static关键字 继承 多态 方法覆盖 final关键字 访问控制权限修饰符)
34 0
|
5月前
|
存储 Java
Java基础手册(标识符 关键字 字面值 变量 数据类型 字符编码 运算符 控制语句 方法及方法重载和递归 面向对象与面向过程)
Java基础手册(标识符 关键字 字面值 变量 数据类型 字符编码 运算符 控制语句 方法及方法重载和递归 面向对象与面向过程)
39 0
|
5月前
|
存储 自然语言处理 Java
Java IO流完全手册:字节流和字符流的常见应用场景分析!
【6月更文挑战第26天】Java IO流涵盖字节流和字符流,字节流用于二进制文件读写及网络通信,如图片和音频处理;字符流适用于文本文件操作,支持多语言编码,确保文本正确性。在处理数据时,根据内容类型选择合适的流至关重要。
74 0
|
6月前
|
Java 开发者
效率工具RunFlow完全手册之Java开发者篇
这篇手册面向Java开发者,介绍了如何使用QLExpress执行Java代码和进行方法验证。示例包括数学计算、读取系统环境变量及格式化输出。QLExpress提供运行时执行Java代码的功能,并支持QLExpress语法的脚本文件。
45 3
效率工具RunFlow完全手册之Java开发者篇
|
6月前
|
算法 安全 Java
「译文」Java 垃圾收集参考手册(三):GC 算法基础篇
「译文」Java 垃圾收集参考手册(三):GC 算法基础篇