1.基本类型和引用类型在内存中的保存
Java中数据类型分为两大类,基本类型和对象(数组,类,接口)类型。相应的,变量也有两种类型:基本类型和引用类型。
基本类型包括:byte,short,int,long,char,float,double,Boolean,returnAddress,
引用类型包括:类类型,接口类型和数组。
基本类型的变量保存原始值,即它代表的值就是数值本身;
而引用类型的变量保存引用值,"引用值"指向内存空间的地址,代表了某个对象的引用,而不是对象本身,对象本身存放在这个引用值所表示的地址的位置。
int num = 10;
String str = "hello";
如图所示,num是基本类型,值就直接保存在变量中。而str是引用类型,变量中保存的只是实际对象的地址。一般称这种变量为"引用",引用指向实际对象,实际对象中保存着内容。
num = 20;
str = "java";
对于引用类型 str,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。 但是原来的对象不会被改变(重要)。
如上图所示,"hello" 字符串对象没有被改变。(没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收)
2.引用传递和值传递
这里要用实际参数和形式参数的概念来帮助理解,
值传递:
方法调用时,实际参数把它的值传递给对应的形式参数,函数接收的是原始值的一个copy,此时内存中存在两个相等的基本类型,即实际参数和形式参数,后面方法中的操作都是对形参这个值的修改,不影响实际参数的值。
引用传递:
也称为传地址。方法调用时,实际参数的引用(地址,而不是参数的值)被传递给方法中相对应的形式参数,函数接收的是原始值的内存地址;
在方法执行中,形参和实参内容相同,指向同一块内存地址,方法执行中对引用的操作将会影响到实际对象。
值传递
示例:
public class Test3 {
public static void change(int a){
a=50;
}
public static void main(String[] args) {
int a=10;
System.out.println(a);
change(a);
System.out.println(a);
}
}
很显然输出的 是10,10。传递的是值得一份拷贝,这份拷贝与原来的值没什么关系。
内存分析:
引用传递
示例:
public class Test3 {
public static void change(int []a){
a[0]=50;
}
public static void main(String[] args) {
int []a={10,20};
System.out.println(a[0]);
change(a);
System.out.println(a[0]);
}
}
显然输出结果为10 50。实际传递的是引用的地址值。
内存分析:
引用传递:如果在函数中改变了引用的地址,如new一个,那么引用就指向了一个新的地址,此时传入的参数还是指向原来的地址,所以不会改变参数的值。
public class Emp {
public int age;
}
public class Test{
public static void change(Emp emp){
emp.age =1000;
System.out.println(emp.age);
emp = new Emp();//再创建一个对象
emp.age=10000;
}
public static void main(String[] args) {
Emp emp = new Emp();
emp.age = 10;
System.out.println(emp.age);
change(emp);
System.out.println(emp.age);
}
}
输出为:10 1000 1000 内存分析:
这里要特殊考虑String,以及Integer、Double等几个基本类型包装类,它们都是immutable类型, 因为没有提供自身修改的函数,每次操作都是新生成一个对象,所以要特殊对待,可以认为是和基本数据类型相似,传值操作。
public class Test {
public static void change(String s){
s="zhangsan";
}
public static void main(String[] args) {
String s=new String("lisi");
System.out.println(s);
change(s);
System.out.println(s);
}
}
输出为:lisi lisi,
由于String类是final修饰的,不可变,它会在内存中在开辟一块新空间。
结论
结合上面的分析,关于值传递和引用传递可以得出这样的结论:
(1)基本数据类型传值,对形参的修改不会影响实参;
(2)引用类型传引用,形参和实参指向同一个内存地址(同一个对象),所以对参数的修改会影响到实际的对象;
(3)String, Integer, Double等immutable的类型特殊处理,可以理解为传值,最后的操作不会修改实参对象。