如何在Java中编写基本的交换函数

56

我是Java的新手。如何编写与以下C代码等效的Java代码。

void Swap(int *p, int *q)
{
   int temp;
   temp = *p;
   *p = *q;
   *q = temp;
} 

错误的答案.. Java 不仅是按值传递.. 当您传递一个非本地值时,您正在传递一个指针。如果您必须使用 new 进行实例化,则它是一个指针。http://javadude.com/articles/passbyvalue.htm - baash05
2
你正在传递一个对象的引用 - 是的,但是这个引用被复制了。"按值传递引用"可能是更好的描述。你不能改变被传递的引用,你只能改变目标对象。 - Bozho
3
我认为这个方法是Java中最接近swap函数的方法。 - dansalmo
这归结于不可能的“按引用传递原始类型”:https://dev59.com/EG855IYBdhLWcg3weUQQ - Ciro Santilli OurBigBook.com
这个问题没有给出上下文,所以意义不大。在什么情况下你需要在Java中使用这样的交换函数呢? - SpaceTrucker
显示剩余4条评论
19个回答

102

这里有一个技巧:

public static int getItself(int itself, int dummy)
{
    return itself;
}

public static void main(String[] args)
{
    int a = 10;
    int b = 20;

    a = getItself(b, b = a);
}

18
你会雇用一个写晦涩难懂代码的人吗?除非他们能解释为什么在实际生产中绝不会 那样的事情。 - ToolmakerSteve
2
加一分给这个技巧,减一分是因为如果没有好的解释,它不能被广泛地用于生产。它不能被封装在单独的方法中,对吗? - Bart
请查看此处https://dev59.com/vXM_5IYBdhLWcg3wdzDz#16826296 以了解其工作原理。 - marcus
谢谢您。由于很长时间没有使用Java作为我的主要语言,我误解了语法的一部分。我以为Java从C/C++中做出的一个改变是赋值不再是表达式。实际上,这个改变是Java引入了一个适当的布尔类型,不能与整数互换使用,因此您不能在if语句中使用不返回布尔值的赋值。赋值返回涉及到的任何类型,并返回赋值表达式的右侧。 - froggythefrog
@GabrielŠčerbák 我想提醒一下,如果使用此功能的员工能够清楚地表达正在执行交换操作,那么他们应该受到赞扬。这种解决方案的缺点在于首先尝试在Java中创建交换函数的缺点。您实际上无法在不先将它们放入对象或数组中的情况下交换基本类型。 :/ - froggythefrog
总的来说,这是一个不好的建议。该方法在C++中无法工作,因为参数的评估顺序是未指定的。因此,您会学习到一种不好的模式。 - 0kcats

41

这里有一种使用位运算符XOR(^)仅用一行代码在Java中交换两个变量的方法。

class Swap
{
   public static void main (String[] args)
   {
      int x = 5, y = 10;
      x = x ^ y ^ (y = x);
      System.out.println("New values of x and y are "+ x + ", " + y);
   }
} 

输出:

x和y的新值为10,5


14
因为这并没有回答问题。问题是关于一个独立的函数,它可以接受两个变量作为参数并交换它们的值。 - mightyWOZ

41

对两个整数进行排序

简短的回答是:你无法这样做,因为Java没有指针。

但是,以下是类似的方法:

public void swap(AtomicInteger a, AtomicInteger b){
    // look mom, no tmp variables needed
    a.set(b.getAndSet(a.get()));
}

你可以使用各种容器对象(如集合、数组或带有int属性的自定义对象)来完成此操作,但不能使用基本类型及其包装类(因为它们都是不可变的)。但我想唯一使它成为一行代码的方法是使用AtomicInteger。
顺便说一下:如果你的数据恰好是一个List,更好的交换方式是使用Collections.swap(List, int, int):
Swaps the elements at the specified positions in the specified list.
(If the specified positions are equal, invoking this method leaves
the list unchanged.)

Parameters:
    list - The list in which to swap elements.
    i - the index of one element to be swapped.
    j - the index of the other element to be swapped. 

对int[]数组进行排序

显然真正的目标是对一个int类型的数组进行排序。 使用Arrays.sort(int[])即可实现一行代码解决:

int[] arr = {2,3,1,378,19,25};
Arrays.sort(arr);

检查输出:

System.out.println(Arrays.toString(arr));
// [1, 2, 3, 19, 25, 378]

这里是一个简单的辅助函数,用于交换整数数组中的两个位置:

public static void swap(final int[] arr, final int pos1, final int pos2){
    final int temp = arr[pos1];
    arr[pos1] = arr[pos2];
    arr[pos2] = temp;
}

由于我正在编写一些排序算法,我有一个整数数组。在调用swap之前,我需要将普通的整数强制转换为AtomicInteger吗? - Melinda
如果您想对一个int数组进行排序,请使用Arrays.sort()方法。参考链接:http://download.oracle.com/javase/6/docs/api/java/util/Arrays.html#sort%28int%5b%5d%29 - Sean Patrick Floyd
顺便说一句,无法将基本类型强制转换为对象,但AtomicInteger具有一个带有int参数的构造函数。 - Sean Patrick Floyd
1
@Melinda:Arrays.sort是答案,但如果你想交换两个简单的值,请遵循老方法:int aux = b; b = a; a = aux; - helios
但是有时候我们可能不仅仅想要对整数进行排序,更不用说只对原始类型进行排序了。真正的“在Java中总是有效”的答案是使用setter和getter的交换方法。它对我很有帮助,非常感谢。 - Benjamin R

11

对于任何原始数字类,包括 doublefloat,请使用此一行代码:

a += (b - (b = a));
例如:
double a = 1.41;
double b = 0;
a += (b - (b = a));
System.out.println("a = " + a + ", b = " + b);

输出为a = 0.0,b = 1.41


让我交换double a = 1.0e17和b = 1.0。哎呀...它不起作用。 我认为在C++中会更糟糕,因为它对于任何类型或值都不起作用。 - 0kcats

5
在Java中没有指针。然而,每个“包含”对象的变量都是该对象的引用。要有输出参数,您必须使用对象。在您的情况下,使用Integer对象。
因此,您必须创建一个包含整数的对象,并更改该整数。您不能使用Integer类,因为它是不可变的(即其值无法更改)。
另一种选择是让方法返回整数数组或一对整数。

1
整数对象是不可变的,所以那也行不通。 - Michael Borgwardt
2
整数不会有帮助,它们是不可变的。你需要一个容器,可以使用AtomicInteger(请参见我的答案)或者一个只有1个元素的列表、数组或任何类似的东西。 - Sean Patrick Floyd
1
再次强调,整数对象将按值传递。这也行不通。http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526-pass.html - Lunivore
4
不,Integer对象并不是按值传递的。它们根本没有被传递。将传递一个指向 Integer 对象的引用,且这个引用是按值传递的。在Java中,你只能传递引用和基本类型的值,永远不会传递对象! - Joachim Sauer
抱歉,我有点懒,您的描述更准确。不过,URL 很好地解释了它,即使对于不是不可变对象的情况也是如此。 - Lunivore

3
在这种情况下,可以使用只有一个元素的数组来解决问题,这是一种快速而简单的解决方案:
public void swap(int[] a, int[] b) {
  int temp = a[0];
  a[0] = b[0];
  b[0] = temp;
}

当然,你的代码也必须与这些数组配合使用,这有点不方便。如果你想从内部类修改本地的 final 变量,则数组技巧更加实用:
public void test() {
  final int[] a = int[]{ 42 };  
  new Thread(new Runnable(){ public void run(){ a[0] += 10; }}).start();
  while(a[0] == 42) {
    System.out.println("waiting...");   
  }
  System.out.println(a[0]);   
} 

3

强大的IntHolder怎么样?我喜欢任何带有omg名称的包!

import org.omg.CORBA.IntHolder;

IntHolder a = new IntHolder(p);
IntHolder b = new IntHolder(q);

swap(a, b);

p = a.value;
q = b.value;

void swap(IntHolder a, IntHolder b) {
    int temp = a.value;
    a.value = b.value;
    b.value = temp;
}

2

片段-1

public int[] swap1(int[] values) {
  if (values == null || values.length != 2)
    throw new IllegalArgumentException("parameter must be an array of size 2");
  int temp = values[0];
  values[0]=values[1];
  values[1]=temp;
  return values;
}

代码段-2

public Point swap2(java.awt.Point p) {
  if (p == null)
    throw new NullPointerException();
  int temp = p.x;
  p.x = p.y;
  p.y = temp;
  return p;
}

使用方法:

int[] values = swap1(new int[]{x,y});
x = values[0];
y = values[1];

Point p = swap2(new Point(x,y));
x = p.x;
y = p.y;

真的。而且非常有趣。但它比使用临时变量进行内联交换更多的是编码。也许指出如果程序员愿意在某个对象中携带这两个值,那么它们可以在该对象内部交换。然而,我想不出任何实际上有所帮助的算法。 - ToolmakerSteve

2

Java使用传值方式。无法使用方法交换两个基本类型或对象。

虽然可以在整数数组中交换两个元素。


无法通过将任何东西作为参数传递到方法中来交换两个任意物体 - 不仅限于基本数据类型。 - Lunivore
@Lunivore 我认为对象是通过引用传递的。那么,在这种情况下,为什么不能交换它们的引用? - Cristian
@Cristian:不正确:Java对象是按值传递的引用。这是一个区别。 - Sean Patrick Floyd
1
C语言也使用按值传递参数,只有C ++具有按引用传递。即使在给出的示例中,它也传递了两个指针的值。这就是为什么在Java中没有按引用传递与此限制无关的原因。 - Trinidad

1

在Java中,您无法使用引用,因此交换函数是不可能的,但是您可以针对每个交换操作使用以下代码片段:

T t = p
p = q
q = t

其中T是p和q的类型

然而,通过重写属性可能会交换可变对象:

void swap(Point a, Point b) {
  int tx = a.x, ty = a.y;
  a.x = b.x; a.y = b.y;
  b.x = t.x; b.y = t.y;
}

这是一个有用的观察。 - ToolmakerSteve

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