【精选】形参和实参

您所在的位置:网站首页 java参数什么意思 【精选】形参和实参

【精选】形参和实参

2023-10-28 15:55| 来源: 网络整理| 查看: 265

目录

 

目录

一、形参与实参:

二、值传递和引用传递

三、基本数据类型、普通对象引用类型、String及基本数据类型装箱类的引用类型---的值传递

概述:

2.1基本数据类型作为形参:(值传递)

2.2其它对象类型 作为形参:(值传递---传递引用的副本,但是在栈stack中 原引用和副本都指向 在 堆heap中同一个实例对象,此时修改实例对象,自然实参的值也就变了)

2.3传递类型是String类型(Integer等基本类型的包装类等同 还是值传递,只不过在处理形参时多了重新赋值引用地址的动作)

 

  一、形参与实参:

 

形参,是指在定义函数时使用的参数,目的是用于接收调用该函数时传入的参数。简单理解,就是所有函数(即方法)的参数都是形参。 实参,在调用有参函数时,主调函数和被调函数之间有数据传递关系。在主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”。

public static void main(String[] args) { int num = 3; printVal(num); //这里num是实参 } private static void printVal(int num) { num = 5; //这里num就是形参 } 二、值传递和引用传递

值传递:是指在调用函数时,将实际参数复制一份传递给函数,这样在函数中修改参数时,不会影响到实际参数。其实,就是在说值传递时,只会改变形参,不会改变实参。

引用传递:是指在调用函数时,将实际参数的地址传递给函数,这样在函数中对参数的修改,将影响到实际参数。

那么,我来给大家总结一下,值传递和引用传递之前的区别的重点是什么。

 

特别强调的是,千万不要以为传递的参数是值就是值传递,传递的是引用就是引用传递。也不要以为传递的参数是基本数据类型就是值传递,传递的是对象就是引用传递。 这是大错特错的。以前的我,一直都是这样认为的,现在想来真是太天真了。判断是值传递还是引用传递的标准,和传递参数的类型是没有一毛钱关系的。

三、基本数据类型、普通对象引用类型、String及基本数据类型装箱类的引用类型---的值传递 概述:

基本数据类型-----形参改变无法改变实参

普通引用类型(对象)-----形参改变,因实参和形参 指向同一个目标对象实例, 因此实参也改变

String以及基本数据类型的装箱类引用类型------形参改变,因实参和形参指向的目标实例对象不一致,因此实参不变

 

Java的参数传递是值传递,而平常我们在Java中所说的“引用传递”,实际上只是将引用对象的地址拷贝了一份传给形参,而非自己本身的地址,也是值传递;否则,当我们为形参更换引用地址后,原拷贝方引用的地址(即为实参)也会发生变动

区分值传递还是引用传递的关键的确像你所说的,需要看形参是否改变了实参,但对于对象来说,地址才是实参! 值传递:形参改变无法改变实参。 因为java中方法的参数传递的原则是复制。也就是说不管是值传递还是引用传递,参数传递的都是值得拷贝或者是引用的拷贝。因此对象作为参数传递的是对象的引用 2.1基本数据类型作为形参:(值传递) public class ValueTransmit { public static void main(String[] args){ int no=1; System.out.println("变更前:"+no); addInt(no); System.out.println("变更后:"+no); } public static void addInt(int n){ n=n+1; System.out.println("形参的值:"+n); } } 运行结果: 变更前:1 形参的值:2 变更后:1

说明:调用addInt(no)时,实际参数no,值传递给相应的形式参数n,在执行方法addInt()时,形式参数n的值的改变不影响实际参数no的值,no的值在调用前后并没改变。 

可以发现,传递基本数据类型时,在函数中修改的仅仅是形参,对实参的值的没有影响。

需要明白一点,值传递不是简单的把实参传递给形参,而是,实参建立了一个副本,然后把副本传递给了形参。下面用图来说明一下参数传递的过程:

 

 

2.2其它对象类型 作为形参:(值传递---传递引用的副本,但是在栈stack中 原引用和副本都指向 在 堆heap中同一个实例对象,此时修改实例对象,自然实参的值也就变了) public class User { private int age; private String name; public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public User(int age, String name) { this.age = age; this.name = name; } public User() { } @Override public String toString() { return "User{" + "age=" + age + ", name='" + name + '\'' + '}'; } }

 

package com.jokin.learn; import java.util.HashMap; import java.util.Map; public class TestUser { public static void main(String[] args) { User user = new User(18, "zhangsan"); System.out.println("修改对象前:"+user); changeUser(user); System.out.println("修改对象后:"+user); } private static void changeUser(User user) { user.setAge(20); user.setName("lisi"); } }

打印结果:

修改对象前:User{age=18, name='zhangsan'} 修改对象后:User{age=20, name='lisi'}

可以发现,传过去的user对象,属性值被改变了。由于,user对象存放在堆里边,其引用存放在栈里边,其参数传递图如下:

user是对象的引用,为实参,然后创建一个副本temp,把它传递给形参user1。但是,他们实际操作的都是堆内存中的同一个User对象。因此,对象内容的修改也会体现到实参user上。

 

2.3传递类型是String类型(Integer等基本类型的包装类等同 还是值传递,只不过在处理形参时多了重新赋值引用地址的动作) public class TestStr { public static void main(String[] args) { String str = new String("zhangsan"); System.out.println("字符串修改前:"+str); changeStr(str); System.out.println("字符串修改后:"+str); } private static void changeStr(String str) { str = "lisi"; } }

打印结果:

字符串修改前:zhangsan 字符串修改后:zhangsan

咦,看到这是不是感觉有点困惑。按照第二种情况,传递参数是引用类型时,不是可以修改对象内容吗,String也是引用类型,为什么在这又不变了呢?

再次强调一下,传递参数是引用类型,并不代表就是引用传递,其实它还是值传递。此时的 lisi 和上边的 zhangsan 根本不是同一个对象。画图理解下:

 

 

 

图中,str是对象 zhangsan 的引用,为实参,然后创建了一个副本temp,把它传递给了形参str1。此时,创建了一个新的对象 lisi ,形参str1指向这个对象,但是原来的实参str还是指向zhangsan。因此,形参内容的修改并不会影响到实参内容。所以,两次打印结果都是zhangsan。

第三种情况和第二种情况虽然传递的都是引用类型变量,但是处理方式却不一样。第三种情况是创建了一个新的对象,然后把形参指向新对象,而第二种情况并没有创建新对象,操作的还是同一个对象。

我们在changeStr 方法中 使用str = "lisi"  ;试着去更改str  的值,阴差阳错的直接改变了str  的引用的地址。因为这段代码,会new一个String,再把引用交给str,即等价于:

str= new String("lishi");

而原来的那个"zhangsan"字符串还是由实参持有着的,所以,并没有修改到实际参数的值。

如果把上边changeUser方法稍作改变,你就会理解:

private static void changeUser(User user) { //添加一行代码,创建新的User对象 user = new User(); user.setAge(20); user.setName("lisi"); }

运行以上代码,你就会惊奇的发现,最终打印修改前和修改后的内容是一模一样的。 这种情况,就等同于第三种情况。因为,这里的形参和实参引用所指向的对象是不同的对象。因此,修改形参对象内容并不会影响实参内容。

修改对象前:User{age=18, name='zhangsan'} 修改对象后:User{age=18, name='zhangsan'}

总结:

从以上三个例子中,我们就能理解了,为什么Java中只有值传递,并没有引用传递。值传递,不论传递的参数类型是值类型还是引用类型,都会在调用栈上创建一个形参的副本。

不同的是,对于值类型来说,复制的就是整个原始值的复制。而对于引用类型来说,由于在调用栈中只存储对象的引用,因此复制的只是这个引用,而不是原始对象。

最后,再次强调一下,传递参数是引用类型,或者说是对象时,并不代表它就是引用传递。引用传递不是用来形容参数的类型的,不要被“引用”这个词本身迷惑了。这就如同我们生活中说的地瓜不是瓜,而是红薯一样。

参数传递时,是拷贝实参的副本,然后传递给形参。(值传递)在函数中,只有修改了实参所指向的对象内容,才会影响到实参。以上第三种情况修改的实际上只是形参所指向的对象,因此不会影响实参。


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3