JAVA引用传递

参考链接(引用数据类型与基本数据类型补充): https://blog.csdn.net/qq_42499188/article/details/88407827
参考链接(基本数据类型): https://www.cnblogs.com/xiohao/p/4296059.html
参考链接: https://blog.csdn.net/weixin_44015669/article/details/89764195

在java中几乎所有的空指针异常都是由引用传递出错(对象没有实例化)而产生的。

JVM运行数据区

jvm运行数据去共有五部分:堆,方法区,栈区,程序计数器,本地方法栈
详情请见:https://blog.csdn.net/weixin_44545800/article/details/102810204

引用数据类型与基本数据类型

引用数据类型

引用数据类型对象本身是存储在堆中(通过new开辟空间),而在栈中保存的是该对象在堆内存中的地址(可以理解为指针),但是在作为类中的属性时,则变量名与变量对象都保存在堆内存中。

eg: Person per=new Person(“张三”,1)[Person类中有两个属性,为name与age,都存储为默认值]

  1. 在栈中开辟一块栈内存,为null。标识符为per
  2. 在堆内存中开辟一块空间,存储Person类与name,age属性(不存储方法),都默认设置为默认值
  3. 将name赋值为"",age赋值为0(执行的是对属性的初始化赋值)
  4. 执行构造方法,将name赋值为“张三”,age赋值为1
  5. 将per中存储Person对内存的地址
    注:java中关于null的原理,请参考: https://blog.csdn.net/weixin_44015669/article/details/89764195

基本数据类型

被创建时,系统自动在栈区开辟空间,将数值直接存储到栈上
但是并非所有的基本数据类型的值都保存在栈空间中:

  • 方法中声明的变量(即局部变量):每当程序调用该方式时,首先通过动态链接在方法区中读取读取的方法代码,执行方法。在执行方法时,系统会为该方法建立一个方法栈,在方法中声明的变量保存在该栈中,当方法结束时,系统会释放该方法栈,相应的变量也会被销毁。这也是局部变量只能在本方法中有效的原因
  • 在类中的变量(即全局变量):当变量为基本数据类型时,变量名与变量值都存储在堆内存中。当变量为引用数据类型时,其声明的变量仍然会存储一个内存地址值,该内存地址值指向所引用的对象。引用变量名和对应的对象仍然存储在相应的堆中

引用传递

eg:

class Person{
	String name="";
	int age=0;
	public void tell() {
		System.out.println("姓名"+name+"\t年龄:"+age);
	}
}
public class P{
	public static void main(String args[]) {
		Person perA=new Person();
		//首先给perA开辟一个栈内存,存储的是在堆内存开辟的一个Person类(记为person1)的内存的地址,
		Person perB=new Person();
		//再给perB开辟另一个一个栈内存,存储的是在堆内存开辟的另一个Person类(记为person2)的内存的地址
		perA.name="张三";
		perA.age=30;
		//再通过存储在perA的堆内存地址,将对应的堆内存Person对象属性赋值(将name赋值为张三,age赋值为30),
		perB.name="王五";
		perB.age=10;
		//perB同理。
		perB=perA;
		//再将栈perA中的堆内存地址复制到perB中,此时perB与perA指向的都为person1。
		perB.name="赵六";
		//perB再将对应的堆内存的name属性改为赵六
		perA.tell();
	}
}

输出为:赵六 30
分析:首先给perA开辟一个栈内存,存储的是在堆内存开辟的一个Person类(记为person1)的内存的地址,再给perB开辟另一个一个栈内存,存储的是在堆内存开辟的另一个Person类(记为person2)的内存的地址,再通过存储在perA的堆内存地址,将对应的堆内存Person对象属性赋值(将name赋值为张三,age赋值为30),perB同理。再将栈perA中的堆内存地址复制到perB中,此时perB与perA指向的都为person1。perB再将对应的堆内存的name属性改为赵六

内存分配图:

eg2:

package lianxi;
public class P {
	public static void main(String args[]) {
		String str="hello";
		fun(str);   // -->相当于s=str,将内存空间传递给s
		System.out.println(str);
		
	}
	public static void fun(String s) {
		s="word";    //方法结束后,进行释放
	}
}

结果:hello

总结

1、new关键字永远将开辟一块堆内存空间,存储的是属性
2、栈内存只能保存一块堆内存地址
3、引用传递的本质为:同一块堆内存可以被不同的栈内存指向
4、在发生引用传递时,如果操作的栈内存空间有堆内存指向,那么改变堆空间就改变了内存指向
5、如果一块堆内存没有任何的栈内存指向,那么此空间将成为垃圾空间,所有的垃圾空间会被GC(垃圾收集器)回收并且释放,垃圾回收时间不确定,所以应尽量少产生垃圾空间。(详情请见jvm)

若有不足,请多多指教。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值