Java浅解 值传递和引用传递

在上一篇文章对象中,略微提出了一些值传递和引用传递的概念,感觉需要写出篇简单的理解一下。

首先声明一点,java的传递时值传递,而非引用传递(即指针)。

  • 值传递:值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
  • 引用传递:引用传递是指在调用函数时将实际参数的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。是C语言的一种传递方式。

如何体现是值传递,代码如下:

public class Test{
	public static void main(String[] args) {

     int a=10;//静态变量
     System.out.println(a);
     updata(a);
     System.out.println(a);
	}
	
	public static void updata(int a) {
		a=a+10;
		 System.out.println("updata中a的值   "+a);
	}
	
}
//输出结果
10
updata中a的值   20
10

可见在updata 中对a进行多了修改,但是没有实际的参数值a进行修改,而a的值只能在方法体内生效,也就是局部变量。

我们这里也就简单的拓展一下局内变量和全局变量。

  • 局部变量:也称内部变量,是指在一个函数内部或复合语句内部定义的变量。

    简单的看,就是在方法体内生效,在之外是不会生效的变量。

  • 成员变量(全局变量):就是在方法体之外的变量。

java 变量取值,会就近原则,就是方法体内部有就不会去外部寻找如何理解:

注意: 此处的的a会全局变量

public class Test{
	static int a=10;//全局变量
	public static void main(String[] args) {

     System.out.println(a);
     updata(a);
     System.out.println(a);
	}
	
	public static void updata(int a) {
		a=a+10;
		 System.out.println("updata中a的值"+a);
	}
	
}
//输出结果
10
updata中a的值   20
10

这样看程序运行似乎,虽然变成了全局变量,但是具体结果和局部变量没有什么区别。

请看下面代码:

public class Test{
	static int a=10;
	public static void main(String[] args) {

     System.out.println(a);
     updata();
     System.out.println(a);
	}
	
	public static void updata() {
		a=a+10;
		 System.out.println("updata中a的值"+a);
	}
	
}
//输出结果
10
updata中a的值20
20

看见结果变了,难道就不知值传递了吗?

不,还是值传递,但是在updata 方法中没有形参 int a,所以也就没有所谓参数传递。而其运行规则我们说过,就近原则,所以局部没有,那么就需要找外面的的,而updata 中的a也就是全局变量a。所以此处不是引用传递,而是两个变量作用域不同而结果不同而已。

我们区别了全局变量和局内变量,现在我们回来继续说java中的值传递,想要理解这个,就必须对于java的堆和栈进一步理解。

java内存中分三个区:堆,栈,方法区。

  • 堆:分配的是对象的存储空间,也就是new之后真正数据存在的内存空间。其中可以理解比如new Dog,而dog就会存储在堆当中,而其就是一个大房子,而其毛色 color,公母 sex 等属性就其里面的房间信息。

  • 栈:基本数据类型以及对象的引用的地址

  • 方法区:就是类运行的时候加载类的信息以及static修饰的变量。

    • 加载类的信息:
      1. 这个类型的完整有效名。
      2. 这个类的直接父类的有效名,当然接口和object是除外,两者无父类
      3. 以及类的类型修饰符 public abstract等
    • 方法信息:就是防护的修饰符,以及方法类型,方法的参数和类型等,方法有关信息
    • static修饰的模块,以及修饰的变量

    方法区包含以上,以及其他的域信息,方法表(提高运算是一种数据结构)等

现在有疑问了,不是说java是值传递吗?为什么栈的定义提到了引用。

java的参数传递的时候是值传递,而其java中也没有如同C语言中指针的概念(也就是引用),但是不代表其没有使用指针。

在这里插入图片描述

可以简单理解如上图所示的一个结构。

int num=10;
String str="apple";

因为int是基本数据类型,所以直接存储在栈中,而string是类,所以在栈中存放的是堆的地址。

在这里插入图片描述

看到上面结构,有的就了一个大胆的想法,那就是,如果用string 类型的话,是否在局部修改的时候会影响实际参数呢?不解释,先看代码:

public class Test{
	
	public static void main(String[] args) {
		String a="test";
     System.out.println(a);
     updata(a);
     System.out.println(a);
	}
	
	public static void updata(String a) {
		 a=a+10;
		 System.out.println("updata中a的值"+a);
	}
	
}
//输出结果
test
updata中a的值test10
test


实参完全没有修改,不是说string是引用吗?为什么改变了而其实参没有改变。

在这里插入图片描述

其实这个就是在传递的时候形参复制了实参引用,但是string,本身尤其自己的特点,以为string 本身在建立后是不可改变的,但是所以虽然是通过+ 号进行了一个字符串添加,但是其意思就是新建了string对象,而其索引也就会变。

而如果需要string类型本身改变,因为大量使用string+会造成资源浪费,而java gc(垃圾回收)机制是jvm自己安排的。而是新建字符串,那就需要其衍生的两个类 StringBuffer和StringBuilder。这两个有append的方法可以在其对象上添加数据。

  1. StringBuilder 适用于单线程,其速度快但是不够安全。
  2. StringBuffer 适用于多线程,其速度慢但安全

现在我们看一下对象使用的引用,同样首先看代码

public class Dog {
	String name;
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}


public class Test{
	
	public static void main(String[] args) {
	 Dog dog = new Dog();
     dog.setName("旺财")   
     System.out.println(dog.getName());
     updata(dog);
     System.out.println(dog.getName());
	}
	
	public static void updata(Dog dog) {
		 dog.setName("元宝")
		 System.out.println("updata中的值"+dog.getName());
	}
	
}
//输出的值
旺财
updata中的值元宝
元宝

在这里插入图片描述

同理,也是传递了所在堆的地址,但是其没有新建一个dog对象,等于还是在原有的对象上调用了setName对dog进行赋值,所以本质还是值传递,而是引用一直没有说,但是一直存在。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值