Java是值传递还是引用传递,又是怎么体现的

关于Java是值传递还是引用传递,可以从代码层面来实现一下拿到结果
执行下面的代码:

    public static void main(String[] args) {         int num = 10;         String name = "Tom";         modify(num, name);         System.out.println("第3次打印int:" + num);         System.out.println("第3次打印String:" + name);         System.out.println("------------------------------------");     }      public static void modify(int n, String str){         System.out.println("第1次打印int:" + n);         System.out.println("第1次打印String:" + str);         System.out.println("------------------------------------");          // 尝试在方法内部修改传进来的参数         n = 999;         str = "ABC";         System.out.println("第2次打印int:" + n);         System.out.println("第2次打印String:" + str);         System.out.println("------------------------------------");     } 

打印出来的结果如下:

第1次打印int:10 第1次打印String:Tom ------------------------------------ 第2次打印int:999 第2次打印String:ABC ------------------------------------ 第3次打印int:10 第3次打印String:Tom ------------------------------------ 

可以看到无论是基本类型还是引用类型,传参数进去的时候的值和执行完modify方法后的值是一样的,也就是第1次打印和第三次打印是一样的。可是为什么明明在第2次已经修改成功了,第3次却又变回去了呢?
尝试换个方法把参数拿出来,

    public static void main(String[] args) {         int num = 10;         String name = "Tom";         int modifiedNum = modifyAndReturn(num);         String modifiedName = modifyAndReturn(name);         System.out.println("打印num:" + num);         System.out.println("打印name:" + name);         System.out.println("------------------------------------");         System.out.println("打印modifiedNum:" + modifiedNum);         System.out.println("打印modifiedName:" + modifiedName);     }      public static int modifyAndReturn(int n){         System.out.println("modifyAndReturn第1次打印int:" + n);          // 尝试在方法内部修改传进来的参数         n = 999;         System.out.println("modifyAndReturn第2次打印int:" + n);         System.out.println("------------------------------------");         return n;     }      public static String modifyAndReturn(String str){         System.out.println("modifyAndReturn第1次打印String:" + str);          // 尝试在方法内部修改传进来的参数         str = "ABC";         System.out.println("modifyAndReturn第2次打印String:" + str);         System.out.println("------------------------------------");         return str;     } 

得到的结果为

modifyAndReturn第1次打印int:10 modifyAndReturn第2次打印int:999 ------------------------------------ modifyAndReturn第1次打印String:Tom modifyAndReturn第2次打印String:ABC ------------------------------------ 打印num:10 打印name:Tom ------------------------------------ 打印modifiedNum:999 打印modifiedName:ABC 

可以看到通过return出来的值,的确是被改变了的,那又是为什么导致这个改变没有应用到参数本体呢?修改下代码再次测试

public static void main(String[] args) {         int num = 10;         String name = "Tom";         // 打印num和str的地址         System.out.println("修改前,传参前:");         System.out.println(System.identityHashCode(num));         System.out.println(System.identityHashCode(name));          System.out.println("---------------------------");         printAddr(num, name);          System.out.println("---------------------------");         System.out.println("修改后,执行完方法后:");         System.out.println(System.identityHashCode(num));         System.out.println(System.identityHashCode(name));     }      public static void printAddr(int n, String str){         // 打印n和str的地址         System.out.println("修改前,传参后:");         System.out.println(System.identityHashCode(n));         System.out.println(System.identityHashCode(str));          n = 999;         str = "ABC";          // 打印n和str的地址         System.out.println("---------------------------");         System.out.println("修改后,传参后:");         System.out.println(System.identityHashCode(n));         System.out.println(System.identityHashCode(str));     } 

执行结果如下

修改前,传参前: 1324119927 990368553 --------------------------- 修改前,传参后: 1324119927 990368553 --------------------------- 修改后,传参后: 1096979270 1078694789 --------------------------- 修改后,执行完方法后: 1324119927 990368553 

可以看到传参进来的参数地址是和外部定义的地址是同一个,但是修改之后会指向另一个新的地址,导致原来地址上的数据不会受到影响,这其实是一个保护机制,防止参数传入方法内被篡改指向。

下面演示引用类型的另一种情况,一些老铁可能以为是对引用类型本身的修改,其实这是不对的。
先定义一个类Person

class Person{     private String name;     private int age;      public Person(String name, int age) {         this.name = name;         this.age = age;     }      public String getName() {         return name;     }      public void setName(String name) {         this.name = name;     }      public int getAge() {         return age;     }      public void setAge(int age) {         this.age = age;     }  	@Override     public String toString() {         return "Person{" +                 "name='" + name + ''' +                 ", age=" + age +                 '}';     }	 } 

执行下面的代码,可以看到传进去的参数的属性被改变

     public static void main(String[] args) {         Person person = new Person("Rosy", 24);         String [] strings = {"AAA", "BBB", "CCC"};         System.out.println("第1次打印:");         System.out.println(person);         System.out.println(Arrays.toString(strings));          modifyObjAndPrintValue(person, strings);          System.out.println("---------------------------");         System.out.println("第4次打印:");         System.out.println(person);         System.out.println(Arrays.toString(strings));     }      public static void main5(String[] args) {         Person person = new Person("Rosy", 24);         String [] strings = {"AAA", "BBB", "CCC"};         System.out.println("第1次打印:");         System.out.println(System.identityHashCode(person));         System.out.println(System.identityHashCode(person.getAge()));         System.out.println(System.identityHashCode(person.getName()));         System.out.println(System.identityHashCode(strings));          modifyObj(person, strings);          System.out.println("---------------------------");         System.out.println("第4次打印:");         System.out.println(System.identityHashCode(person));         System.out.println(System.identityHashCode(person.getAge()));         System.out.println(System.identityHashCode(person.getName()));         System.out.println(System.identityHashCode(strings));     }      public static void modifyObjAndPrintValue(Person person, String [] strings){         System.out.println("---------------------------");         System.out.println("第2次打印:");         System.out.println(person);         System.out.println(Arrays.toString(strings));          person.setAge(1024);         person.setName("ABC");         strings[0] = "XXX";          System.out.println("---------------------------");         System.out.println("第3次打印:");         System.out.println(person);         System.out.println(Arrays.toString(strings));     } 

执行结果为

第1次打印: Person{name='Rosy', age=24} [AAA, BBB, CCC] --------------------------- 第2次打印: Person{name='Rosy', age=24} [AAA, BBB, CCC] --------------------------- 第3次打印: Person{name='ABC', age=1024} [XXX, BBB, CCC] --------------------------- 第4次打印: Person{name='ABC', age=1024} [XXX, BBB, CCC] 

从结果可以发现,Person对象的属性都被修改,String数组的元素也被修改,说明参数里对属性或数组的修改是会影响对象本身的,具体可以打印地址再查看一下:

     public static void main(String[] args) {         Person person = new Person("Rosy", 24);         String [] strings = {"AAA", "BBB", "CCC"};         System.out.println("第1次打印:");         System.out.println(System.identityHashCode(person));         System.out.println(System.identityHashCode(person.getAge()));         System.out.println(System.identityHashCode(person.getName()));         System.out.println(System.identityHashCode(strings));         System.out.println(System.identityHashCode(strings[0]));          modifyObjAndPrintAddr(person, strings);          System.out.println("---------------------------");         System.out.println("第4次打印:");         System.out.println(System.identityHashCode(person));         System.out.println(System.identityHashCode(person.getAge()));         System.out.println(System.identityHashCode(person.getName()));         System.out.println(System.identityHashCode(strings));         System.out.println(System.identityHashCode(strings[0]));     }       public static void modifyObjAndPrintAddr(Person person, String [] strings){         System.out.println("---------------------------");         System.out.println("第2次打印:");         System.out.println(System.identityHashCode(person));         System.out.println(System.identityHashCode(person.getAge()));         System.out.println(System.identityHashCode(person.getName()));         System.out.println(System.identityHashCode(strings));         System.out.println(System.identityHashCode(strings[0]));          person.setAge(1024);         person.setName("ABC");         strings[0] = "XXX";          System.out.println("---------------------------");         System.out.println("第3次打印:");         System.out.println(System.identityHashCode(person));         System.out.println(System.identityHashCode(person.getAge()));         System.out.println(System.identityHashCode(person.getName()));         System.out.println(System.identityHashCode(strings));         System.out.println(System.identityHashCode(strings[0]));     } 
第1次打印: 990368553 1096979270 1078694789 1831932724 1747585824 --------------------------- 第2次打印: 990368553 1096979270 1078694789 1831932724 1747585824 --------------------------- 第3次打印: 990368553 1023892928 558638686 1831932724 1149319664 --------------------------- 第4次打印: 990368553 2093631819 558638686 1831932724 1149319664 

从地址上可以看到,person和strings的地址一直没有变过。而在参数内部修改的person属性和数组元素,会对这部分成员的地址进行修改,并且会应用到对象本体上。

总结下来就是,无论传的是基本类型还是引用类型,只要在方法内部尝试改变参数地址的,都只能在方法内部使用,不会影响本体,而在方法内部改变属性的,会把对应的改变应用到本体上。所以Java是值传递的,传参的时候并不是把本身传入,而是创建一个副本,当被修改指向的时候不会影响本身,修改属性由于不会修改本身的地址,因此的时候可以应用到本体上。

发表评论

相关文章