闲来无事,回忆起大学我与校花同桌的快乐时光,其中有一件特别有意思的事,在此来分享给大家。
大二的某个早晨,眼见着快要上课了,老师上节课布置的编程作业我还没有写完,于是乎想借校花同桌的作业来抄一抄,校花很爽快的答应了,我拿着U盘COPY了一份校花的代码,把代码导入到我的IDEA里稍加修改,完事儿还删掉了U盘里的代码,然后自信的交上了作业。
下课后校花找到我说“我的作业不能白让你抄,你得付出代价啊,把你的钱包给我,你得请我吃饭”,然后校花拿着我的钱包去食堂刷了四份红烧肉。
下午校花把钱包还给我的时候,我怒了,“就抄你一次作业,你特么刷了劳资四块钱,你是猪么?”
校花白了我一眼说“我又不白刷你饭卡,晚上来**酒店305房,我帮你补习功课,你夜里9点过来,连敲1024下门,我就帮你开门”
我寻思行吧!就当教学费了
吃完晚饭回寝室打游戏打到8:50,我穿上外套,拿着我的笔记本电脑和Java教材跑到**宾馆,敲了三下门,校花就把门打开了。
只见校花穿着半透明睡衣,画着美美的妆站在门口,我当时懵了,道“你还真精致,大半夜的还化妆。你要给我讲什么内容啊?我可是花了四块钱的,你今天要是不给我讲明白了,可得还我钱”
校花迟疑的看着我,愣了好半天才说道“那我今天给你讲讲Java程序中的值传递与引用传递吧!”
一、定义
从字面意义上来说就是Pass By Value 和 Pass By Reference,值传递就是在方法中用到的是参数的值,引用传递就是在方法中获取的是参数的引用的值,通过对引用地址的操作,直接操作这个参数本身。
二、举例
听完定义,我还是很懵逼,校花接下来又讲到:
我们先定义三个类
Baldwin.java类代表你,你的属性里包括你的作业和你的钱
import java.util.HashMap;
/**
* 类描述
*
* @author: 12405
* @date: 2020/3/17-21:54
*/
public class Baldwin {
private int myCode;
private HashMap<String,String> myMoney;
public int getMyCode() {
return myCode;
}
public void setMyCode(int myCode) {
this.myCode = myCode;
}
public HashMap<String, String> getMyMoney() {
return myMoney;
}
public void setMyMoney(HashMap<String, String> myMoney) {
this.myMoney = myMoney;
}
}
Girl.java类代表校花,校花在这次里只涉及到作业的属性
/**
* 类描述
*
* @author: 12405
* @date: 2020/3/17-21:54
*/
public class Girl {
private int myCode;
public int getMyCode() {
return myCode;
}
public void setMyCode(int myCode) {
this.myCode = myCode;
}
}
Transaction.java类里面有我们两个进行的操作
import java.util.HashMap;
/**
* 类描述
*
* @author: 12405
* @date: 2020/3/17-22:20
*/
public class Transaction {
int baldwinCopyCode(int girlCode){
//Baldwin得到的传进来的校花的作业
int myCode;
//Baldwin修改传进来的校花的作业
girlCode -= 1;
myCode = girlCode;
//把修改好的作业传出去
return myCode;
}
void girlCost(HashMap myMoney){
//校花花钱
myMoney.remove("money1");
myMoney.remove("money2");
myMoney.remove("money3");
myMoney.remove("money4");
}
}
我今天借你抄的作业就是典型的值传递,你在使用我给你的代码是,只是复制了我的作业的值,并没有拿到我作业,实际上我的作业还在我的电脑里,你是接触不到的,你抄作业的行为跟下面的程序类似
1.值传递
import java.util.HashMap;
/**
* 类描述
*
* @author: 12405
* @date: 2020/3/17-22:29
*/
public class Demo {
public static void main(String[] args) {
Baldwin baldwin = new Baldwin();
//Baldwin没写作业,现在的Code是0
baldwin.setMyCode(0);
Girl girl = new Girl();
//校花同桌写了作业,现在的Code是10
girl.setMyCode(10);
Transaction transaction = new Transaction();
System.out.println("Baldwin`s Code:"+baldwin.getMyCode()+",Girl`s Code :"+ girl.getMyCode());
//Baldwin将修改好的作业,保存到自己的电脑里
baldwin.setMyCode(transaction.baldwinCopyCode(girl.getMyCode()));
System.out.println("Baldwin is copying girl`s code");
System.out.println("Baldwin`s Code:"+baldwin.getMyCode()+",Girl`s Code :"+ girl.getMyCode());
}
}
你看这个程序的输出
"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" "-javaagent:E:\tools\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=52781:E:\tools\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Workspaces\IdeaProjects\DemoTest\out\production\DemoTest" cn.yzstu.man.Demo
Baldwin`s Code:0,Girl`s Code :10
Baldwin is copying girl`s code
Baldwin`s Code:9,Girl`s Code :10
Process finished with exit code 0
你虽然在transcation.copyGirlCode(girlCode)中修改了形参中的的girlCode,我知道你时候还删掉了U盘里代码,你得到的这个参数不过是个形参而已,在你copyGirlCode的操作结束之后,你也释放了U盘空间,这个形参直接就删除了,所以无论你怎么操作,也不过是影响到了你所得到的值而已,与我电脑中的代码无关,所以值传递结束后,我的代码还是是10,而你得到了你想要的9
Baldwin:哦哦我现在明白了值传递的意思了,那引用传递呢?
2.引用传递
引用传递有以下示例
import java.util.HashMap;
/**
* 类描述
*
* @author: 12405
* @date: 2020/3/17-22:29
*/
public class Demo {
public static void main(String[] args) {
Baldwin baldwin = new Baldwin();
//Baldwin有5块钱
HashMap<String,String> baldwinMoney = new HashMap<>(16);
baldwinMoney.put("money1","1");
baldwinMoney.put("money2","1");
baldwinMoney.put("money3","1");
baldwinMoney.put("money4","1");
baldwinMoney.put("money5","1");
baldwin.setMyMoney(baldwinMoney);
Girl girl = new Girl();
Transaction transaction = new Transaction();
System.out.println("Girl wants Baldwin's wallet");
//此时Baldwin还有5块钱
System.out.println("Baldwin`s money:"+baldwin.getMyMoney().size());
System.out.println("Girl is spending money");
transaction.girlCost(baldwin.getMyMoney());
System.out.println("Baldwin`s money:"+baldwin.getMyMoney().size());
}
}
在这个里面,我拿到了你的钱包,相当于拿到了你的钱包的引用地址,就可以直接操作你的钱包了,我花了你钱包里的钱,直接影响了你钱包还剩下多少钱,所以你看下程序执行的结果
"C:\Program Files\Java\jdk1.8.0_171\bin\java.exe" "-javaagent:E:\tools\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=52781:E:\tools\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.8.0_171\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\cldrdata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\jfxrt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\nashorn.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\sunpkcs11.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\ext\zipfs.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jce.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jfxswt.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\resources.jar;C:\Program Files\Java\jdk1.8.0_171\jre\lib\rt.jar;E:\Workspaces\IdeaProjects\DemoTest\out\production\DemoTest" cn.yzstu.man.Demo
Girl wants Baldwin's wallet
Baldwin`s money:5
Girl is spending money
Baldwin`s money:1
Process finished with exit code 0
你看,这不就只剩一块钱了
Baldwin:哦哦我明白了值传递与引用传递的区别了,现在已经12点钟了,我得回去了,要不然我得室友该担心我了
校花:别别别,时间还早,我们还需要深入交流一下
三、值传递与引用传递的深层原理
到这里你已经明白了值传递与引用传递的不同,但是更重要的是他们的深层原理,表象很重要,但是本质更重要,就像我虽然现在表象上在跟铁柱谈恋爱,其实我的的本质还是喜欢你的
我们的Code是int类型的,也就是基本类型,他的值就直接保存在变量里,我们定义int类型变量时直接会有值存在这个变量里,但是我们定义的myMoney类型的变量就不同,他是HashMap变量中储存的其实只有一个地址你看下面这张图
myMoney变量的值其实是你钱包的地址,一般称这种变量为"引用",引用指向实际对象,实际对象中保存着内容。
我们获取到对象地址就能就能操作对象,这个对象就是你本身引用的对象,所以我们在方法中操作的对象地址,就是你引用的对象地址,这样我操作完成之后你再看你的属性,也就会发生变化了。
四、总结
1.在传递参数时基本类型参数时,我们得到了这个参数的值,无法对参数本身构成影响,此时发生的叫做“值传递”
2.在传递参数不是基本类型时,我们得到了参数的引用地址,修改该地址储存的值时,会对原参数构成影响
3.我们这里不讨论关于“Java中只有值传递”的内容,仅以Java为例来讨论值传递与引用传递,由于Java中没有指针的概念,所以Java引入地址来指向数据实现引用传递
五、后续
Baldwin:哎呀这下我才算是真的明白了,真的太谢谢你了,时间不早了,这下我真的得回去了
校花:这都凌晨三点钟了,寝室门都关了,回不去了,要不今天在宾馆睡吧
Baldwin:没事儿,我带了身份证了,我等下去网吧包夜,你要不要一起去啊?我压缩贼6
校花:WQNMLGB,NGSB