以前自己就没怎么搞清楚值传递与引用传递的内部机制,近来发现好多面试题中都考到了它,决定真正弄懂它,所以在网上查了很多资料,最后再结合自己的理解,写一篇文件来做一下总结。
这里就结合一个常见的例子来做解析,User类源码如下:
class User {
private int id;
private String name;
public User(int _id, String _name) {
id=_id;
name=_name;
}
public void setId(int $id) {
id=$id;
}
public void setName(String $name) {
name=$name;
}
public int getId() {
return id;
}
public String getName() {
return name;
}
public String toString() {
return id+" - "+name;
}
}
再写一个测试类UserTest:
public class UserTest {
public static void main( String[] args) {
UserTest test=new UserTest();
int n=2;
User u1=new User(20,"Boy");
User u2=new User(21,"Girl");
test. changeId (n);
System.out.println ( "n is " + n);
test.changeName(u1);
test.changeIdName(u2);
System.out.println(u1.toString());
System.out.println(u2.toString());
}
public void changeId(int i) {
i=3;
}
public void changeName( User u) {
u=new User(1,"Test");
}
public void changeIdName( User u) {
u.setId(23);
u.setName ("My Name");
}
}
为了真正弄清楚程序的执行过程,我觉得得先明白几个东西,也就是下面这张图里面的内容:
下面再来讲解程序在内存中的执行过程,首先从main函数的第一行开始,创建了一个UserTest对象,变量test指向了新new出来的UserTest对象,通过上面知道,局部变量存放在栈空间,所以执行完这句,在栈中就给test变量分配了一小块空间,同时在堆内存中也分配了一块空间用来存放new出来的UserTest对象,test指向了堆中对象,这就是所谓的引用;再往下面给一个变量赋值,同样是一个变量,在栈中分配一块空间,变量名为n,类型为int,值为2;下面创建了一个User对象,栈中给u1变量分配空间,堆中也分配一块内存给new出来的User对象,同样u1也指向了堆中new出来的User对象,这个对象中有两个成员变量id和name,但创建这个对象的时候,我们调用了这个对象的有参构造方法:
public User(int _id,String _name) {
id=_id;
name=_name;
}
那么方法是怎么执行的呢?方法里面的开参跟局部变量同等对待,在栈中分配_id和_name空间,它们的值分别是20和"Boy",然后通过赋值,就把它们的值传递给了User对象中的id和name,当这个方法构造方法调用完毕后,分配给这个方法的参数和内存全部消失,然后再给让其它人用。那么这个过程的执行流程图如下:
我觉得这个内存的分析,对我们学习程序是很有帮助的,我相信只要弄懂了内存,以后这方面再怎么样的面试题都难不到了。另外还要强调的是:
1.先要弄清程序存放在内存的哪些地方。
2.局部变量的存放位置,尤其方法里面的参数,方法执行完毕,为这个方法分配的参数和内存都将消失,把空间让给别人用。
3.新new出来的对象一定是放在堆中,如果一个对象没有了引用,也就会在适时被垃圾回收掉。
4.这个东西最好是自己动手画一画,一动手可能就全明白了。
由于程序执行是一个动态的过程,如果用语言描述清楚,需要花大量的篇幅,写了之后别人也不一定能看的懂,所以我做了一个PPT,比较全面的描述了这个程序在内存中的执行过程,不过由于本人PPT技术不咋的(呵呵),做的比较粗糙,希望大家都能看的懂。这篇文章是自己看过一些资料后的总结,自己难免会有理解疏漏的地方,希望大家不吝赐教。
- 大小: 22.9 KB
- 大小: 42.9 KB
分享到:
相关推荐
### Java中的按值传递与按引用传递详解 #### 一、引言 在Java编程语言中,关于参数传递的方式一直存在两种观点:一种认为Java仅支持按值传递,另一种则指出Java同时支持按值传递和按引用传递。实际上,这两种观点...
因此,尽管看似是引用传递,但对`String`类型的处理结果与值传递类似。 总结来说,Java中的参数传递主要有以下特点: 1. 基本数据类型按值传递,函数内部无法改变实际参数的值。 2. 引用类型看似按引用传递,实际上...
引用传递则不同,它不复制实参的值,而是传递实参的内存地址给形参。形参实际上是对实参的一个引用,因此对形参的任何修改都会直接影响到实参。在Delphi中,使用`var`关键字来声明引用参数: ```delphi procedure ...
Java编程语言中有两种参数传递方式:按值传递和按引用传递。理解这两种方式对于编写高效、无误的代码至关重要。 1. **按值传递(Pass by Value)** - Java中的基本类型(如int, double, char等)是按值传递的。这...
本文将深入探讨Java中的方法调用、值传递与引用传递,并通过字节码分析来进一步理解这些概念。 首先,我们来看方法调用。在Java中,方法是一组完成特定任务的代码块,可以通过方法名来调用执行。方法调用的基本语法...
接下来,我们详细分析Python中不可变类型和可变类型在传递值和传递引用时的行为: 1. 不可变类型: 在Python中,不可变类型包括数字(Number)、字符串(String)和元组(Tuple)等。不可变类型的对象一旦创建,它...
首先讨论函数之前,先弄清楚基本类型值与引用类型值的复制问题 一、数据类型的复制分析 内存分为栈区(stack)和堆区(heap) ,如果将内存看成一本书,栈好比是书的目录,而堆就是书的内容,基本类型可以看成内容...
值传递意味着将变量的值复制给函数参数,而引用传递则是传递变量的内存地址,使得函数可以直接访问和修改原始变量的值。 #### 值传递 当向函数传递基本类型(如`int`、`double`等)或值类型(如`struct`)的参数时...
通过上述分析,我们可以得出结论,尽管Java的参数传递方式被描述为“按值传递”,但对于对象来说,实际上传递的是对象引用的副本,从而实现了类似按引用传递的效果。理解这一机制对于编写Java程序至关重要,尤其是在...
在探讨Python函数传递参数的方式时,很多人会陷入“值传递”与“引用传递”的概念之中。实际上,这两种说法在Python中并不完全适用,因为Python有自己的特殊机制来处理参数传递。本文将通过具体的代码示例和内存地址...
然而,JavaScript的实现其实更为复杂,它包含了值传递和引用传递的特性,但并不完全等同于这两种方式。 首先,我们来看基础类型的参数传递。例如,对于一个数字`num`: ```javascript function add(num) { num +=...
4. **长时间持有相机引用**:在某些情况下,开发者可能会长时间保持对相机的引用,比如在多个页面之间传递相机实例。这会导致相机资源无法释放,直到应用完全关闭。 解决这些问题的方法包括: 1. **使用Using语句*...
按引用传递的重要特点是:传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。例如: ```java public class TempTest { private void test1(A a){ a.age = 20; System.out....
- 当传递引用类型时,尽管仍然遵循按值传递的原则,但由于传递的是引用的值,因此对引用所指向的对象所做的任何修改都会影响原始对象。 - 在处理不可变类型(如 `String`)时,需要注意即使是引用类型,由于不可变性...
本文将通过示例代码详细介绍Java中值传递和引用传递的区别,并对其进行深入分析。 一、值传递 值传递是一种常见的参数传递机制,在这种机制中,实参传递给形参的是值。形参和实参在内存上是两个独立的变量,对形参...
Java中的参数传递方式有两种基本类型:按值传递和引用传递,但实际上Java只支持按值传递。这意味着在Java中,无论是基本数据类型还是引用数据类型,传递的都是值的一个拷贝。 对于基本数据类型(如int、char、float...
2. 引用传递:与值传递不同,引用传递是将变量的内存地址传给方法,方法可以访问并修改原始变量的内容。在C#中,对象实例是通过引用传递的,因为它们的值实际上是内存中的地址。 在WinForm应用中,可能会有以下场景...