当前位置: 首页 > article >正文

【java】值传递引用传递

目录

一、概念

二、实例解释

 1. 基本类型

过程分析如下:

2. 引用类型

过程分析如下:

3. String类型

1> String的值没有改变。

过程分析:

2>StringBuffer的值改变。

过程分析:


一、概念

如果传递的是句柄(变量名)的地址,就是引用传递

如果传递的是值的地址,就是值传递

java里,只有值传递,没有引用传递。

C--Java  值传递

c++         引用传递

值:对象也是值,只要传的是个值,就是值传递

等号左边是句柄引用,右边是值。

int x1=10;
  •         基本类型

                int a = 10;                jvm会在栈中开辟一块空间存储变量a并赋值为10。

  •         引用类型

                Sample s = new Sample();                JVM会在堆中开辟一块空间存储Sample对象,并在栈中开辟一块空间存储对象的引用s(存储Sample对象在堆中的地址),并将s指向堆中的Sample对象。

  •         特殊类型

                String(是一种特殊的引用类型),                JVM做了一些优化处理。


二、实例解释

 1. 基本类型

public static void main(String[] mmm) {
		
		int x1=10;
		
		m1(x1);
        System.out.println(x1);

	}
	public static void m1(int a) {
		
	}

在m1如何操作,都无法改变x1,x2的指向,实际上传的是他的值。

过程分析如下:

        1. 首先执行main方法的主线程会在栈中申请一块内存空间,然后分配给变量x1并赋值为10.

        2. 然后执行m1(int a)方法是,会将变量x1复制一份,然后传入m1方法中的方法体去执行。

        3. 复制的变量x1并不是原来的变量,只不过值也是10.

        4. 方法结束,方法外输出打印x1的值, 因为原来的x1没有改变,所以输出的还是10.

而引用传递是可以改变指向的,因为传的是它的地址。

C++:

void m1(int &a){-- 碰到这种传参这种形式的&a,就是C++
    a=90;
}
int main(){
    int a=10;
    m1(a);
    printf("%d",a);
    return 0;
}

 返回结果10,a=10.


2. 引用类型

public static void main(String[] mmm) {
		
		
		Person x2=new Person();
		x2.age=100;
		m1(x2);
        System.out.println(x2.age);

	}
	public static void m1(Person b) {
		b.age=10;
	}

这种形式无法改变对象x2的值。因此输出的也是100.

过程分析如下:

        1. JVM首先看方法区中有没有关于Person的*.class类、方法等信息,如果没有则将方法等类信息储存到方法区中,然后创建一个Person对象和一个对象的引用x2,在中申请一块区域储存Person对象并将堆中的Person对象与方法区的class类信息等相关联,并在中申请一块区域存放x2(存放Person对象在堆中的内存地址)指向堆中的Person对象,如果方法区中有该类的相关信息,则直接将堆中的对象和方法区的对象相关联。

        2. 然后执行   x2.age=100;     Person对象的类信息和方法等是存在方法区中的,Person对象去方法区中找到该类的相关方法然后执行,将Person的属性改为age:100。

        3. 然后调用  m1()  方法时,虚拟机会复制一个引用 x2 ,然后将复制以后的 x2 也指向堆中的Person对象,虽然是两个引用(在栈中分别占用一小块内存区域,但是他们的引用地址是相同的都是指向堆中的Person对象的)。

        4. 将复制后的x2传入 m1 方法中,重复2的过程,将对象的属性改为 age:10。

        5.  方法结束,方法外打印x2中的变量值,因为x2和复制后的x2指向的都是堆中的同一个对象,所以复制到方法中的x2改变了Person对象,所以最后输出的值也是改变的。

注意!!

这种方式改变对象改变不了。

public static void main(String[] mmm) {
		
		Person x1=new Person();
		Person x2=new Person();
		m1(x1,x2);

	}
	public static void m1(Person a,Person b) {
		Person c=a;
        a=b;
        b=c;
	}

原因也是因为是值传递(复制一份),没有传地址,因此改变不了。

只能对指向的内存区域的值进行改变。


3. String类型

public class Demo {
	public static void main(String[] args) {
		String s="A";
		StringBuilder ss=new StringBuilder("A");
		add(s);
		add(ss);
		System.out.println("s:"+s);		//A
		System.out.println("ss:"+ss);	//AA
	}
	public static void add(String s){
		s+="A";
	}
	public static void add(StringBuilder s){
		s.append("A");
	}
}

1> String的值没有改变。

过程分析:

        1、首先执行main方法的线程会去方法区中的运行时常量池中查看是否有常量"A",有则直接将引用s(和上面对象一样也是s也存储在栈中)指向常量池中的"A",如果没有则先在常量池中添加常量"A",并将引用s指向"A",显然我们这里常量池中还没有A,所以创建一个常量A,并让在栈中s引用指向A。
        2、此时调用add方法,将s传入add方法中,虚拟机 会
复制一份s,将复制的s传入add方法中,复制后的s和s是两个不同的引用(在栈中的地址不同但是值相同),都是指向常量池中的常量A。
        3、这一步非常关键,进入方法中以后,A会变成AA,然后会在常量池中判断常量池中是否会有AA,显然没有,所以会将复制之后的引用s指向常量AA,结束方法。
        4、方法结束后,在方法外打印s,因为s并没有改变,还是指向的是常量池中的A,所以会输出A。

2>StringBuffer的值改变。

过程分析:

StringBuffer类的对象能够被多次修改而不产生未使用的对象,StringBuffer的内部封装了对字符串操作的方法。
        1、首先创建一个StringBuffer对象,在堆中申请一块区域然后存放该对象,然后在栈中存放ss引用(值为StringBuffer在堆中的地址)并指向堆中的 StringBuffer对象。
        2、调用StringBuffer的add方法,虚拟机会复制一份ss然后传入到add方法中,ss和复制后的ss值一样,都是指向堆中的StringBuffer对象。
        3、传入以后调用append方法将StringBuffer的值变为AA,然后调用toString方法将返回给StringBuffer对象。
        4、方法结束,方法外输出ss,因为ss也指向的是StringBuffer对象,所以会输出最后toString返回的值。


http://www.kler.cn/a/398536.html

相关文章:

  • 2.STM32之通信接口《精讲》之USART通信
  • React中组件通信的几种方式
  • mysql中mvcc如何处理纯读事务的?
  • Android加载pdf
  • torchvision库在进行图片转换操作中报antialias参数没有显式设置会导致不同图片后端中的值不统一的警告信息
  • MySQL技巧之跨服务器数据查询:基础篇-A数据库与B数据库查询合并
  • JAVA中对象实体与对象引用有何不同?举例说明
  • Transformer学习笔记(一)
  • 机器学习基础03
  • Android 关于使用videocompressor库压缩没有声音和异常的问题
  • 专题二十_动态规划_简单多状态dp问题_买卖股票系列问题_算法专题详细总结
  • 「Qt Widget中文示例指南」如何创建一个窗口标志?(二)
  • Android Framework层介绍
  • 半导体器件与物理篇3 P-N结
  • Redis的Zset在排行榜中应用
  • 【数据结构】树——顺序存储二叉树
  • 面试题1111
  • 使用Kafka实现大规模数据流处理的最佳实践
  • 用哈希表封装myunordered_map/_set--C++
  • LeetCode100之回文链表(234)--Java
  • 药方新解:Spring Boot中药实验管理系统设计
  • 比较TCP/IP和OSI/RM的区别
  • Maven常用打包方式
  • 对接钉钉审批详情
  • FMEA 在新兴技术领域(如量子计算、人工智能芯片等)的应用挑战与机遇
  • linux内核中如何向slab内存分配器申请内存