本帖最后由 燿陚√揚葳 于 2014-7-10 11:37 编辑
今天做练习时,碰到的问题,如:
public static void main(){
int x=10;
show(x);
System.out.println(x);
}
public static void show(int x){
x=0;
}
相信都知道这个输出结果是什么
由此而引出的很多文题也就出来了,一个方法调用另一个方法时,用到它的数据,是不是原数据一定不会受到影响呢
比如数组为什么就会改变了原来的数据呢?
如:
public static void main(){
int[] arr={4,5,6,7,9,8,53,1,2,0};
t.changeShuzu(arr);
for(Object str:arr){
System.out.print(str+"*");
}
}
public static void changeShuzu(int[] args){
for(int x=0;x<args.length;x++){
if(args[x]>4)
args[x]=0;
}
}
他的数据为什么会改变呢?
这里总结了一些关于这方面的知识,希望对大家有所帮助
首先
与其他语言不同,Java不允许程序员选择按值传递还是按引用传递各个参数,
基本类型(byte--short--int--long--float--double--boolean--char)的变量总是按值传递。
就对象而言,不是将对象本身传递给方法,而是将对象的的引用或者说对象的首地址传递给方法,
引用本身是按值传递的-----------也就是说,讲引用的副本传递给方法(副本就是说明对象此时有两个引用了),
通过对象的引用,方法可以直接操作该对象(当操作该对象时才能改变该对象,而操作引用时源对象是没有改变的)。
如代码:
- public class Test {
- public void changeInt(int i) {
- i = 5;
- }
- public void changeLong(long i) {
- i = 555;
- }
- public void changeString(String str) {
- str = "5555";
- }
- public void changeMember(Member member) {
- member = new Member("Cindy", 35);
- }
- public void changeMemberField(Member member) {
- member.setAge(20);
- member.setName("Andy");
- }
- public void changeShuzu(String[] args){
- for(int x=0;x<args.length;x++){
- if(args[x]=="aaa")
- args[x]="111";
- }
- }
- public void change(StringBuffer x, StringBuffer y) {
- x.append(y);
- y = x;
- }
- public static void main(String[] args) {
- Test t = new Test();
- int intValue = 10;
- t.changeInt(intValue);
- System.out.println(intValue);
- long longValue = 10;
- t.changeLong(longValue);
- System.out.println(longValue);
- String stringValue = "1234";
- t.changeString(stringValue);
- System.out.println(stringValue);
- String[] strs={"aaa","bbb","ccc","ddd","eee","fff"};
- t.changeShuzu(strs);
- for(String str:strs){
- System.out.print(str+"*");
- }
- System.out.println();
- Member member2 = new Member("Douglas", 45);
- t.changeMember(member2);
- System.out.println(member2);
- Member member = new Member("Bill", 25);
- t.changeMemberField(member);
- System.out.println(member);
- StringBuffer buffA = new StringBuffer("a");
- StringBuffer buffB = new StringBuffer("b");
- t.change(buffA, buffB);
- System.out.println(buffA + "," + buffB);
- }
- }
- class Member {
- private String name;
- private int age;
- public Member(String name, int age) {
- this.age = age;
- this.name = name;
- }
- public String toString() {
- return "Member name=" + name + " age=" + age;
- }
- public void setAge(int age) {
- this.age = age;
- }
- public void setName(String name) {
- this.name = name;
- }
- }
复制代码 输出的结果为
10
10
1234
111*bbb*ccc*ddd*eee*fff*
Member name=Douglas age=45
Member name=Andy age=20
ab,b
结果的分析:
第一个输出10是因为int是基本类型,传递的参数是intValue的拷贝,对拷贝的修改对原值intValue没有影响.
第一个输出10和上面是一个道理.
第三个输出1234.由于String是类类型, str是stringValue的地址拷贝,参数str指向的地址和stringValue的一致,
但在函数changeString 中,由于String的特殊性, str=“5555”和str=new String(“5555”)是等价的,
str指向了新的”5555”所在的地址,此句后str就与原来的stringValue彻底脱离了联系.
第四个输出的是111*bbb*ccc*ddd*eee*fff*。如果将单个基本类型数组的元素传递给方法,并在方法中对其进行修改,
则在被调用方法结束执行时,该元素中存储的并不是修改后的值,因为这种元素是按值传递,如果传递的是数组的引用,
则对数组元素的后续修改可以在原始数组中反映出来(因为数组本身就是个对象,int[] a = new int[2];,
这里面的int是数组元素的类型,而数组元素的修改是操作对象)。
于单个非基本类型数组的元素在方法中修改,则在被调用方法结束执行时,该元素中存储的是修改后的值,
因为这种元素是按引用传递的,对象的改动将在源数组的数组元素中反映出来。
第五个输出Member?name=Douglas?age=45的道理和上面相同.
第六个输出Member?name=Andy?age=20是因为changeMemberField函数中修改了参数member
的值,也就是修改member指向实例的值,而这个实例正是member指向的值,因此member就变成了name=Andy 且age=20.
就像是数组一样都是对对象的操作所以会改变原数据
第七个输出的是ab,b。
在方法change()里 的x.append(y),其中引用x调用api方法append()修改了new StringBuffer("a");的内容。
y=x;是一个修改内容的对象把首地址赋值给引用变量y了,此时操作的是引用,
而先前y是new StringBuffer("b");的引用变量,所以输出结果是:ab,b
总结:
Java参数,不管是原始类型还是引用类型,传递的都是副本(有另外一种说法是传值,但是说传副本更好理解吧,传值通常是相对传址而言)。
如果参数类型是原始类型,那么传过来的就是这个参数的一个副本,也就是这个原始参数的值,
这个跟之前所谈的传值是一样的。如果在函数中改变了副本的 值不会改变原始的值.
如果参数类型是引用类型,那么传过来的就是这个引用参数的副本,这个副本存放的是参数的地址。
如果在函数中没有改变这个副本的地址,而是改变了地址中的 值,那么在函数内的改变会影响到传入的参数。
如果在函数中改变了副本的地址,如new一个,那么副本就指向了一个新的地址,
此时传入的参数还是指向原来的 地址,所以不会改变参数的值。
|