转载 值传递和引用传递

本文通过示例详细解释了值传递与引用传递的概念,包括它们如何在方法调用中工作,以及如何影响实际参数的值。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

值传递:方法调用时,实际参数把它的值传递给对应的形式参数,方法执行中形式参数值的改变不影响实际参 数的值。
引用传递:也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,在方法执行中,对形式参数的操作实际上就是对实际参数的操作,方法执行中形式参数值的改变将会影响实际参数的值。
下面举例说明:
传值---传递基本数据类型参数
public class PassValue{
static void exchange(int a, int b){//静态方法,交换a,b的值
int temp;
temp = a;
a = b;
b = temp;
}
public static void main(String[] args){
int i = 10;
int j = 100;
System.out.println("before call: " + "i=" + i + "\t" + "j = " + j);//调用前
exchange(i, j); //值传递,main方法只能调用静态方法
System.out.println("after call: " + "i=" + i + "\t" + "j = " + j);//调用后
}
}
运行结果:
before call: i = 10 j = 100
after call: i = 10 j = 100
说明:调用exchange(i, j)时,实际参数i,j分别把值传递给相应的形式参数a,b,在执行方法exchange()时,形式参数a,b的值的改变不影响实际参数i和j的值,i和j的值在调用前后并没改变。
引用传递---对象作为参数
如果在方法中把对象(或数组)作为参数,方法调用时,参数传递的是对象的引用(地址),即在方法调用时,实际参数把对对象的引用(地址)传递给形式参数。这是实际参数与形式参数指向同一个地址,即同一个对象(数组),方法执行时,对形式参数的改变实际上就是对实际参数的改变,这个结果在调用结束后被保留了下来。
class Book{
String name;
private folat price;
Book(String n, float ){ //构造方法
name = n;
price = p;
}
static void change(Book a_book, String n, float p){ //静态方法,对象作为参数
a_book.name = n;
a_book.price = p;
}
public void output(){ //实例方法,输出对象信息
System.out.println("name: " + name + "\t" + "price: " + price);
}
}
public class PassAddr{
public static void main(String [] args){
Book b = new Book("java2", 32.5f);
System.out.print("before call:\t"); //调用前
b.output();
b.change(b, "c++", 45.5f); //引用传递,传递对象b的引用,修改对象b的值
System.out.print("after call:\t"); //调用后
b.output();
}
}
运行结果:
before call: name:java2 price:32.5
after call: name:c++ price:45.5
说明:调用change(b,"c++",45.5f)时,对象b作为实际参数,把引用传递给相应的形式参数a_book,实际上a_book也指向同一个对象,即该对象有两个引用名:b和a_book。在执行方法change()时,对形式参数a_book操作就是对实际参数b的操作。
在 Java 的学习与开发过程中,总有一些概念容易让人混淆,从而在编程时出现各种问题。今天,我们就来深入剖析几对极易混淆的概念,通过代码示例与图示,帮助大家彻底理清它们之间的区别与联系。 目录 一、线程与进程 1.1 概念 1.2 区别 1.3 代码示例 二、值传递引用传递 2.1 概念 2.2 区别 三、接口与抽象类 3.1 概念 3.2 区别 3.3 代码示例 总结 一、线程与进程 1.1 概念 进程:是计算机中已运行的程序的实体,是系统进行资源分配调度的基本单位。每个进程都有自己独立的内存空间、系统资源等,进程之间相互隔离,安全性高。例如,当我们同时打开浏览器、音乐播放器文档编辑器时,它们分别对应一个进程,彼此互不干扰。 线程:是进程中的一个执行单元,是程序执行的最小单位。一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间、文件句柄等。线程之间的切换通信开销相对较小,能提高程序的执行效率。 1.2 区别 我们可以通过一张表格直观地看出线程与进程的区别: 对比项 进程 线程 资源分配 独立分配资源,有独立内存空间 共享进程资源 执行开销 创建、撤销、切换开销大 创建、撤销、切换开销小 并发性能 进程间并发,开销大 线程间并发,开销小 安全性 进程间相互隔离,安全性高 共享资源,需考虑同步问题 1.3 代码示例 下面是一个简单的 Java 多线程示例,通过创建线程类并启动线程,展示线程的使用: class MyThread extends Thread { @Override public void run() { for (int i = 0; i < 5; i++) { System.out.println(Thread.currentThread().getName() + " 正在执行:" + i); } } } public class ThreadAndProcess { public static void main(String[] args) { MyThread thread1 = new MyThread(); MyThread thread2 = new MyThread(); thread1.start(); thread2.start(); } } AI写代码 java 运行 在上述代码中,我们创建了MyThread类继承自Thread类,重写run方法定义线程执行的逻辑。在main方法中创建两个线程对象并启动,此时两个线程会并发执行run方法中的代码。 二、值传递引用传递 2.1 概念 值传递:是指在方法调用时,实际参数将其值复制一份传递形式参数,在方法内部对形式参数的修改不会影响到实际参数的值。简单来说,就是传递的是数据的副本。 引用传递:在方法调用时,实际参数将其引用(内存地址)传递形式参数,形式参数实际参数指向同一内存地址,在方法内部对形式参数的修改会直接影响到实际参数。 2.2 区别 在 Java 中,只有值传递。对于基本数据类型,传递的是值本身;对于引用数据类型,传递的是对象的引用(地址值)。虽然看起来像是引用传递,但本质上还是值传递,因为传递的是引用的副本。我们通过代码来验证: public class PassByValue { public static void changeInt(int num) { num = 100; } public static void changeArray(int[] arr) { arr[0] = 100; } public static void main(String[] args) { int num = 10; changeInt(num); System.out.println("修改后的num:" + num); int[] arr = {10}; changeArray(arr); System.out.println("修改后的arr[0]:" + arr[0]); } } AI写代码 java 运行 在上述代码中,changeInt方法接收一个基本数据类型int的参数,在方法内部修改参数值后,不会影响到main方法中num的值。而changeArray方法接收一个引用数据类型int[]的参数,在方法内部修改数组元素的值,会影响到main方法中arr数组对应元素的值。这是因为传递的是数组的引用副本,通过该引用副本依然可以访问修改原数组。 三、接口与抽象类 3.1 概念 抽象类:使用abstract关键字修饰的类,抽象类中可以包含抽象方法(只有方法声明,没有方法体)非抽象方法。抽象类不能被实例化,只能被继承,子类必须实现抽象类中的抽象方法(除非子类也是抽象类)。抽象类通常用于抽取相关类的共性,作为父类来定义一些通用的行为属性。 接口:使用interface关键字定义,接口中的方法默认是public abstract的(可以省略不写),属性默认是public static final的常量。接口不能被实例化,类通过implements关键字实现接口,一个类可以实现多个接口。接口用于定义一种规范,实现接口的类必须实现接口中定义的所有方法。 3.2 区别 同样,我们通过表格来对比接口与抽象类: 对比项 抽象类 接口 定义方式 使用abstract class定义 使用interface定义 继承 / 实现 子类通过extends继承抽象类 类通过implements实现接口 方法 可以包含抽象方法非抽象方法 只能包含抽象方法(JDK 8 后可添加默认方法静态方法) 属性 可以包含各种类型的属性 只能包含public static final常量 多继承 一个类只能继承一个抽象类 一个类可以实现多个接口 3.3 代码示例 先看抽象类的示例: abstract class Animal { protected String name; public Animal(String name) { this.name = name; } public abstract void speak(); } class Dog extends Animal { public Dog(String name) { super(name); } @Override public void speak() { System.out.println(name + " 汪汪叫"); } } AI写代码 java 运行 在上述代码中,Animal是抽象类,包含一个抽象方法speak。Dog类继承自Animal类,并实现了speak方法。 再看接口的示例: interface Flyable { void fly(); } class Bird implements Flyable { @Override public void fly() { System.out.println("鸟儿在飞翔"); } } AI写代码 java 运行 总结 这里定义了Flyable接口,包含fly抽象方法,Bird类实现了Flyable接口并实现了fly方法。 通过以上对线程与进程、值传递引用传递、接口与抽象类的深入剖析对比,我们可以更清晰地理解它们之间的区别与联系。 在学习 Java 编程过程中,理解这些基础概念至关重要。线程与进程是操作系统中的重要概念,而值传递引用传递则涉及到方法调用时参数传递的机制,对于理解 Java 中的数据传递有着重要意义。同时,接口与抽象类是面向对象编程中的重要组成部分,能够帮助我们更好地设计组织代码。 通过深入研究这些概念,结合代码示例区别对比,我们可以更好地掌握 Java 编程中的关键知识点,避免混淆错误的应用,提高编程效率质量。希望以上内容能够帮助您更好地理解运用这些概念,在 Java 学习与开发中取得更好的成果。 ———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接本声明。 原文链接:https://blog.youkuaiyun.com/2401_88952086/article/details/148977946补充说明
最新发布
06-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值