在Java中编写swap方法是否可行?

54

这里是问题:编写一个方法来交换两个变量的值。这两个变量应该是原始类型(primitives)。它不需要是通用的,例如两个int 变量。有办法吗?!


看这个。有关通过引用交换的更多信息。http://www.cs.utsa.edu/~wagner/CS2213/swap/swap.html 看这个。有关通过引用交换的更多信息。 - user1487767
13个回答

59
虽然不可能编写一个可以简单地交换两个变量的函数,但是可以编写一个辅助函数来实现以下功能:
  • 使用仅一个语句交换两个变量
  • 在调用者的代码中不使用临时变量
  • 不对基元类型进行“封箱”
  • 通过几种重载(其中一种使用泛型),它适用于任何类型
下面是如何实现它:
int returnFirst(int x, int y) {
    return x;
}
<T> T returnFirst(T x, T y) {
    return x;
}
// other overloads as needed
int a = 8, b = 3;
a = returnFirst(b, b = a); // try reading this as a = b; b = a;
System.out.println("a: " + a + ", b: " + b); // prints a: 3, b: 8

这是因为Java语言保证(Java语言规范,Java SE 7版,第15.12.4.2节)所有参数从左到右进行评估(与其他一些语言不同,其评估顺序未定义),因此执行顺序如下:
1. 评估b的原始值以便作为函数的第一个参数传递; 2. 评估表达式b = a,并将结果(b的新值)作为第二个参数传递; 3. 函数执行,返回b的原始值并忽略其新值; 4. 将结果分配给a。
如果returnFirst太长,您可以选择一个更短的名称来使代码更紧凑(例如a = sw(b, b = a))。
假设您需要依次交换许多不同类型的变量。通过使用returnFirst,无需intAux、objAux等。由于调用者中没有额外的变量,因此较少错误地在某个地方使用错误的变量的风险。

3
如果你将函数命名为下划线(_),那么你就几乎可以写成 a=b;b=a; 的形式。看看这样的代码多简洁:a=_(b,b=a); - marcus
2
糟糕,_ 在Java 8中已被弃用作标识符,并可能在Java 9中被删除。不确定他们将用它来做什么。 - marcus
这太糟糕了,难以阅读,谁会想要做这个? - maazza
1
我认为这应该是一个被接受的答案!太棒了(但是,完全不切实际) - Osman-pasha
我发现他们计划将下划线 _ 正式作为“未使用”的变量/参数:http://www.coffee-bytes.com/2013/08/01/reclaiming-underscore/ http://www.tothenew.com/blog/why-you-should-stop-using-underscore-as-variable-name-in-java/ 然而,实现这一目标的道路似乎异常缓慢(版本8和9不允许使用它,也许版本10会添加新的语义)。 - marcus
显示剩余3条评论

50

不使用数组或对象,不能在一个方法内完成该操作。


2
顺便说一句,数组是对象,所以你只需要说对象就可以了。来自java.sun.com的解释是:“数组是一个容器对象,它可以容纳固定数量的同一类型的值。”我知道我有点挑剔 :) - geowa4
使用数组或对象可能如何实现呢?这些数组或对象不是在方法内使用的吗?它们是全局的吗?还是可以在方法内使用本地数组或对象交换对象? - C0D3
@geowa4 我认为向新手介绍数组是一个对象,两种说法都可以。 - Ifan Iqbal

18

请查看这篇JavaWorld文章,它详细解释了这个问题:

http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html

交换两个原始数据类型的值永远不会起作用,因为在Java中,原始数据类型是按值传递的。你甚至不能编写一个方法来交换两个对象。

正如@Thomas所说,您唯一能做的就是将原始数据类型包含在其他对象/数组中,并修改它们。


15

任何原始数字的一行代码:

a += (b - (b = a));

4
您可以制作一个@marcus的swap方法的通用版本,可交换相同类型的任意数量对象:
<T> T swap(T... args) {   // usage: z = swap(a, a=b, b=c, ... y=z);
    return args[0];
}

b = swap(a, a=b);
z = swap(x, x=y, y=z);

一个可变参数函数将创建一个临时数组(Object []),以传递所有对象。我不确定JIT在运行时的行为,但是为了交换两个值而创建一个数组看起来有点浪费,除非你真的需要一个未指定数量对象的“旋转”函数。 - marcus
对于固定数量的值,您可以不使用数组来完成它。 - dansalmo

2
在Java5中,我能想到最接近的可能会对你有帮助的是:AtomicInteger类(以及其他类)具有getAndSet()原子方法。

这个问题特别涉及到原始类型。它们是对象。 - Thomas Owens
@Thomas: “应该是基本数据类型” - geowa4
@Thomas 好的,那我就不知道了。@geowa4 感谢您的支持 :-) - KLE

2
要编写一个交换原始数据类型的swap方法,您需要具备“out”变量的概念,即将其值传递到调用上下文的变量。C#有这些变量,但您仍然必须指定它们是“out”变量。

1
我已经阅读了上面的答案,寻求解释为什么说在Java中不能像在C++中编写交换程序的方式。我采用了以下方法程序截图

1
这里有一个交换两个基本变量的方法。
private void swap(){
    int a = 1;
    int b = 2;
    int temp = a;
    a = b;
    b = temp;
}

可能并没有太大用处;)

好的,认真地说,如果变量是类级别的,那么可以这样做:

public class MyClass{
    // excuse horrible coding practice of public mutable fields
    public int a = 1;
    public int b = 2;

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

虽然如此,我仍然看不出这有什么用处。


这回答了问题 - 为什么要踩? - wonderer

1

这个函数将交换两个整数

Integer[] swap(int a, int b){
    return new Integer[]{b,a};
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接