Java 数据传递(值传递与引用传递)
java的数据类型分为两类:基本类型和引用类型
- 基本类型
boolean, byte, short, int, long, float, double, char - 引用类型
Class, interface, 数据。 (String, 自定义类和接口)
java的jvm内存被分为 栈(stack) 和 堆(heap) 和 方法区(method) 三个区域。
- 栈区:
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象
而是对象放在堆内存中的地址),对象都存放在堆区中
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。 - 堆区:
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息。(class的目的是得到操作指令)
2.jvm只有一个堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身 - 方法区:
1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的class和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。
所以当我们操作一个基本类型的变量时,是直接在栈中操作的变量的值。而我们对一个引用类型的变量进行操作的时候,
是我们先通过引用到栈中拿到这个对象在堆中的地址,再对堆中的数据进行操作。
public class Test {
public static void main(String[] args) {
int a = 100;
plug(a);
System.out.println("a =" + a);
}
public static void plug(int num) {
num += 100;
}
}
上面代码中对 基本类型变量a 进行了操作,但是输出的结果还是100!
首先变量a 是一个基本变量,进行的操作都是对它的值得操作,在方法plug中的形参只是对变量a 的值得复制,对变量a 没有影响。
public class Test1 {
public static void main(String[] args) {
String str = "1001";
change(str);
System.out.println("str =" + str);
}
public static void change(String arg) {
arg = "0";
}
}
上面代码对 引用类型变量str 进行了操作,输出结果是0。
为什么呢?
首先对引用类型变量str 进行的操作都是对它持有地址对应的堆内存数据进行的操作。change方法的形参只是对它引用的一个声明,
也就是说变量str和形参arg同时指向了同一个堆内存,也就是“1001”对应的数据内存,而change方法,对这个内存的值进行了修改。
所以在输出的时候变量str拿到的数据就是经过change方法之后的数据“0”。
public class Test2 {
public static void main(String[] args) {
String str = "1001";
change(str);
System.out.println("str =" + str);
}
public static void change(String arg) {
arg = new String("0");
}
}
大家在看上面的代码,change方法中做了改变,这样的输出结果就变成了“1001”。
是这样的,new操作会在堆内存中开辟内存空间,这时,变量str和形参arg指向的就不是同一个堆内存空间了,这样不管变量arg
做怎样的操作都不会影响到变量str,因为变量arg操作的堆内存空间和str没关系,所以输出的结果就是“1001”。