Java到底能不能实现类似C++的swap
C++的swap函数相信大家都不陌生吧,呵呵,就是典型的三行代码。该函数位于默认的std命名空间内,并且是一个模板函数。
我们这里先简单讨论下这个swap函数的参数应该是什么样。
首先,肯定是两个参数,我们这里命名形式参数为a,b,实际参数为m,n,以整数为例。如果是如下的代码:
void swap(int a, int b) {int temp=a; a=b; b=temp; }
调用代码如下:
int m=5,n=10;
swap(m, n);
上面的代码是否可行呢?
只要对参数传递有一点了解的话,就知道肯定不可行。
因为C++的默认参数传递方式是传递值(Pass by value),函数体所操作的参数变量其实是实际参数的一个副本,当离开函数体的时候,这些临时变量包括参数都被销毁。那么当然不影响真正的m和n。
在C时代,解决这个问题的方法是指针(Pointer)。指针可以通过一个内存地址而操作到真正的变量,而非一个副本。改进后代码如下:
void swap(int* a, int* b) {int temp = *a; *a = *b; *b = temp; }
调用代码如下:swap(&m, &n);
这个代码是可行的。但调用比较麻烦,因为参数是两个地址,让人或多或少有点不爽。
理解起来并不困难。随后,C++的出现有带来了一种新的解决方案。引入了“引用”(reference)的概念。swap的代码再次变化,如下:
void swap(int& a, int& b) {int temp = a; a = b; b = temp; }
调用代码如下:swap(m, n);
总之,这个swap的问题是解决了。当我首次接触到Java的时候(也就是刚开学),思考另一个问题,Java中能否实现类似swap。
首先,有必要清楚Java的参数传递方式。Java比较特殊,它对待基本类型(比如说int,char,double,boolean,long等),按值传参;而对待非基本类型,按引用传参。
引用……这个对每位程序员都再熟悉不过的名词,却在一开始令我非常迷惑。
Java中,对于基本类型,我们无法改变让它变成一个指针类型或者C++的引用类型,我们只能接受Pass by value的现实。
不过非基本类型,比如说String,既然是按引用传参,实现两个String交换应该没什么问题吧。
起初,呃,我就是这么想的。但是实践后发现我错了。
就比如如下的代码:
public void swap(String a, String b)
{ String temp=a; a=b; b=temp; }
本来以为可以轻轻松松实现a和b交换,结果……该方法的表现背叛了它的swap头衔。
为什么会这样?通过搜索,在CSDN的BBS上发现了不少类似的问题,解释嘛,归结下就是Java的传递引用并不是一个深层的引用拷贝,而是一个浅层的地址拷贝,所以swap并没有操作到真正的实参。
那么说,Java的引用和C++的引用还是有蛮大差距的咯!
Java的引用更大程度上是类似C++的指针,只是你完全不需要像C++那样得一个一个为指针手动解析(manual dereference)。
那么,我们看下面的C++代码:
void swap (int* a,int* b)
{int* temp = a; a = b; b = temp;}
大概,看到这里你也就明白了。Java的swap更像是上述的代码,根本没有交换a和b,交换的只是指针变量的指向地址。
C++的引用是一种封装的常指针,这也就决定了它一旦初始化后无法修改指针自身的内容,但是可以修改指向的内容。
而Java的引用只是一种普通的封装指针,封装性体现在你无法让指针进行指针加减运算。这样做……当然有自己很多的好处,最大的好处就是提高了程序的安全性,但最大的弊端就是降低了程序的灵活性。
呵呵,关于swap就说这么多吧。
以上主要是更偏个人心得,其实swap还有一个很值得谈论的就是C++的PIMPL的技巧,相关文献也是相当多。以后有机会嘛,偶会发表更多的啦!