一:变量的类型
Java中的数据类型分为两类:基本数据类型和复合类型。
相应的变量分为两种类型:基本类型(java中的八中基本类型)和引用类型(类,接口,数组)。
基本类型变量:包含单个值 在变量声明时 系统就直接给变量分配空间。
引用类型变量:引用类型变量的值域基本类型的值是不同的,变量值是指向内存空间的引用(地址),在引用变量声明时,只是给该变量分配了引用空间,数据空间未分配,只有通过实例恶化开辟数据空间。
说了着吗多你们应该会说这都是瞎扯吧,但并非如此。
二:区别
值传递:如果是以基本数据类型(包括String类 因为string是final类型的)做参数进行传递,或以某个类名(包括数组名)为类型做为参数而直接对其类进行操作(非类的属性),值传递是参数的一个副本,值传递后,两个变量改变的是各自的值 。
引用传递:如果是以 引用类型之间赋值,引用传递是对象的引用地址传递后两个引用改变的是同一个对象的状态。
下面就一个简单的列子来更好的理解他们吧。
//例1
1 void
2 int
3 this.change(x1);
4 System.out.println(x1);
5 }
//改变函数
7 void change(int
8 i1=3;
9 }
//例2
1 void
2 StringBuffer x2=new StringBuffer("Hello");
3 this.change(x2);
4 System.out.println(x2);
5 }
6
7 void
8 i2.append("world");
9 }
猛一看两者没有啥区别。要是根据我开先就讲的(那些你们认为无用的)就可以一眼看出,method1()中运用的值传递,method2()中运用的引用传递,
为什吗呢下面我从内存的存储方式讲讲:
例1中
在执行到第2行时,变量x1指向存放着int 0的内存地址
x1--->【存放值0】
执行到第3行时调用changge(x1)方法的时候,内存中会出现:x1把自己值在内存中copy一份然后变量i1指向这个被复制出来的0
x1--->【存放值0】
进行一次值复制
i1--->【存放值0】
执行到第8行时,变量i1被赋值为3,而这一步已经和x1没有关系了
x1--->【存放值0】
i1--->【存放值3】
这里应该理解为啥是值传递了吧
例2中
在执行到第2行时,变量x2指向存放着Hello的内存地址
x2--->【存放值”Hello”】
执行到第3行时调用changge(x2)方法的时候,内存中会出现:x1把自己值在内存中copy一份然后变量i2指向这个被复制出来的0。
x2和变量i2 --->【存放值”Hello”】
执行到第8行时,变量i2后加上”world”,因此x2值也随之改变
x2和变量i2 --->【存放值”Hello world”】
这里应该理解为啥是引用传递了吧。
看完上面两个例子后是不是感觉有点知其所以然了。那就继续往下吧。
三:对象引用
给一个对象的引用
class
int i
}
public class
public static void
a = new A();
a.i++;
}
public static void
A a = new
add(a);
System.out.println(a.i);
}
}
输出结果是0
在该程序中,对象的引用指向的是A ,而在change方法中,传递的引用的一份副本则指向了一个新的OBJECT,并对其进行操作。而原来的A对象并没有发生任何变化。 引用指向的是还是原来的A对象。
class
int i
}
public class
public static void
//a = new A();
a.i++;
}
public static void
A a = new
add(a);
System.out.println(a.i);
}
}
输出结果是1
在该程序中,对象的引用指向的是A , 因此原来的A对象发生变化。
四:总结
Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言)。
如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,这个跟之前所谈的传值是一样的。如果在函数中改变了副本的 值不会改变原始的值. 如果参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。如果在函数中没有改变这个副本的地址,而是改变了地址中的 值,那么在函数内的改变会影响到传入的参数。如果在函数中改变了副本的地址,如new一个,那么副本就指向了一个新的地址,此时传入的参数还是指向原来的 地址,所以不会改变参数的值。