swap

C/C++

在C中交换两个变量可以通过指针的方式实现:

void swap(int *a, int *b)
{
    int temp;
    temp = a;
    a = b;
    b = temp;
}

C++里面可以使用指针也可以使用引用来实现:

void swap1(int *a, int *b)
  int temp;
    temp = *a;
    *a = *b;
    *b = temp;
}

void swap2(int &a, int &b){
    int temp;
    temp = a;
    a = b;
    b = temp;

测试
swap1(&a,&b);
swap2(a,b);

Java

Java中没有指针的概念,所以不能用指针来实现基本类型的地址传递,只能值传递,这样是实现不了swap方法的。

public class TestSwap{
	public static void main(String[] args){
		int a=2;
		int b=3;
		System.out.println("交换前 -> "+a+":"+b);
		swap(a,b);
		System.out.println("交换后 -> "+a+":"+b);
	}
	public static void swap(int a,int b){
		int temp=a;
		a=b;
		b=temp;
	}
}

console输出结果为:

交换前 -> 2:3
交换后 -> 2:3
原因:
在Java中,对基本类型的操作都是传值操作,在进入swap语句中时,我把a的值传给了新的变量a,而非原先的变量a。

java支持引用传递

eg:StringBuffer是Java中的类,定义了一个addStr()方法,并把sb对象,传入到方法中去,并且成功的改变了sb的值,这就说明进入方法体后,方法体中的局部变量sb指向了存放“Hello”的对象内存去了,不管这个指向是引用还是指针,起码引用传递能够改变原先变量sb的值。

StringBuffer sb=new StringBuffer("Hello");
addStr(sb);
System.out.println(sb);

public static void addStr(StringBuffer sb){
	sb.append(",my name is demon!");
}

console输出结果为:

Hello,my name is demon!

Java的类的划分

Java中,对类有两类划分,一类为基本类型,即我们见到的int,char,byte….等等这些小写开头的基本数据类型,还有一类在Java类库中都是以class关键字定义的类型,该类型为引用类型,即只有这些以class定义的类型才能够真正实现引用传递,而基本类型传递的只是参数值而已。
在《Thinking in Java》中提到,每个基本类型都有对应的包装类,包装类都是用class定义的引用类型。eg:int->Integer ;char->Character
那么包装类传递可以实现交换嘛?

Integer integerA=new Integer(1);
Integer integerB=new Integer(2);
System.out.println("交换前 -> "+integerA+":"+integerB);
swap(integerA, integerB);
System.out.println("交换前 -> "+integerA+":"+integerB);

public static void swap(Integer a,Integer b){
	Integer temp=a;
	a = b;
    b = temp;	
}

console输出结果:

交换前 -> 2:3
交换前 -> 2:3

结果:不能。
包装类不是引用类型嘛,为何依旧无法实现swap的正确传值?与自己封装的包装类是如何实现swap的,得出了比较合理的解释,其实引用本身是对一个类的别名。
它不像C++中的指针那样**,如果指针指向某个内存单元,对它赋值就能直接改变内存单元的值,对内存单元的操作,直接由指针指向来完成。在Java中,上述版本的swap方法,显然并没有对引用指向的内存单元进行操作,而只是改变了引用的指向**。
方法体中完成了交换,却不影响integerA和integerB的指向。那跟基本类型的值传递有何区别,**基本类型的传递是拷贝内存单元的实际数据,即内存单元中存在两份一模一样的数据,**分别由变量a和方法体内的a表示,而引用传递,在内存单元中只存放了一份实际数据,只是变量integerA和方法体内的a均指向该内存单元。
所以,只有当方法体中的a对包装类的值进行改变时,才能够影响integerA中内存单元的值。
而如果只是简单的对引用进行操作,那么即使是包装类也无法产生效果,从sb中也可以看出,它append了”my name is demon.”这就是对指向该内存单元的数据做了改变,由此改变了原先sb的值。
总结:
C/C++中swap是通过传递变量地址(指针或引用)来交换变量地址中的值。Java对程序员屏蔽了变量地址的概念,为的是减少指针误用。
在Java中函数或者叫方法的入参都是通过值拷贝的方式进行传递:

原始类型(char,int,double等)都是通过直接拷贝变量值传参;
对象类型都是通过引用拷贝(跟C++中引用不同)传参,通过该引用能够更改其指向的对象内部值,但是更改该引用值,仅对函数内部可见,函数外部的实参依然没有改变;
在这里插入图片描述

三种实现方法

重新定义类

public class MyInteger {

    private int num;

    public MyInteger(int num){
        this.num = num;
    }

    public int getNum() {
        return this.num;
    }

    public void setNum(int num){
        this.num = num;
    }

    @Override
    public String toString() {
        return num+"";
    }
}

/**引用传递+改变内存单元**/
MyInteger integerA = new MyInteger(2);
MyInteger integerB = new MyInteger(3);
System.out.println("交换前 -> "+integerA+":"+integerB);
swap(integerA, integerB);
System.out.println("交换前 -> "+integerA+":"+integerB);

public static void swap(MyInteger a,MyInteger b){
    MyInteger temp =new MyInteger(a.getNum());//拷贝一份新的值
    a.setNum(b.getNum());;//a为b的值
    b.setNum(temp.getNum());//b为a的值
}

数组(排序算法实现的swap)

public class SwapValue {
 
    public static void main(String[] args) {
        SwapValue sv = new SwapValue();
        int[] num = new int[2];
        num[0] = 20;
        num[1] = 30;
        sv.swap(num, 0, 1);
        System.out.println("num1,num2:" + num[0] + "," + num[1]);
    }
 
    public static void swap(int[] data, int a, int b) {
 
        int temp = data[a];
        data[a] = data[b];
        data[b] = temp;
    }
}

int[] data = {2,3};
System.out.println("交换前 -> "+data[0]+":"+data[1]);
swap(data, 0,1);
System.out.println("交换前 -> "+data[0]+":"+data[1]);

public static void swap(int[] data, int a, int b) {  
    int t = data[a];  
    data[a] = data[b];  
    data[b] = t;  
} 

反射机制

import java.lang.reflect.Field;

public class SwapTest {
    public static void main(String[] args) {
        Integer a = 1;
        Integer b = 2;
        System.out.println(a + " " + b);
        swap(a, b);
        System.out.println(a + " " + b);
    }

    public static void swap(Integer a, Integer b) {
        if (a == null || b == null) {
            return;
        }
        //获得a的class对象
        Class<Integer> integerClass = (Class<Integer>) a.getClass();
        try {
            //获得value属性
            Field value=integerClass.getDeclaredField("value");
            //设置权限为可访问
            value.setAccessible(true);
            //交换
            int temp=a;
            value.setInt(a,b);
            value.setInt(b,temp);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


}


外部内联

public class SwapValue03 {
 
    int i, j;
 
    public static void main(String[] args) {
        SwapValue03 sv = new SwapValue03(1, 2);
        sv.swap();
        System.out.println("i,j =" + sv.i + "," + sv.j);
    }
 
    public SwapValue03(int i, int j) {//构造方法
        this.i = i;
        this.j = j;
    }
 
    public void swap() {
        int temp = i;
        i = j;
        j = temp;
    }
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页