交换原语的Java方法

问题描述 投票:39回答:8

如果没有可以通过引用传递的方法,我如何在java中使我的交换函数生效?有人可以给我一个密码吗?

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

但是由于Java通过值传递,所以更改不会被反映回来

java
8个回答
22
投票

您无法创建方法交换,因此在调用swap(x,y)之后,将交换x和y的值。您可以通过交换它们的内容来为可变类创建这种方法¹,但这不会更改其对象标识,因此您无法为此定义通用方法。

但是,如果需要的话,您可以编写一个方法来交换数组或列表中的两个项目。

¹例如,您可以创建一个包含两个列表的交换方法,执行该方法后,列表x将具有列表y的先前内容,列表y将具有列表x的先前内容。


64
投票

我认为这是最接近简单交换的方法,但是它没有简单的用法模式:

int swap(int a, int b) {  // usage: y = swap(x, x=y);
   return a;
}

y = swap(x, x=y);

这取决于在x分配给swap之前,y将进入x,然后返回x并分配给y的事实。

您可以使其通用并交换任意数量的相同类型的对象:

<T> T swap(T... args) {   // usage: z = swap(a, a=b, b=c, ... y=z);
    return args[0];
}

c = swap(a, a=b, b=c)

13
投票

取决于您要做什么。此代码交换数组的两个元素。

void swap(int i, int j, int[] arr) {
  int t = arr[i];
  arr[i] = arr[j];
  arr[j] = t;
}

类似这样的操作交换了两个长度相等的int[]的内容。

void swap(int[] arr1, int[] arr2) {
  int[] t = arr1.clone();
  System.arraycopy(arr2, 0, arr1, 0, t.length);
  System.arraycopy(t, 0, arr2, 0, t.length);
}

类似这样的操作交换了两个BitSet的内容(使用XOR swap algorithm:]

void swap(BitSet s1, BitSet s2) {
  s1.xor(s2);
  s2.xor(s1);
  s1.xor(s2);
}

类似这样的交换某些x类的yPoint字段:

void swapXY(Point p) {
  int t = p.x;
  p.x = p.y;
  p.y = t;
}

6
投票

很显然,我对Dansalmo's answercomment没有足够的声望点,但这是个不错的名字,尽管名字不正确。他的答案实际上是K组合器。

int K( int a, int b ) {
    return a;
}

JLS is specific about argument evaluation when passing to methods/ctors/etc。 (在较早的规格中不是吗?)

当然,这是一个[[functional习惯用语,但对于认识它的人来说足够清楚。 (如果您不理解所找到的代码,请不要弄乱它!)

y = K(x, x=y); // swap x and y
K组合器是专门为这种事情设计的。 AFAIK没有理由不通过代码审查。

我的$ 0.02。


2
投票
[AFAIS,没有人提到atomic reference

整数

public void swap(AtomicInteger a, AtomicInteger b){ a.set(b.getAndSet(a.get())); }

String

public void swap(AtomicReference<String> a, AtomicReference<String> b){ a.set(b.getAndSet(a.get())); }


1
投票
我可能会执行以下操作。当然,有了丰富的Collection类,我无法想象在任何实际代码中都需要使用它。

public class Shift { public static <T> T[] left (final T... i) { if (1 >= i.length) { return i; } final T t = i[0]; int x = 0; for (; x < i.length - 1; x++) { i[x] = i[x + 1]; } i[x] = t; return i; } }

带有两个参数,它是一个交换。

它可以如下使用:

int x = 1; int y = 2; Integer[] yx = Shift.left(x,y);

或者:

Integer[] yx = {x,y}; Shift.left(yx);

然后

x = yx[0]; y = yx[1];

注意:它将自动装箱原语。

1
投票
尝试这个魔术

public static <T> void swap(T a, T b) { try { Field[] fields = a.getClass().getDeclaredFields(); for (Field field : fields) { field.setAccessible(true); Object temp = field.get(a); field.set(a, field.get(b)); field.set(b, temp); } } catch (IllegalAccessException e) { e.printStackTrace(); } }

并测试!

System.out.println("a:" + a); System.out.println("b:" + b); swap(a,b); System.out.println("a:" + a); System.out.println("b:" + b);


0
投票
对于整数类型,您可以做

a ^= b; b ^= a; a ^= b;

使用按位异或运算符^。与所有其他建议一样,您可能不应该在生产代码中使用它。

出于某种原因,我不知道,单行版本a ^= b ^= a ^= b不起作用(也许我的Java编译器有错误)。单行代码在C语言中与我尝试过的所有编译器一起工作。但是,两行版本有效:

a ^= b ^= a; b ^= a;

以及

b ^= a; a ^= b ^= a;

[其有效的证明:令a₀和b₀为ab的初始值。在第一行之后,a是a₁=a₀xorb₀;在第二行之后,b为b₁=b₀xora₁=b₀xor(a₀xorb₀)=a₀。在第三行之后,a为a2 =a₁xorb₁=a₁xor(b₀xora₁)=b₀。
© www.soinside.com 2019 - 2024. All rights reserved.