精华内容
下载资源
问答
  • 深入理解--Java按值传递引用传递

    万次阅读 多人点赞 2017-07-20 15:48:49
    引言最近刷牛客网上的题目时碰到不少有关Java按值传递引用传递的问题,这种题目就是坑呀,在做错了n次之后,查找了多方资料进行总结既可以让自己在总结中得到提高,又可以让其他人少走弯路。何乐而不为?Java...

    引言

    最近刷牛客网上的题目时碰到不少有关Java按值传递和按引用传递的问题,这种题目就是坑呀,在做错了n次之后,查找了多方资料进行总结既可以让自己在总结中得到提高,又可以让其他人少走弯路。何乐而不为?

    Java按值传递和按引用传递

    首先问一句:Is Java “pass-by-reference” or “pass-by-value”? Java到底是按值传递还是按引用传递的呢?国外的网站上关于这个问题的讨论非常之多。官方答案:The Java Spec says that everything in Java is pass-by-value. There is no such thing as “pass-by-reference” in Java. 官方的说法是在java中只有按值传递,并没有所谓的按引用传递。

    基本数据类型的按值传递

    java数据类型可以分为两大类:基本类型(primitive types)和引用类型(reference types)。primitive types 包括boolean类型以及数值类型(numeric types)。numeric types又分为整型(integer types)和浮点型(floating-point type)。整型有5种:byte short int long char(char本质上是一种特殊的int)。浮点类型有float和double。关系整理一下如下图:

    这里写图片描述
    例1

    public class Swap {
    
        public static void main(String[] args) {
            int x = 10;
            int y = 20;
            swap(x, y);
            System.out.println("x(2) = " + x);
            System.out.println("y(2) = " + y);
        }
         public static void swap(int x, int y) {
            int temp = x;
            x = y;
            y = temp;
            System.out.println("x(1) = " + x);
            System.out.println("y(1) = " + y);
        }
    }
    
        /*输出
        x(1) = 20
        y(1) = 10
        x(2) = 10
        y(2) = 20
        */

    上面程序main函数调用swap函数来交换 x,y的值,然而调用函数之后发现main中x,y的值并未交换。包括在Java api中找不到一个可以交换两个变量的方法。这与Java语言的特性有关。通过一个图就可以知道上面程序的运行结果了。

    这里写图片描述
    由上图可知,main函数中的x,y和swap函数中的x,y分别存放在不同的区域,在main中调用swap函数的时候,会将main中的x,y的值赋给swap中的x,y。当swap函数中对x,y交换时只是对swap帧中的x,y做交换,并不会改变main中的x,y。所以当函数返回时main中的x,y并不会改变。swap执行过程图如下:
    这里写图片描述

    对于基本数据类型 short int long float double char byte boolean这八种按值传递调用函数并不会改变在原函数中的值。

    引用数据类型的按值传递

    引用数据数据类型分为三种:①接口 ②类 ③数组对于引用数据类型的按值传递先给出一个实例对比实例进行分析。

    例2

    public static void main(String[] args) {    
            int []a={10,20};
            System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=10,a[1]=20;      
            swap(a, 0, 1);
            System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=20,a[1]=10;  
    
        }
    public static void swap(int []a,int i,int j){
            int temp=a[i];
            a[i]=a[j];
            a[j]=temp;
            System.out.println("a[0] :"a[0]+"a[1] : "+a[1]);//a[0]=20,a[1]=10;
        }
    //输出
    /*a[0]=10 a[1]=20
    
      a[0]=20 a[1]=10
    
      a[0]=20 a[1]=10   
    */

    运行程序后发现,swap函数对a[0] ,a[1]的操作竟然影响到了main函数中的a[0] ,a[1]的值,真是不可思议。为什么会产生如此之结果。原来引用类型的按值传递,传递的是对象的地址。还是用图来解释一下。

    这里写图片描述
    由图可以看出在swap中仅仅是得到了数组的地址,并没有对数组的元素进行复制,在swap中对数组的操作是直接对main函数中数组的操作,因此swap函数返回后main函数中的a[0] ,a[1]的值发生交换。

    数组、类、接口按值传递的时候都是传递对象的地址。再来看一个比较复杂的实例。

    例3

    public class Main{
         public static void main(String[] args){
              Foo f = new Foo("f");
              changeReference(f); // It won't change the reference!
              modifyReference(f); // It will modify the object that the reference variable "f" refers to!
         }
         public static void changeReference(Foo a){
              Foo b = new Foo("b");
              a = b;
         }
         public static void modifyReference(Foo c){
              c.setAttribute("c");
         }
    }

    ①Foo f = new Foo(“f”);
    这里写图片描述

    ②public static void changeReference(Foo a)
    这里写图片描述

    ③changeReference(f);
    这里写图片描述

    ④Foo b = new Foo(“b”);
    enter image description here
    ⑤a = b
    enter image description here

    enter image description here
    ⑥c.setAttribute(“c”);

    enter image description here

    经典笔试题目

    试题1

    public class Demo {
    
        public static void main(String[] args) {
    
            //demo1
            String str=new String("hello");
            char []chs={'w','o','r','l','d'};
            change(str, chs);
            System.out.println(str+" "+new String(chs));
    
            //-------------------------------------------------
            //demo2
    
            StringBuffer sb=new StringBuffer("hello");
            change(sb);
            System.out.println(sb);
    
        }
        public static void change(StringBuffer sb)
        {
            sb.append(" world");
    //      sb.deleteCharAt(0);
        }
        public static void change(String str,char[]chs)
        {
            str.replace('h', 'H');
            chs[0]='W';     
        }       
    }

    上面程序段demo1和demo2分别输出什么,这里涉及到String特性,这道题目会做了,Java按值传递和按引用传递就彻底懂了,答案和解析先匿了。

    试题2

    public class foo {
        public static void main(String sgf[]) {
    
            StringBuffer a=new StringBuffer(“A”);
            StringBuffer b=new StringBuffer(“B”);
            operate(a,b);
            System.out.println(a+”.”+b);
    
        }
    
        static void operate(StringBuffer x,StringBuffer y) {
    
            x.append(y);
            y=x;
    
        }
    }

    参考文献

    1.https://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value

    展开全文
  • 如果数据对象小,如内置数据类型或小型结构,则按值传递; 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针; 如果数据对象是较大的结构,则使用const指针或const引用,以...
    • 值传递
        形参是实参的拷贝(会在栈内存中创建形参并拷贝实参的值),函数执行完毕后会自动清除栈内存。所以从被调用函数的角度来说,值传递是单向的,形参不能改变实参。当内部函数不需要改变实参则采用值传递。

    • 指针传递
       指针传递参数的本质是值传递,只不过它传递的是一个地址值,函数执行的时候在栈中创建并拷贝实参的地址值。函数可以根据地址,找到地址指向的内存单元。因而可以改变主函数实参指向的变量的值。
      如果要数据对象是数组,则只能使用指针。因为值传递不能直接数组,引用的对象也不能是数组。

    • 引用传递
        &表示引用实参,即代表形参是实参的一个别名。操作引用变量就是操作实参变量。这是C++语法写法,标准C是不支持这种写法的。

      在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。

    • 引用和指针的区别:
      指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名,引用初始化后不能改变指向(引用必须在创建的时候初始化)。使用时,引用更加安全,指针更加灵活。但是就效率和占用内存的来说,指针和应用是差不多的。

    使用背景

    • 对于使用传递的值二不作修改的函数
    1. 如果数据对象小,如内置数据类型或小型结构,则按值传递;
    2. 如果数据对象是数组,则使用指针,因为这是唯一的选择,并将指针声明为指向const的指针;
    3. 如果数据对象是较大的结构,则使用const指针或const引用,以提高程序的效率。这样可以节省复制结构所需的时间和空间。
    4. 如果数据对象是类对象,则使用const引用。类设计的语义常常要求使用引用,这是c++新增这项特性的主要原因。因此,传递类对象参数的标准方式是按引用传递。
    • 对于修改调用函数中数据的函数
    1. 如果数据对象是数组,则只能使用指针。
    2. 如果数据兑现是结构,则使用指针或应用。
    3. 数据对象是类对象,则使用引用。
    展开全文
  • JAVA参数传递方式 (按值传递与引用传递区别)

    千次阅读 多人点赞 2018-09-30 22:58:30
    首先要明确的是JAVA中没有引用传递, 全部是按值调用 令大家所费解的 当对象引用作为参数时 函数为什么能修改真实的对象呢?这不是引用传递的特征吗? 尤其先学习C++再学习JAVA的同学(比如说我自己)会这样认为, 用...

    首先要明确的是JAVA中没有引用传递, 全部是按值调用

    令大家所费解的 当对象引用作为参数时  函数为什么能修改真实的对象呢?这不是引用传递的特征吗?

    尤其先学习C++再学习JAVA的同学(比如说我自己)会这样认为,

    用白话解释就是:

    引用传递指针时, 连函数操作的指针都是原来的指针,比如C++传入对象时直接用传入的指针操作

    而JAVA的引用传进函数时 , 会复制一个引用与实参指向同一对象的引用, 操作的不是同一个引用,

    如果还不明白区别再换种方式解释一次:

    JAVA只有按值调用, 参数是什么都会复制一份再操作, 就算是对象的引用也会复制一份新的引用,只不过指向的是同一个对象

    这种传参方式叫做按值传递, 传递的东西可以是引用(类似C++的指针)

    如果是引用传递像C++传入指针不会再复制一份了,直接拿来用

     

    如果再不明白也没关系,看看下面的例子和解释分析

    举个例子:

    输出结果:

    也就说我们用一个函数修改了 传入的一个int变量和一个对象内容,

    再输出int变量和对象内容时发现 ,int的没有改变,而 对象的内容改变了

     

    这说明什么呢,说明像 int ,double等基本数据类型在参数传递时并没有传进变量本身,

    而是创建了一个新的相同数值的变量, 函数修改这个新变量并没有影响原来变量的数值,这也是按值传递的特点

    那为什么对象a的数据就改变了呢?

    因为虽然也是按值传递, 复制了一份新的引用但是指向的对象是同一个,修改后会影响原对象

    这种方式假如在函数内修改 a=null; 只是把复制的引用与对象的联系断开,不影响函数外与实际对象

     

    这就是按值传递, 即使传的是引用也不是引用传递,

    因为引用传递是不复制的,直接使用参数,如下图:

    这时候函数把指针a=null就指针就置空了,函数外也无法再通过指针访问对象了

    这样可以理解了吗,自我觉得足够明白了, 我如此深厚的画图功底都供出来了,再不明白就是在为难我胖虎!

    水平有限, 可能有错误,敬请指出! 

    展开全文
  • 按值传递引用传递详细解说

    千次阅读 2018-05-21 20:59:03
    1:按值传递是什么指的是在方法调用时,传递的参数是值的拷贝传递。示例如下:public class TempTest { private void test1(int a){ //做点事情 } public static void main(String[] args) { TempTest t = ...

    1:按值传递是什么

    指的是在方法调用时,传递的参数是按值的拷贝传递。示例如下:

    public class TempTest {  
    private void test1(int a){  
    //做点事情  
    }  
    public static void main(String[] args) {  
    TempTest t = new TempTest();  
    int a = 3;  
    t.test1(a);//这里传递的参数a就是按值传递  
    }  
    }  

    按值传递重要特点:传递的是值的拷贝,也就是说传递后就互不相关了。

    示例如下:

    public class TempTest {  
    private void test1(int a){  
    a = 5;  
    System.out.println("test1方法中的a="+a);  
    }  
    public static void main(String[] args) {  
    TempTest t = new TempTest();  
    int a = 3;  
    t.test1(a);//传递后,test1方法对变量值的改变不影响这里的a  
    System.out.println(”main方法中的a=”+a);  
    }  
    } 

    运行结果是:

    test1方法中的a=5  
    main方法中的a=3 

    2:按引用传递是什么

    指的是在方法调用时,传递的参数是按引用进行传递,其实传递的引用的地址,也就是变量所对应的内存空间的地址。

    示例如下:

    public class TempTest {  
    private void test1(A a){  
    }  
    public static void main(String[] args) {  
    TempTest t = new TempTest();  
    A a = new A();  
    t.test1(a); //这里传递的参数a就是按引用传递  
    }  
    }  
    class A{  
    public int age = 0;  
    }  

    3:按引用传递的重要特点

    传递的是值的引用,也就是说传递前和传递后都指向同一个引用(也就是同一个内存空间)。

    示例如下:

    public class TempTest {  
    private void test1(A a){  
    a.age = 20;  
    System.out.println("test1方法中的age="+a.age);  
    }  
    public static void main(String[] args) {  
    TempTest t = new TempTest();  
    A a = new A();  
    a.age = 10;  
    t.test1(a);  
    System.out.println(”main方法中的age=”+a.age);  
    }  
    }  
    class A{  
    public int age = 0;  
    }  

    运行结果如下:

    test1方法中的age=20  
    main方法中的age=20 

    4:理解按引用传递的过程——内存分配示意图

    要想正确理解按引用传递的过程,就必须学会理解内存分配的过程,内存分配示意图可以辅助我们去理解这个过程。

    用上面的例子来进行分析:

    (1):运行开始,运行第8行,创建了一个A的实例,内存分配示意如下:



    (2):运行第9行,是修改A实例里面的age的值,运行后内存分配示意如下:


    (3):运行第10行,是把main方法中的变量a所引用的内存空间地址,按引用传递给test1方法中的a变量。请注意:这两个a变量是完全不同的,不要被名称相同所蒙蔽。

    内存分配示意如下:


    由于是按引用传递,也就是传递的是内存空间的地址,所以传递完成后形成的新的内存示意图如下:


    也就是说:是两个变量都指向同一个空间。

    (4):运行第3行,为test1方法中的变量a指向的A实例的age进行赋值,完成后形成的新的内存示意图如下:


    此时A实例的age值的变化是由test1方法引起的

    (5):运行第4行,根据此时的内存示意图,输出test1方法中的age=20

    (6):运行第11行,根据此时的内存示意图,输出main方法中的age=20

    5:对上述例子的改变

    理解了上面的例子,可能有人会问,那么能不能让按照引用传递的值,相互不影响呢?就是test1方法里面的修改不影响到main方法里面呢?

    方法是在test1方法里面新new一个实例就可以了。改变成下面的例子,其中第3行为新加的:

     public class TempTest {  
     private void test1(A a){  
     a = new A();//新加的一行  
     a.age = 20;  
     System.out.println("test1方法中的age="+a.age);  
     }  
     public static void main(String[] args) {  
     TempTest t = new TempTest();  
     A a = new A();  
     a.age = 10;  
     t.test1(a);  
     System.out.println(”main方法中的age=”+a.age);  
     }  
    }  
    class A{  
     public int age = 0;  
    } 

    运行结果为:

    test1方法中的age=20  
    main方法中的age=10

    为什么这次的运行结果和前面的例子不一样呢,还是使用内存示意图来理解一下

    6:再次理解按引用传递

    (1):运行开始,运行第9行,创建了一个A的实例,内存分配示意如下:

    (2):运行第10行,是修改A实例里面的age的值,运行后内存分配示意如下:

    (3):运行第11行,是把main方法中的变量a所引用的内存空间地址,按引用传递给test1方法中的a变量。请注意:这两个a变量是完全不同的,不要被名称相同所蒙蔽。

    内存分配示意如下:

    由于是按引用传递,也就是传递的是内存空间的地址,所以传递完成后形成的新的内存示意图如下:


    也就是说:是两个变量都指向同一个空间。

    (4):运行第3行,为test1方法中的变量a重新生成了新的A实例的,完成后形成的新的内存示意图如下:

    (5):运行第4行,为test1方法中的变量a指向的新的A实例的age进行赋值,完成后形成的新的内存示意图如下:

    注意:这个时候test1方法中的变量a的age被改变,而main方法中的是没有改变的。

    (6):运行第5行,根据此时的内存示意图,输出test1方法中的age=20

    (7):运行第12行,根据此时的内存示意图,输出main方法中的age=10

    7:说明

    (1):“在Java里面参数传递都是按值传递”这句话的意思是:按值传递是传递的值的拷贝,按引用传递其实传递的是引用的地址值,所以统称按值传递。

    (2):在Java里面只有基本类型和按照下面这种定义方式的String是按值传递,其它的都是按引用传递。就是直接使用双引号定义字符串方式:String str = “Java私塾”;

    展开全文
  • 引言:过程调用参数传递有两种方法,一是地址传递,二是按值传递,下面通过反汇编来比较两种方法的区别。 #include<stdio.h>//地址传递参数 main() { int a=15,b=22; printf(&...
  • C/C++按值传递地址传递

    万次阅读 多人点赞 2018-04-06 19:41:11
    C/C++的按值传递地址传递有明显不同,下面对他们作个区别:按值传递:在调用函数中将原函数的值拷贝一份过去被调用的函数,在被调用函数中对该值的修改不会影响原函数的值。地址传递:在调用函数的时候将原...
  • C# 按值传递引用传递

    千次阅读 2018-08-03 16:02:31
    1,按值传递按值传递,引用类型按值传递的实质的是传递值,参数为值类型时,“值”为实例本身,因此传递的是实例拷贝,不会对原来的实例产生影响;参数为引用类型时,“值”为对象引用,因此传递的是引用地址拷贝...
  • 形参与实参: 如果把函数比喻成一台机器,那么参数就是...在函数定义中出现的参数可以看做是一个占位符,它没有数据,只能等到函数被调用时接收传递进来的数据,所以称为形式参数,简称形参。 实参(实际参数) ...
  • Python函数参数:按值传递引用传递

    千次阅读 多人点赞 2019-04-15 09:54:04
    首先简单说明一下,Python中按值传递引用传递的区别: 值参数传递是指一个变量的值来取代一个函数参数的做法。 如果这个值在函数代码组中改变,对于调用这个函数的代码来说,其中相应的变量值并不会受到任何...
  • 举个栗子,分析一下C++按值传递、引用传递和指针传递的区别: #include "transmit.h" #include <iostream> using namespace std; //值传参 void changeValue(int x) { x = x + 5; cout << "地址...
  • 测试数组作为参数传递给函数,在函数中访问和修改。并且,这表明C语言的数组作为参数传递给函数时,是作为引用方式传递的。 还有,在传递的时候,还需要把数组的大小也一并传递给函数。因为只传递数组给函数,进而想...
  • 本篇文章主要讲的是JavaScript中最正常不过的现象——函数参数传递,本篇文章篇幅不长,但一定能引发属于你自己的思考!
  • C/C++ 按值传递对象和址传递对象

    千次阅读 2017-03-19 23:02:59
    按值传递对象:在传递时候,会建立一个该对象的拷贝(调用复制构造函数);而从函数返回一个对象是,也要建立这个被返回的对象的一个拷贝。这样带来的内存开销非常大。 在传递的过程中会默认调用复制构造函数,...
  • JS是按值传递还是引用传递?

    千次阅读 2016-12-11 23:05:01
    原始数据类型 primitive type,比如Undefined,Null,Boolean,Number,String。引用类型,也就是对象类型 Object type,比如Object,Array,Function,Date等。 声明变量时不同的内存分配 原始:存储在栈(stack...
  • 以js为例解释按值传递引用传递

    千次阅读 2018-02-01 23:27:42
    首先“ EMCAJavaScrip里面所有函数的参数传递都是按值传递” 这句话是公认的,没错的。 按值传递的意思就是形参是实参的复制。 引用传递是 函数的形参接收实参的隐式引用,而不再是副本。这意味着函数形参的值...
  • 当我们声明一个变量并给它赋值时,可以赋给其简单和复杂(以下堆内存和栈内存的地址表示均随意取的,只是为了区分,并不是真实的内存地址); 针对简单数据类型: 例1 var simpleData1 = 18 var simpleData2 =...
  • JAVA 方法的参数是按值传递还是引用传递?
  • 这种说法是把引用的副本也看作了一种“值”,也能够说的过去,但是本人还是更赞成将按值传递引用传递分开比较好理解。引自----http://smile2015.blog.51cto.com/9250194/1629685/ 文章结尾解释string引用传递...
  • 《JavaScript高级程序设计(第3版)》中P70页关于传递参数一上来就各种强调开发人员会错误的认为参数是引用传递,前后看了几遍,甚是迷惑,被几个概念绕得晕乎,说的是玄之又玄,于是花了一下午准备把这个点的所有...
  • 在调用自定义函数时经常会遇到给被调用函数传递参数。注意参数和变元的区别,eg:声明一个函数如下:int fun(int a,int *pnumber),其中的a和pnumber就是参数。 int main(void) { int b,c; b= fun(int c...
  • java中按值传递和引用传递区别

    万次阅读 2017-02-08 12:54:03
    java中在参数传递时有2种方式, ...有些文章中写的是java中所有的传参方式都是按值传递,这也说得通,无非就是文字游戏,因为无论是按值传递还是引用传递都是把值传递过去了,所以就叫按值传递
  • c++关于函数的按值传递址传递

    千次阅读 2016-06-04 15:20:32
    按值传递只是将实参的值传递给形参变量,参与运算,因为是在不同的存储单元,所以实参值不会受影响。  值传递按值传递)  址传递(引用传递)使用别名,共享存储空间(直接访问) 形参为引用参数时,才为址...
  • 在c++中,一般有两种传递方式:一种是引用按值传递,另一种是引用传值,其我们经常在java中写一些方法调用,当传递基本类型时,都是指传递,在传递对象时,都是引用类型传递。 那么这两种的方式,我举个例子...
  • 在函数中的参数是如何传递的:是传值?还是传引用?当然,结果我们是知道的,肯定是传引用的。 现在,我们来测一下我们的结论: ===== 修改list,Code: # 添加了一个string类型的元素添加到末尾 def ChangeList...
  • 按值传递地址传递

    千次阅读 2014-03-28 16:35:13
    数据传递方式有两种方式:按值传递地址传递。 1. 按值传递参数  按值传递参数时,是将实在参数的值复制一个形式参数中,如果在调用过程中改变了形式参数的值,不会影响实在参数本身,即实在参数保持调用前的...
  • Java:按值传递还是引用传递详细解说

    万次阅读 多人点赞 2012-11-14 23:02:12
    前天在做系统的时候被Java中参数传递问题卡了一下,回头查阅了相关的资料,对参数传递问题有了新的了解和掌握,但是有个问题感觉还是很模糊,就是Java中到底是否只存在值传递,因为在查阅资料时,经常看到有人说Java...
  • 对Java方法参数按值传递的理解

    千次阅读 2017-02-28 22:37:40
    今天看到(Java核心计数)Java方法对参数按值传递的时候,居然怎么都想不通,故而自己写代码尝试了理解了一下: 定义一个Person类: class Person { private double m_dAge; public Person(double age) { m_dAge...
  • java方法参数传递方式--按值传递、引用传递

    万次阅读 多人点赞 2017-12-25 21:33:28
    java的方法参数传递方式有两种,按值传递和引用传递 1.按值传递
  • js参数按值传递

    千次阅读 多人点赞 2020-07-19 14:48:11
    什么是按值传递呢? 也就是说,把函数外部的值复制给函数内部的参数,就和把值从一个变量复制到另一个变量一样。 1. 按值传递 举个简单的例子: var value = 1; function foo(v) { v = 2; console.log(v); //2 } foo...
  • 缺省的情况下C++是按值传递的,这可能付出昂贵的代价(费时)。 看看下面的代码吧:class Person { public: Person(); virtual ~Person(); ... private: std::string name; std::string adddress; }; clas

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,841,947
精华内容 736,778
关键字:

按值传递