JAVA中参数传递时值传递的机制分析

参数传递是什么?

在C的函数或是JAVA的方法中,向一个函数或方法内部传递一个参数,比如:

void fun( int num ){

num+=2 ;

}

int a = 3 ;

fun( a ) ;

这个a就被作为参数传入函数fun()中,作为a,然后返回或者不返回值

回到最初,函数的作用是复用,那么我们希望这个参数传递是什么样的呢?就是假如我们去掉函数的外衣,就让函数变成代码放到之前是函数的地方,那么很自然这里最后b的值会被改变,这可以说是最朴实的参数传递了,自然的样子。

但是人们又发明了另一种方式

其实我认为这是人们重新定义函数,把函数只作为一段代码的复用上升到一个工具,函数不是作为调用函数代码的一部分,而是把函数作为一个工具,一个函数只能以返回值的方式影响调用代码(这里不考虑在函数体内能跟调用代码中除了参数以外的代码沟通,因为java中泛滥了,其实java中能取到的值也是类中的而不是调用代码的)的,这样更加安全。

这种方式采用的方法是复制一个新值放到函数中去运算,就像:在调用时初始化的局部变量。我们知道局部变量的生存空间只有函数内,这样函数内部的操作就不会影响到外面。

这种方式被称为值传递。 那它是怎么实现的呢?看下面。

上面说了复制一个新值,其实这个东西很有门道。

先从硬件说起。

所有的代码在跑的时候,里边数据都是放在内存中的,包括文件啊什么的都需要从硬盘啊SD卡中取出来,放到内存中,也就是说你所有的值啊,对象啊,都在内存中。

而内存中放这些东西的地方分为两块:堆、栈

很俗套的情节:其中栈的位置小,速度快,堆的位置大,速度慢

于是很自然会有一套放东西的规划,小的数据,用的多的数据,放栈中,大的数据,用得少的数据,放堆中

具体在JAVA中是这样的:

  • JAVA中所有的数据类型有9种,8种基本类型和1种对象类型,对象类型又分为系统自建和用户自建
  • int、long、double、float、byte、boolean、char 这七种基本类型的数据是直接放在栈中
  • string基本类型和所有的对象类型的数据(这里的数据指的是实例化的对象,空的类不是数据)放在堆中,在栈中存放在堆中的指针

所以如果要说复制一个新值,对于只存在栈中和存放在在栈和堆中的数据来说,情况是不一样的。

说复制之前,要说一下创建,创建一个值的时候发生了什么?同样是分两种情况:

  1. 创建一个存放在栈中的数据

    1. 比如:int a = 3 ; 这一句其实是两步:int a ; a = 3 ;
    2. 第一步 int a 是在栈中找了并且开辟了一个放int类型的存储空间,然后把这个存储空间跟变量名a绑定起来了(我自定义绑定的机制发生在命名空间中);
    3. 第二步是把3这个值存入a绑定的存储空间中。
  2. 创建一个 指针存放在栈中,内容存放在堆中 的数据
    1. 比如:Apple myapple = new Apple() ; 这一句也是两步:Apple myapple ; myapple = new RedApple() ;
    2. 第一步是在栈中找了并且开辟了一个存储空间,因为声明不是基本类型,所以它开辟了一个指针类型的存储空间,然后把这个存储空间跟对象名myapple绑定起来了;
    3. 第二步是(这里特意用了多态的属性)先在内存的堆中开辟一个能够存放RedApple对象的空间(这个空间没有绑定命名空间),然后经过类型检查是否合法之后,把这个空间的地址存放在跟myapple绑定的指针空间中

数据在内存中的状态就像这样:

好,回到开始,那么复制一个新值到函数中运算的复制的真实情况是什么样子?

假如是这两个函数:

          

传参的过程其实是一个赋值的过程:

  • fun(a); 这句执行的时候,传参其实是执行了这么两句:int num ; num = a ;
    • 在栈中开辟了一个int类型int大小空间,并且绑定num,然后把a绑定的栈空间中的数据复制一份放到num绑定的栈空间中
  • fun(myapple)这句执行的时候也是一样:Apple apple ; apple = myapple ;
    • 在栈中开辟了一个Apple类型指针大小空间,并且绑定apple,然后把myapple绑定的栈空间的数据(是地址啊)复制衣服放到apple绑定的栈空间中

现在数据在内存中的状态就像这样:

这种在传参时,把a绑定的栈空间中的数据复制一份放到num绑定的栈空间中 的行为就叫做值传递(同样发生在=运算符赋值运算符的时候)。

不过你要注意,你也能很清晰看到,所谓值传递之后,在函数中对变量进行操作会不会影响到调用函数代码中的变量,是不一定的,需要看传的是值还是地址,也就看真实数据是放在哪里,真实数据放在堆中传递的是栈中的地址时,就能被改变。

不过其实如果传入的时地址,能不能改变也要看是什么操作。

以上面的apple.dosomesth() 为例:

  • 假如这个方法能对apple的某些值进行操作,那么调用函数的代码中的myapple的内容也会受到改变
  • 但如果是赋值,也就是JAVA中的赋值。那么,它进行的还是值传递,受改变的是在局部变量中new出新对象的栈空间的地址,可能换成了新的地址,但是原来那个地址链接的堆空间的数据不受影响,也就是调用函数的代码中的myapple的内容完全不受影响
时间: 2024-10-12 20:08:06

JAVA中参数传递时值传递的机制分析的相关文章

java中参数传递--值传递,引用传递

java中的参数传递--值传递.引用传递 参数是按值而不是按引用传递的说明 Java 应用程序有且仅有的一种参数传递机制,即按值传递. 在 Java 应用程序中永远不会传递对象,而只传递对象引用.因此是按引用传递对象.Java 应用程序按引用传递对象这一事实并不意味着 Java 应用程序按引用传递参数.参数可以是对象引用,而 Java 应用程序是按值传递对象引用的. Java 应用程序中的变量可以为以下两种类型之一:引用类型或基本类型.当作为参数传递给一个方法时,处理这两种类型的方式是相同的.两

如何理解Java中参数传递只能传值?

以前学习C#的时候,是完全在工作岗位上学习,一些底层较为深入的道理都不是很清楚.如今学习了Java,对于Java参数传递只能传值,不能传引用(指针)感到很困惑,在C#中不是常常说把某个引用传递到函数中吗?甚至C#有相当简便的ref.out参数,明明白白的传引用. 经过一番探索,得出的结论表明,Java中我不管你到底是传值还是传引用,只需要记住原生数据类型(值类型)和String作为参数传递的时候,其原本的值都不会发生改变:而引用类型在作为参数传递时,函数中对其的操作,都会反馈到引用所指向的值.

JAVA学习篇--ThreadLocal,Java中特殊的线程绑定机制

在DRP项目中,我们使用了ThreadLocal来创建Connection连接,避免了一直以参数的形式将Connection向下传递(传递connection的目的是由于jdbc事务要求确保使用同一个connection连接).那么ThreadLocal是如果做到的呢?它和同步锁的不同在哪里? 是什么: 对于ThreadLocal看英文单词我们很容易理解为一个线程的本地实现,但是它并不是一个Thread,而是threadlocalvariable(线程局部变量).也许把它命名为ThreadLoc

请注意,java中没有引用传递-----转载

1 说明:本文的适用对象为java初学者.如果有读者发现文章中有叙述不妥之处,请指正. 2 3 今天在论坛上有人提了一个关于java中调用函数时有没有引用传递的问题,可谓是吵的不可开交.有人说java只有值传递,也有人说java既有值传递也有引用传递,那么java中到底有没有引用传递呢,下面我来分析一下. 4 5 一.首先来明确一下"值传递"和"引用传递的"区别 6 7 值传递:是对所传递参数进行一次副本拷贝,对参数的修改只是对副本的修改,函数调用结束,副本丢弃,原

请注意:java中没有引用传递

说明:本文的适用对象为java初学者.如果有读者发现文章中有叙述不妥之处,请指正. 今天在论坛上有人提了一个关于java中调用函数时有没有引用传递的问题,可谓是吵的不可开交.有人说java只有值传递,也有人说java既有值传递也有引用传递,那么java中到底有没有引用传递呢,下面我来分析一下. 一.首先来明确一下"值传递"和"引用传递的"区别 值传递:是对所传递参数进行一次副本拷贝,对参数的修改只是对副本的修改,函数调用结束,副本丢弃,原来的变量不变(即实参不变)引

一道笔试题来理顺Java中的值传递和引用传递

前段时间参加了一场面试,其中有一道引用传递的题,因为当时并没有考虑清楚所以做错了. 现在来复盘一下,题目如下: private static void change(StringBuffer str11, StringBuffer str12) { str12 = str11; str11 = new StringBuffer("new world"); str12.append("new world");} public static void main(Stri

java中参数传递

总之一句话:java中只有副本传递,对于值,拷贝值,对于引用,拷贝引用(对于数组,数组名传递的都是引用). /** * java中只有副本传递,对于值,拷贝值,对于引用,拷贝引用(对于数组,数组名传递的都是引用). * @author sargeles */ public class About_Onlyvaluetransmit { /** * 测试一组:基本类型传递是按值传递,意味着当将一个参数传递给一个函数时,函数接收的是原始值的一个副本. * String因为两个原因表现出基本类型的特征

理解Java中的引用传递和值传递

关于Java传参时是引用传递还是值传递,一直是一个讨论比较多的话题,有论坛说Java中只有值传递,也有些地方说引用传递和值传递都存在,比较容易让人迷惑.关于值传递和引用传递其实需要分情况看待,今天学习和分析一下,着急可以先看最后的结论. >>基本类型和引用类型在内存中的保存 Java中数据类型分为两大类,基本类型和对象类型.相应的,变量也有两种类型:基本类型和引用类型.基本类型的变量保存原始值,即它代表的值就是数值本身:而引用类型的变量保存引用值,"引用值"指向内存空间的地

(转载)理解Java中的引用传递和值传递

关于Java传参时是引用传递还是值传递,一直是一个讨论比较多的话题,有论坛说Java中只有值传递,也有些地方说引用传递和值传递都存在,比较容易让人迷惑.关于值传递和引用传递其实需要分情况看待,今天学习和分析一下,着急可以先看最后的结论. 1.基本类型和引用类型在内存中的保存 Java中数据类型分为两大类,基本类型和对象类型.相应的,变量也有两种类型:基本类型和引用类型.基本类型的变量保存原始值,即它代表的值就是数值本身:而引用类型的变量保存引用值,"引用值"指向内存空间的地址,代表了某