java 引用传递的三种类型小结
作者:源君 发布时间:2023-09-03 03:59:47
java引用传递的三种类型
我这里使用了mldn视频里的例子,只用于学习交流。
第一种
结果:调用前:50
调用后:1000
分析:
理解:好理解
第二种传递方式
先看例子
运行结果:
分析图片:
第三种传递方式
结果:
分析:
对于三种引用传递的理解
第一种和第三种都好理解:
其实就是c语言那样传递的是地址,当然能够修改属性值,对于第二种其实就是因为String类比较特殊,在第二个例子中fun()函数str2="mldn"其实mldn是个匿名对象!!!这个等式其实就是将str2的引用的地址值改变了,也即使str1的引用地址指向了mldn这个在堆内存的这个对象。
java引用传值问题
一图胜万言(配上一张启舰大神的图,一个自定义控件写的很吊的大神):
这几天一直在写一个项目,果然只搞理论是不行的,距离上一次写项目已经快有半年了,今天无论是效率还是熟练度都大不如前
好了言归正传,今天要说的这个问题其实很简单——在java中的参数传递问题。(其实我承认,这个地方我只是知道对象传引用、普通类型传值,典型的理论派-。+),但是这个问题可大可小,我觉得还是要把这些缕得清清楚楚才好。
问题起源,一个蠢到家的是失败案例
其实今天写这篇文章完全是咋呼-。+,恰好是因为自己在做RecyclerView的万能适配器的时候出现的问题,先给大家引入一下当时的场景:
@Override
public void resultCallbackFromFragment(List<Contact> list) {
Toast.makeText(this, "修改成功!", Toast.LENGTH_SHORT).show();
......
contactList = list;
adapter.notifyDataSetChanged();
......
}
只留下了我们设计的代码,其他部分的代码全部打……了。接下来我用极其简单的组织语言介绍一下场景:
打开一个具有复选框的界面,退出时返回选中的数据,方法为一个回调方法,方法的效果是更新列表数据(contactList为我们传入RecyclerView的源数据)。
理论上说先给contactList更新为获取到的最新的值,然后调用notifyDataSetChanged方法,列表就刷新了,看上去一切都是那么的圆满。然后我们看一下效果:
不要吐槽这个App背景,因为是给我的小仙女做的-。+!
在上面的效果中,我们看到,在选中了两个联系人,点击确定之后,按道理说应该是显示成两个人,怎么还是刚才的数据呢?
当时也是知道引用类型的传递传递的是引用,回忆了一下自己当时的思路:引用传递给了另一个引用,这一个引用的内容改变了,所有的都改变了。。。。 (可能有的朋友看到我这句话觉得很好笑:哇博主你好菜啊,这么基础的问题都被绕住了,好吧我得承认java基础是有些差。。)
就是这么简单的一句话让我饶了好几个大弯,当时自己已经被绕进去了,觉得这个数据就是被改变了啊,然后就开始从其他地方找错误,过了好久才开始反思:是不是数据传递的过程出现了点问题-。+
然后自己就开始查找参数传递相关问题,好了,现在开始,我们先跳出上面这个案例中,我不希望大家被上面花里胡哨的东西影响,因为我们今天讲的问题只有一个:java的引用传值。
两类参数传递
参数传递主要分为两种:一种是参数是基本类型,一种是参数为引用类型。
基本数据类型
这个相信大家都没什么问题,基本类型作为参数传递的时候是在一个方法栈中开辟了一块新内存,拷贝了原来的数据值,所以无论我们如何修改,原来的数据值不会受到任何影响。
举个简单的栗子:
public class Practice2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int a = 5;
System.out.println(a);
change(a);
System.out.println(a);
}
public static void change(int b) {
b = 500;
}
}
结果如下:
5
5
没有任何变化,对吧。
引用数据类型
首先我们要知道引用的数据存储在栈内存中,而引用指向的对象存储在堆内存中。
当引用作为方法参数传递给方法的时候,是将引用的值拷贝一份给另一个引用,但引用指向的都是同一个堆内存,所以进行的修改操作同样有效。
实例代码:
public class Practice {
static A a = new A(10);
public static void main(String[] args) {
// TODO Auto-generated method stub
Practice practice = new Practice();
System.out.println(practice.a.intData);
change(practice.a);
System.out.println(practice.a.intData);
}
public static void change(A aa) {
aa.intData = 500;
System.out.println(aa.intData);
}
}
class A{
int intData;
public A(int intData) {
this.intData = intData;
}
}
10
500
这么说起来没什么难度,对吧。
引用传递
其实上面所说的引用形参传递,本质上就是引用的传递,我们将引用传递给了另一个引用,那么这两个引用都有了相同的值——既指向了相同的对象。
A a1 = new A(10);
A a2 = a1;
System.out.println("a1的intData: " + a1.intData + " a2的intData: " + a2.intData );
a2.intData = 500;
System.out.println("a1的intData: " + a1.intData + " a2的intData: " + a2.intData );
结果如下:
a1的intData: 10 a2的intData: 10
a1的intData: 500 a2的intData: 500
注意):引用类型中,形参能够改变实参的值,或者一个引用能够改变另一个引用的值,仅仅是因为他们栈内存中存储的值相同,但这个值是随时可以修改的。
这个也就是本人之前一直被困住的地方,其实只要引用存储的值改变了,这两个引用就毫无关系了。请见下面的例子:
A a1 = new A();
A a2 = a1;
System.out.println(a1);
System.out.println(a2);
a2 = new A();
System.out.println(a1);
System.out.println(a2);
结果如下:
A@33909752
A@33909752
A@33909752
A@55f96302
在a2指向新的对象后,a1和a2就已经没有任何关系了,因为他们两个引用存储的值已经完全不一样了。
相信这张图已经说的很明白了吧。
反过来再解决这个案例
现在有了上面的理论知识,我们在反过头来看一开始的这个问题。
@Override
public void resultCallbackFromFragment(List<Contact> list) {
Toast.makeText(this, "修改成功!", Toast.LENGTH_SHORT).show();
......
contactList = list;
adapter.notifyDataSetChanged();
......
}
在我们获取到了新的list之后,是给contactList赋值了一个新的引用,此时他指向的为一个新的堆内存空间。但是适配器中的list还是指向之前的引用,因为我们只是改变了contactList引用的值,然后执行notifyDataSetChanged方法,可是适配器中list数据还是原来contactList指向的数据。
因此解决的办法是:直接改变适配器中的list引用,然后调用notifyDataSetChanged方法:
public void notifyData(List<T> mList){
this.mList = mList;
notifyDataSetChanged();
}
直接在适配器中写一个修改数据的方法,然后在外面调用就好啦:
@Override
public void resultCallbackFromFragment(List<Contact> list) {
Toast.makeText(this, "修改成功!", Toast.LENGTH_SHORT).show();
......
contactList = list;
adapter.notifyData(contactList);
......
}
来源:https://blog.csdn.net/weixin_43157199/article/details/82902658
猜你喜欢
- 一、Lambda 表达式的基础语 * ambda 表达式的基础语法:Java8中引入了一个新的操作符 "->" 该操
- 一,FileWritter写入文件FileWritter, 字符流写入字符到文件。默认情况下,它会使用新的内容取代所有现有的内容,然而,当指
- Mybatis 有两种实现方式其一:通过xml配置文件实现其二:面向接口编程的实现  
- 这篇文章主要介绍了Java实现TCP/IP协议的收发数据(服务端)代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参
- cookie和session的区别和联系cookie是本地客户端用来存储少量数据信息的,保存在客户端,用户能够很容易的获取,安全性不高,存储
- 因为mybatis好使,所以几乎需要操作数据库的时候,我都会使用mybatis,而且在一个正式的项目中,同时存在BS和CS的程序,都使用的M
- 在C程序代码中我们可以利用操作系统提供的互斥锁来实现同步块的互斥访问及线程的阻塞及唤醒等工作。然而在Java中除了提供LockAPI外还在语
- 前言这里主要简单介绍如何使用Camera+SurfaceView自定义相机拍照,如果是Camera2或者是TextureView的可以前往主
- Java实现PC微信扫码支付做一个电商网站支付功能必不可少,那我们今天就来盘一盘微信支付。微信支付官方网站业务流程:开发指引文档支付服务开发
- Java中List.of()和Arrays.asList()的区别及原因动手写一下,让自己更有印象1.Arrays.asList()可以插入
- 如今,企业级应用程序的常见场景是同时支持HTTP和HTTPS两种协议,这篇文章考虑如何让Spring Boot应用程序同时支持HTTP和HT
- 本文主要给大家介绍了关于Java8中Optional类型和Kotlin中可空类型使用的相关内容,分享出来供大家参考学习,下面话不多说了,来一
- 自动登录是我们在软件开发时一个非常常见的功能,例如我们登录 QQ 邮箱:很多网站我们在登录的时候都会看到类似的选项,毕竟总让用户输入用户名密
- 作为开发人员,掌握开发环境下的调试技巧十分有必要。我们在编写java程序的过程中,经常会遇到各种莫名其妙的问题,为了检测程序是哪里出现问题,
- 本文实例讲述了Android+SQLite数据库实现的生词记事本功能。分享给大家供大家参考,具体如下:主activity命名为Dict:代码
- 一、打印直角三角形这个循环控制打印十行空格for (int x = 1; x <= 10; x++) {//因为要打印一个十行的直角三
- 让我们来看看这段代码: import java.util.BitSet;import java.util.concurrent.C
- 本文实例讲述了JAVA设计模式之备忘录模式。分享给大家供大家参考,具体如下:备忘录模式:又叫做快照模式,指在不破坏封装性的前提下,获取到一个
- 附GitHub源码:WebViewExplore一、WebView的基础配置WebSettings ws = getSettings();w
- 二分查找又称折半查找,它是一种效率较高的查找方法。折半查找的算法思想是将数列按有序化(递增或递减)排列,查找过程中采用跳跃式方式查找,即先以