Java中的“引用传递”
做Java的小伙伴们肯定都知道,java的参数传递仅仅支持值传递,不像C#中可以用ref、out关键字传递引用!!
今天小编突然脑洞大开,Java也可以“引用传递”!!
话不多说,先上一段基本的Java代码
值类型参数传递
public static void main(String[] args) { int num = 9; change(num); System.out.println("main --> num:" + num); } private static void change(int num) { num += 2; System.out.println("change --> num:" + num); }
输出结果

这个没有疑问!so easy
引用类型参数传递(String对象和基本数据类型对象)
用String做演示
1 public static void main(String[] args) { 2 String str = "--mainMethod--"; 3 change(str); 4 System.out.println("main --> str:" + str); 5 } 6 7 private static void change(String str) { 8 str = "--changeMethod--"; 9 System.out.println("change --> str:" + str); 10 }
输出结果

也没有疑问?不管有没有,这里都要稍作解释一下
我们加上输出哈希编码,看看结果如何!
1 public static void main(String[] args) { 2 String str = "--mainMethod--"; 3 System.out.println("main --> "+str.hashCode()); 4 change(str); 5 System.out.println("main --> str:" + str); 6 } 7 8 private static void change(String str) { 9 str = "--changeMethod--"; 10 System.out.println("change --> "+str.hashCode()); 11 System.out.println("change --> str:" + str); 12 }
输出结果

我们都知道,一般情况下 hashCode 的值不一样,表示对象也不一样。因此得出结果:这个字符串对象的引用在change方法中发生了改变(在Java中,只要是String对象中的值发生改变,就会重新创建一个String对象)。
但是为什么main方法中的str没有改变呢?
这里要说到Java的方法传参了。Java中方法传参是值类型传递的,这个大家都知道,但是,不仅如此,传送的还是参数的副本。
什么意思呢?就是在传递参数的同时,Java虚拟机做了个操作,将这个参数备份了一下,将副本传给这个方法。
在上面这个change方法中,副本的引用地址发生了改变,会影响到原参数吗?答案:不会的!
接着再看一段代码
引用类型参数传递(非(String对象和基本数据类型对象))
用List做演示
1 public static void main(String[] args) { 2 List<String> list = new ArrayList<String>(); 3 list.add("chb"); 4 change(list); 5 System.out.println("main --> size:"+list.size()); 6 for (String item : list) { 7 System.out.println("foreach --> "+item); 8 } 9 } 10 11 private static void change(List<String> list) { 12 list.add("yiming"); 13 System.out.println("change --> size:"+list.size()); 14 }
输出结果

唉!怎么回事,这个值竟然添加进去了!
先嫑(不要)惊讶,看完下面代码,再惊讶也不晚!!
输出一下哈希编码
1 public static void main(String[] args) { 2 List<String> list = new ArrayList<String>(); 3 list.add("chb"); 4 System.out.println("main --> hashCode:"+list.hashCode()); 5 change(list); 6 System.out.println("main --> size:"+list.size()); 7 for (String item : list) { 8 System.out.println("foreach --> "+item); 9 } 10 } 11 12 private static void change(List<String> list) { 13 list.add("yiming"); 14 System.out.println("change --> hashCode:"+list.hashCode()); 15 System.out.println("change --> size:"+list.size()); 16 }
输出结果

what?和上面的结论不一样了?hashCode改变了,为什么main函数中的list发生了改变呢?
输出一下,调用change方法之后的list的哈希编码
1 public static void main(String[] args) { 2 List<String> list = new ArrayList<String>(); 3 list.add("chb"); 4 System.out.println("main --> hashCode:"+list.hashCode()); 5 change(list); 6 System.out.println("main --> hashCode:"+list.hashCode()); 7 System.out.println("main --> size:"+list.size()); 8 for (String item : list) { 9 System.out.println("foreach --> "+item); 10 } 11 } 12 13 private static void change(List<String> list) { 14 list.add("yiming"); 15 System.out.println("change --> hashCode:"+list.hashCode()); 16 System.out.println("change --> size:"+list.size()); 17 }
输出结果

是不是有些明白了?
再看下面代码,在change方法中重新new一次
1 public static void main(String[] args) { 2 List<String> list = new ArrayList<String>(); 3 list.add("chb"); 4 System.out.println("main --> hashCode:"+list.hashCode()); 5 change(list); 6 System.out.println("main --> hashCode:"+list.hashCode()); 7 System.out.println("main --> size:"+list.size()); 8 for (String item : list) { 9 System.out.println("foreach --> "+item); 10 } 11 } 12 13 private static void change(List<String> list) { 14 list = new ArrayList<String>(); 15 list.add("yiming"); 16 System.out.println("change --> hashCode:"+list.hashCode()); 17 System.out.println("change --> size:"+list.size()); 18 }
输出结果

越看越乱,看看源码(add方法源码以及add方法关联方法源码)
1 //add 2 public boolean add(E e) { 3 ensureCapacityInternal(size + 1); // Increments modCount!! 4 elementData[size++] = e; 5 return true; 6 } 7 8 //ensureCapacityInternal 9 private void ensureCapacityInternal(int minCapacity) { 10 modCount++; 11 // overflow-conscious code 12 if (minCapacity - elementData.length > 0) 13 grow(minCapacity); 14 } 15 16 //grow 17 private void grow(int minCapacity) { 18 // overflow-conscious code 19 int oldCapacity = elementData.length; 20 int newCapacity = oldCapacity + (oldCapacity >> 1); 21 if (newCapacity - minCapacity < 0) 22 newCapacity = minCapacity; 23 if (newCapacity - MAX_ARRAY_SIZE > 0) 24 newCapacity = hugeCapacity(minCapacity); 25 // minCapacity is usually close to size, so this is a win: 26 elementData = Arrays.copyOf(elementData, newCapacity); 27 }
看到这里,原来如此,调用list函数的方法时,list集合长度改变,相当于重新创建了list集合,所以才会hashCode改变
所以呢,小编想到的方法是什么呢?
找到一个规律:只要不是让传入的对象等于(=)另一个对象,这个对象所做的改变,是会影响调用者传入的对象的!
一段代码,搞懂!
1 public static void main(String[] args) { 2 // 问题: 我想传入一个 String 实现 C# 中的 ref、out 关键字的作用 3 // 思路:不能用等号 4 // 用别的对象封装起来呗!! 5 // 什么对象?非(基本数据类型对象和String对象) 6 // 那么用list试试吧! 7 String str = "chb"; 8 List<String> list = new ArrayList<String>(); 9 list.add(str);// 封装 10 change(list);// 此方法中进行一系列操作,将 str 的值进行改变 11 str = list.get(0);//将操作后的值,返还给 str 12 System.out.println(str); 13 } 14 15 private static void change(List<String> list) { 16 // 一系列操作省略 17 list.set(0, "wsm");// 将集合中下标是0的值,替换成:wsm 18 }
输出结果

这个时候就会有人说了,我用返回值不行吗?
小编给你的回答:可以,完全可以!但是,你想一下,编写的代码不可能总像小编写的这么简单吧!返回值要是返回了另一个数据呢?你这个值怎么办?
1 private static Element teleseme_template(String[] obj, List<List<String[]>> s) throws Exception { 2 //方法体保密 3 }
就像上面这个方法,怎么办?我在这个方法中更改了s参数中的List<String[]>集合的值,但是,在调用者那边还需要得到s参数里面List<String[]>的新值,而我的返回值类型却是一个实体!!
若有疑问或者发现小编写的有问题,还请留言!谢谢!!
 
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号