精华内容
下载资源
问答
  • Java方法的参数传递

    2018-09-02 19:55:38
    对于程序设计语言来说,一般方法(函数)的参数传递有两种:按值传递和按引用传递。  按值传递意味着当将一个参数传递给一个方法时,方法接收的是原始值的一个副本。因此,如果方法修改了该参数,仅改变副本,而...

    参数传递机制

    对于程序设计语言来说,一般方法(函数)的参数传递有两种:按值传递和按引用传递。 

    按值传递意味着当将一个参数传递给一个方法时,方法接收的是原始值的一个副本。因此,如果方法修改了该参数,仅改变副本,而原始值保持不变。按引用传递意味着当将一个参数传递给一个方法时,方法接收的是原始值的内存地址,而不是值的副本。因此,如果方法修改了该参数,调用代码中的原始值也随之改变。

    需要注意的是,方法可以修改按引用传递的参数对应的变量值,但不可以修改按值传递的参数对应的变量值,这是两者的最大区别。

     

    Java中的参数传递

    Java中的参数传递机制只有一种,就是值传递。在Java中并没有C++的引用传递这种参数传递机制,它所有的参数传递都遵循值传递的机制。

    Java中对于对象(数组,类,接口)的传递似乎有点像引用传递,可以改变对象中某个属性的值。但是不要被这个假象所蒙蔽,实际上这个传入方法的值是对象引用的拷贝,即传递的是引用的地址值,所以还是按值传递。

     

    基本类型的参数传递

    在方法调用时,传递的参数是按值的拷贝传递;

    public class Test {
        public static void main(String[] args) {
            Test t = new Test();
            int a = 5;
            t.method(a); // 传递后,method方法对变量值的改变不影响这里的a
            System.out.println("method调用完后的a: " + a);
        }
        private void method(int a){
            System.out.println("method中重新赋值之前的a: " + a);
            a = 10;
            System.out.println("method中重新赋值之后的a: " + a);
        } 
    }

    执行结果如下:

    method中重新赋值之前的a: 5
    method中重新赋值之后的a: 10
    method调用完后的a: 5

    由此可知按值传递重要特点:传递的是值的拷贝,也就是说传递后就互不相关了。下面看一下内存分析:

     

    引用类型的参数传递

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

    public class Test {
        public static void main(String[] args) {
            Person person = new Person();
            person.age = 18;
            // 把main方法中的变量person所引用的内存空间地址,按引用传递给method方法中的person变量
            // 请注意:这两个person变量是完全不同的,不要被名称相同所蒙蔽
            method(person);
            System.out.println("调用method方法之后:" + person.age);
        }
        public static void method(Person person){
            person.age = 20;
            System.out.println("method方法内第一次修改:" + person.age);
            person = new Person(); // 新创建一个对象
            person.age = 25;
            System.out.println("method方法内第二次修改:" + person.age);
        }
    }
    class Person {
        public int age;
    }
    

    执行结果如下:

    method方法内第一次修改:20
    method方法内第二次修改:25
    调用method方法之后:20

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

    下面我们接着看一个例子:

    public class Test {
        public static void main(String[] args) {
            int[] a = {5, 10};
            method(a);
            System.out.println("调用完method方法之后:" + a[0]);
        }
        public static void method(int[] a){
            System.out.println("method内修改a[0]之前:" + a[0]);
            a[0] = 50;
            System.out.println("method内修改a[0]之后:" + a[0]);
        }
    }

    执行结果如下:

    method内修改a[0]之前:5
    method内修改a[0]之后:50
    调用完method方法之后:50

    根据结果可知,调用method方法时实际传递的是引用的地址值。

     

    传递String类型的参数

    由于String类是final修饰的,不可变,它会在内存中在开辟一块新空间。

    public class Test {
        public static void main(String[] args) {
            String str1 = new String("test1");
            String str2 = "test2";
            method(str1, str2);
            System.out.println("调用method传参str1之后:" + str1 + ", " + str2);
        }
        public static void method(String str1, String str2){
            System.out.println("method内修改str之前:" + str1 + ", " + str2);
            str1 = "new1";
            str2 = "new2";
            System.out.println("method内修改str之后:" + str1 + ", " + str2);
        }
    }

    执行结果如下:

    method内修改str之前:test1, test2
    method内修改str之后:new1, new2
    调用method传参str1之后:test1, test2

     

    总结:

    1)基本数据类型传递的是值的复制,对一个参数的修改不会影响另一个参数;

    2)引用类型传引用,形参和实参指向同一个内存地址(同一个对象),所以对参数的修改会影响到实际的对象;

    3)String、Integer、Double等immutable的类型特殊处理,可以理解为传值,最后的操作不会修改实参对象(与基本数据类型一致)。

     

     

     

    展开全文
  • 主要介绍了Java方法的参数传递机制,结合实例形式详细分析了java方法参数传递机制原理、实现方法及操作注意事项,需要的朋友可以参考下
  • 探究Java方法的参数传递是值传递还是引用传递

    测试思路

    每个更改形参的方法,返回值都是void,不同方法的参数设置不同类型。

    注意在方法内测地址的时候在改之前测一下,才能看出传入参数是不是传了地址。(注意反正OS的内存地址是虚拟的,JVM中的也是,掰扯不清的,所以就姑且按照JVM中的虚拟地址来考虑吧)

    数组参数传递

    private static void changeArray(int[] array) {
        Arrays.fill(array, 2);
    }
    

    数组的值改变了,但地址没变,是引用传递。

    基本类型及其包装类的参数传递

    private static void changeInt(int data) {
        data = 3;
    }
    
    private static void changeInteger(Integer data) {
        data = 3;
    }
    

    无论是int还是Integer,没有返回值,所以外面的实参值没变。

    对于基本类型,打印地址也能看出地址改了,是值传递。
    对于包装类型,打印地址能看出地址没改,是引用传递。

    由于hashCode()被重写了,所以可以用System.out.println(System.identityHashCode(data));来看虚拟地址(当然不是真的地址啦)。

    普通类参数传递

    private static class Person {
        int id;
        String name;
        int age;
        Person(int id, String name, int age) {
            this.id = id;
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';
        }
    }
    
    private static void changePerson(Person data) {
        data = new Person(101, "Bob", 15);
    }
    

    是引用类型,也是引用传递。打印地址测试过,确实在new之前的虚拟地址与传入实参的虚拟地址一致。(想测地址就把@Override的toString()注释掉,再打印对象啊)

    只改属性

    private static void changePersonAttributes(Person data) {
        data.id = 101;
        data.name = "Bob";
        data.age = 15;
    }
    

    改了属性,打印结果改了,但是实际地址没改,说明是引用传递。

    完整代码

    部分打印地址的测试内容就删掉不附上了,感兴趣可以自测。

    import java.util.Arrays;
    
    public class ReferenceTest {
        private static void changeArray(int[] array) {
            Arrays.fill(array, 2);
        }
    
        private static void changeInt(int data) {
            data = 144;
        }
    
        private static void changeInteger(Integer data) {
            data = 155;
        }
    
        private static class Person {
            int id;
            String name;
            int age;
            Person(int id, String name, int age) {
                this.id = id;
                this.name = name;
                this.age = age;
            }
            @Override
            public String toString() {
                return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}';
            }
        }
    
        private static void changePerson(Person data) {
            data = new Person(101, "Bob", 15);
        }
    
        private static void changePersonAttributes(Person data) {
            data.id = 101;
            data.name = "Bob";
            data.age = 15;
        }
    
        public static void main(String[] args) {
            int[] array = new int[5];
            System.out.println(Arrays.toString(array));
            changeArray(array);
            System.out.println(Arrays.toString(array));
            Integer a = 133;
            changeInteger(a);
            System.out.println(a);
            changeInt(a);
            System.out.println(a);
            Person p = new Person(100, "Sam", 10);
            System.out.println(p);
            changePerson(p);
            System.out.println(p);
            changePersonAttributes(p);
            System.out.println(p);
        }
    }
    

    测试结果

    [0, 0, 0, 0, 0]
    [2, 2, 2, 2, 2]
    133
    133
    Person{id=100, name='Sam', age=10}
    Person{id=100, name='Sam', age=10}
    Person{id=101, name='Bob', age=15}
    

    总结反思

    其实自己也一直没搞明白Java的参数传递到底是值传递还是引用传递,网上说法众说纷纭,于是下定决心自己认真测一下。

    按照JVM的虚拟地址来做测试,在整数测试的时候还考虑了整数缓存池,选了127以上的数。

    个人认为,其实不能单纯利用返回值为void的函数运行后查看原值来判断是值传递还是引用传递。我选择在传完参数后的函数内测地址,地址一样就是引用传递,不一样就是值传递。
    hashCode()一般包含了地址,但Integer的hashCode()则只是原值,得使用System.identityHashCode(data)来测。

    emmm,接下来,讲讲结论orz

    总结

    • 基本类型是值传递
    • 引用类型是引用传递,返回值为void的话未必能在外面看到改变。
      • 引用类型对象重新被new了以后,看不到改变;但改变属性能看到改变。
      • 数组也是引用类型,数组元素值的改变能在void方法外面测出来。

    其实研究这个问题Real迷惑,如有不足还请指正!


    Update on 2020.3.7
    强调String这个问题,如果你简单地测试得到地址没变,这是不对的,涉及到String常量池等等……
    因为我还不太会,所以回头再来补充orz

    看来这篇文章可能有些我思虑不周(尚未涉猎)的地方啊,果然水深莫涉啊orz

    展开全文
  • Java方法的参数传递机制 java中方法的参数传递方式只有一种:值传递。就是将实际参数的副本(复制品)传入方法中,其本身不会受到影响。 1、普通变量的传递 public class t { public static void swap(int a,int b)...

    Java方法的参数传递机制

    java中方法的参数传递方式只有一种:值传递。就是将实际参数的副本(复制品)传入方法中,其本身不会受到影响。

    1、普通变量的传递

    public class t {
    	public static void swap(int a,int b) {
    		int temp=a;
    		a=b;
    		b=temp;
    		System.out.println("swap()方法中a的值为:"+a+",b值为:"+b);
    	}
    	public static void main(String[] args) {
    		int a=1;
    		int b=2;
    		swap(a,b);  //传入的是值,即1,2,而不a,b本身
    		System.out.println("交换后的a值为:"+a+",b值为:"+b);
    	}
    }
    

    输出结果:swap()方法中a的值为:2,b值为:1
    交换后的a值为:1,b值为:2

    在这里插入图片描述

    只是将a,b的副本传入swap方法中,而main方法中的a,b本身并不改变。

    2、引用类型的参数传递

    class Date{
    	int a;
    	int b;
    }
    public class t {
    	public static void swap(Date dt) {
    		int temp=dt.a;
    		dt.a=dt.b;
    		dt.b=temp;
    		System.out.println("swap()方法中,a成员变量的值为:"+dt.a+",b成员变量的值为:"+dt.b);
    	}
    	public static void main(String[] args) {
    		Date dt=new Date();
    		dt.a=1;
    		dt.b=2;
    		swap(dt);
    		System.out.println("交换后,a成员变量的值为:"+dt.a+",b成员变量的值为:"+dt.b);
    	}
    }
    

    输出结果:swap()方法中,a成员变量的值为:2,b成员变量的值为:1
    交换后,a成员变量的值为:2,b成员变量的值为:1

    此时发现,swap方法和main方法中的输出结果一样,但是这并不是因为swap中操作的是对象本身,而是因为实例dt是一个引用(想当于c中的指针),其存放的数据是一个地址值,指向堆内存中Date对象。

    在这里插入图片描述

    main方法将dt的地址值传递给了swap方法,因此swap方法中的dt也指向了堆内存中的Date对象,因此此时无论是更改main方法还是swap方法,均会造成影响。

    展开全文
  • 对于Java初学者来说,刚学习Java的时候可能经常会听到调用方法时参数的值传递与...下面我们通过几个例子具体分析java方法的参数传递机制。 方法的参数为基本数据类型 首先我们来看下面代码: public class ParamTrans

    对于Java初学者来说,刚学习Java的时候可能经常会听到调用方法时参数的值传递与引用传递。但是,实际上Java中方法的参数传递机制只有值传递。
    首先,我们要了解一个概念——栈帧。栈帧位于java虚拟机栈中,用于支持虚拟机进行方法的调用和方法的执行。可以简单的理解为栈帧即方法。每个方法有自己独立的栈帧。栈帧中有局部变量表、操作数栈、动态链接、返回地址等。
    下面我们通过几个例子具体分析java方法的参数传递机制。

    方法的参数为基本数据类型

    首先我们来看下面代码:

    public class ParamTransmit {
        public static void main(String[] args) {
            int i = 1;
            
            change(i);
    
            System.out.println("i = " + i);
        }
    
        public static void change(int j) {
            j += 1;
    
        }
    }
    

    程序的运行结果为:
    在这里插入图片描述
    当在main方法中调用change方法时,参数传递相当于将main栈帧中的参数i=1拷贝了一份给change栈帧,此时change栈帧中,变量j的值为1。然后在change方法中执行j += 1;运算,j的值变为2,change方法结束。main方法未结束,此时main栈帧中变量i的值仍为1。当传递的参数是基本数据类型时,传递的是数据值,即将参数拷贝一份到被调用方法的栈帧中。该方法中对变量的操作不影响原来栈帧中的变量的值,原栈帧中的变量不被修改。
    在这里插入图片描述

    方法的参数为引用类型

    引用类型变量如String类型,包装类,数组和其他自定义类等。下面依次介绍。

    String类型

    先上代码

    public class ParamTransmit {
        public static void main(String[] args) {
            String str = "hello";
    
            change(str);
    
            System.out.println("str = " + str);
        }
    
        public static void change(String str) {
            str += "world";
        }
    }
    

    程序运行结果为:
    在这里插入图片描述
    首先,在jdk1.7之后,运行时常量池从方法区中移了出来,在堆中开辟了一块区域存放运行时常量。并且要知道String的值是不可变的,每次对String的操作都会产生新的String对象。因此,在上面代码中,main方法中调用change方法时,首先是将变量str的值(即运行时常量池中hello的地址)拷贝一份到change栈帧中,此时change栈帧中的变量str也是指向“hello”。然后执行str += "world";操作,由于String值不可变,此时change栈帧中的str指向新的字符串“helloworld”,str的地址值已改变。而此时main栈帧中str的值并没有改变,仍指向“hello”,所以main方法中输出的str仍是“hello”。
    在这里插入图片描述

    包装类

    先上代码:

    public class ParamTransmit {
        public static void main(String[] args) {
            Integer num = 200;
    
            change( num);
    
            System.out.println("num = " + num);
        }
    
        private static void change(Integer num) {
            num += 1;
        }
    }
    

    程序运行结果为:
    在这里插入图片描述
    上面代码中,首先Integer num = 200;会自动装箱,先调用Integer.valueOf(200),在堆中创建一个值为200的Integer实例,并将该实例的地址赋值给num。main方法在调用change方式时传递的是num的地址值,此时change栈帧中的num也指向值为200的Integer实例。当执行num += 1;时,也自动装箱,先调用Integer.valueOf(201),在堆中创建一个职位201的Integer实例,并将该实例的地址赋值给change栈帧中的变量num,change方法结束。但此时,main栈帧的num仍指向值为200的Integer实例,因此打印结果为200。内存结构图如下:
    在这里插入图片描述
    注:上述内存结构图仅适用于不在-128至127之间的整数。Integer类的自动装箱机制是首先提供一个Integer cache[],用于存放-128至127的缓存。因此,若对实参及对形参操作的结果均在-128至127之间,则实参及形参应指向数组中的元素,而不是堆中新的Integer实例。

    数组

    直接上代码

    import java.util.Arrays;
    
    public class ParamTransmit {
        public static void main(String[] args) {
            int[] arr = {1, 2, 3, 4, 5};
    
            change(arr);
    
            System.out.println("arr = " + Arrays.toString(arr));
        }
    
        private static void change(int[] arr) {
            arr[0] += 1;
        }
    
    

    程序运行结果为:
    在这里插入图片描述
    数组变量也是引用类型。main方法在调用change方法时,传递的是数组arr的地址值。change方法内,将数组中第一个元素的值自增1,此时数组中第一个元素的值变为2。change方法结束,main方法继续执行,此时main栈帧变量arr仍指向该数组,只不过该数组中的元素已被修改。所以输出的是被修改后的数组。内存结构示意图如下:
    在这里插入图片描述
    可以引申为多维数组及数组元素为引用类型的情况。

    其他自定义类

    直接上代码

    class MyData {
        int a = 10;
    }
    public class ParamTransmit {
        public static void main(String[] args) {
            MyData md = new MyData();
    
            change(md);
    
            System.out.println("md.a = " + md.a);
        }
    
        private static void change(MyData md) {
            md.a += 1;
        }
    }
    

    程序运行结果为:
    在这里插入图片描述
    main方法调用change方法时,同样是将main栈帧中的变量md的值传递到change栈帧中,此时传递的是地址值,指向堆中同一个MyData实例。然后执行md.a += 1,此时该实例的成员变量a为11。change方法执行完毕,main方法未结束,main栈帧中的变量md仍指向该实例,此时输出的a为11。内存结构如下图。
    在这里插入图片描述
    若将上面代码修改如下,会是什么结果呢?

    class MyData {
        int a = 10;
    }
    public class ParamTransmit {
        public static void main(String[] args) {
            MyData md = new MyData();
    
            change(md);
    
            System.out.println("md.a = " + md.a);
        }
    
        private static void change(MyData md) {
            md = new MyData();
            md.a += 1;
        }
    }
    

    程序运行结果为:
    在这里插入图片描述
    main方法调用change方法时,同样传递的是地址值。然而执行md = new MyData();时,在堆中创建了一个新的实例。此时change栈帧中的变量md的值变成了新的MyData实例的地址。然后继续执行md.a += 1;,修改的是新的实例的成员变量。当change方法调用结束后,main方法继续执行,此时main栈帧中md指向的仍是原来的实例,原实例的成员变量未被修改,仍是10。因此输出结果是10。内存结构如下图。
    在这里插入图片描述

    总结

    通过以上分析,我们可以知道java的参数传递机制是值传递。若参数是基本数据类型,传递的是数据值;若参数是引用数据类型,传递的是地址值。

    1. 若参数是基本数据类型,对形参的操作不影响实参,因其是不同栈帧的不同变量。
    2. 若参数是引用数据类型,并且是String、包装类等。因其对象的不可变性,对形参的操作会导致其指向新的String或包装类等对象,但不影响实参,实参仍指向原来的对象且该对象并未被修改。
    3. 若参数是引用数据类型,并且是数组、StringBuffer及其他自定义类等时,对形参的操作会影响到实参,因其指向的是同一个实例。
    展开全文
  • java 方法的参数传递

    2009-04-04 20:57:00
    package book.oo;public class PassParamter { public PassParamter() { } public void methodA(ComplexNumber comNum) { // comNum这个引用指向了一个新new出来对象。 comNum = new ComplexNumber(1, 2);
  • 目录Java方法的参数传递注意事项(一)传参类型问题分析总结补充 Java方法的参数传递注意事项(一) 在学习了Java方法的功能之后,发现在方法的参数传递中存在着一些小坑,在这里对问题进行有一下梳理总结,方便日后...
  • 介绍java 方法的参数传递,本文是引用传递。
  • 方法,必须有其所在类或对象调用才...java方法的参数传递方式只有一种,值传递。 PS:即将实际参数值的副本(复制品)传入方法内,而参数本身不受影响。 EG: int i =10; int j =5; TestArgsTransfer s=new ...
  • java方法的参数传递其二 引用类型    本来写好了,但是图片上传不了了. 就发到资源里了.  java方法参数传递其二
  • 方法的参数传递: 1、形参:方法声明时,方法小括号内的参数。  2、实参:调用方法时,实际传入的参数的值。  3、规则:java中的参数传递机制:值传递机制。 形参是基本数据类型的:将实参的值传递给形参的...
  • java方法的参数传递其一

    千次阅读 2013-01-22 18:17:28
    java方法的参数传递其一  基本类型    java方法的参数传递有时不太好理解,结合简单的图形来对此问题进行一些分析。主要是参照张孝祥所著。 本文先看看基本类型的参数传递。 以下
  • Java的参数传递类似于《西游记》里的孙悟空,孙悟空复制一个假的孙悟空,这个假孙悟空具有和真孙悟空相同的能力,可除妖或被砍头,但不管这个假孙悟空遇到什么事,真孙悟空不会受到任何影响。与此类似,传入方法的...
  • ​public class Test7 { public static void swap(DataSwap ds... System.out.println("在swap方法中ds1.a值:"+ds1.a); } public static void main(String[] args) { // TODO Auto-generated method...
  • 言归正传,JAVA参数传递只有值传递,所谓值传递就是传递基础类型拷贝和对象类型引用拷贝。   看代码识真相:     package client; public class Test { public static void main(String[] args) ...
  • java的参数传递(只有值传递没有引用传递)

    万次阅读 多人点赞 2019-07-31 19:25:14
    所以在java方法中改变参数的值是不会改变原变量,但为什么改变引用变量属性值却可以呢?请看下面解答。 java中数据类型 Java中数据类型分为两大类:基本类型和引用类型。相应,变量也分这两种类型:...
  • 文章目录Java方法之参数传递机制基本数据类型引用数据类型...这就涉及到Java中的参数传递机制,值传递。 基本数据类型 基本数据类型,值传递的体现是数值的传递。 public class TransferTempTest { public stati...
  • 标题Java的参数传递 – 方法的参数传递 值传递 基本类型的值传递: 不是传递的 实参变量,而是传递参数的 值。 引用类型的值传递: 就是复制一下实参的内存,也就是 对象的地址,复制到 形参的位置(被调用方法的方法...
  • 标题注意java中只有值传递基本数据类型传递的...在Java方法参数的传递过程中如果用是=赋值话都相当于重新创建了一个新对象。String也是如此,String底层是final不可以变化所以也会创建一个新对象。 ...
  • java方法参数传递问题

    2019-05-21 14:15:17
    答:Java方法的参数传递方式只有一种:值传递。就是将实际参数值的副本(复制品)传入方法内,而参数本省不会受到任何影响。 数值类型变量,复制数值; 数值类型变量的引用,复制引用; 对象类型变量,复制引用(即...
  • Java方法参数的传递

    2020-05-26 08:40:33
    Java中,所有的方法参数都是传值,也就是说,方法中参数变量值是指定值拷贝 基本数据类型参数传值 向该参数传递的级别不可以高于该参数级别,如:不能向int传递一个float类型值 引用类型参数...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 12,809
精华内容 5,123
关键字:

java方法的参数传递

java 订阅