Как написать базовую функцию подкачки на Java

Я новичок в java. Как написать Java-эквивалент следующего кода C.

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

person Melinda    schedule 02.09.2010    source источник
comment
Вместо того, чтобы просто указать метод обмена, я бы дал вам эта статья. В нем объясняется, как сделать метод подкачки, но также объясняется, как этого не делать, и почему это невозможно в том виде, в котором вы его ожидаете, из-за того, что Java является только передачей по значению (в отличие от C/C++)   -  person Bozho    schedule 02.09.2010
comment
неправильный ответ. Java не только передается по значению. Когда вы передаете неродное значение, вы передаете указатель. Если вам нужно изменить его, это указатель. javadude.com/articles/passbyvalue.htm   -  person baash05    schedule 07.03.2012
comment
вы передаете ссылку на объект - да, но ссылка копируется. передача ссылки по значению, вероятно, является лучшим описанием. Вы не можете изменить переданную ссылку, вы можете изменить только целевой объект   -  person Bozho    schedule 07.03.2012
comment
Я думаю, что этот метод является ближе всего вы можете добраться до функции подкачки в Java.   -  person dansalmo    schedule 25.06.2014
comment
Я нашел эту статью, пытаясь понять то же самое. ссылка   -  person Jaca    schedule 05.02.2015
comment
Это сводится к невозможному примитиву передачи по ссылке: stackoverflow.com/questions/4319537/   -  person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 13.04.2015
comment
C - это такая же передача по значению, как и Java.   -  person Buge    schedule 11.05.2015
comment
@Buge Не в том смысле, который здесь обсуждается. В C, как вы, наверное, знаете, можно передать указатель на ЧТО-НИБУДЬ, включая указатель на местоположение переменной (не значение переменной, ее местоположение, указатель на указатель). Результат можно использовать как ссылку, то есть как возможность модифицировать то, на что указывала исходная переменная. Таким образом, написать функцию подкачки на языке C очень просто. Любой, кто пришел из C (или C++, C# и т. д.) и пытается написать функцию подкачки на Java так же, как это было бы в языке C, обнаруживает, что она может нельзя делать (так).   -  person ToolmakerSteve    schedule 09.09.2015
comment
Этот вопрос не имеет особого смысла без данного контекста. В каком контексте вам понадобится такая функция подкачки в java?   -  person SpaceTrucker    schedule 22.02.2016


Ответы (19)


Вот один трюк:

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);
}
person Eng.Fouad    schedule 29.10.2013
comment
Вы бы наняли кого-то, кто будет писать такой непонятный код? Может быть, если бы они тогда объяснили, почему они никогда не будут делать это в рабочем коде. - person ToolmakerSteve; 09.09.2015
comment
плюс один за хитрость, минус один за то, что его нельзя широко использовать в производстве без хорошего объяснения. Его нельзя заключить в отдельный метод, не так ли? - person Bart; 24.02.2016
comment
См. здесь stackoverflow.com/questions/1363186/, чтобы узнать, как он работает. - person marcus; 06.04.2017
comment
Спасибо тебе за это. Не имея Java в качестве основного языка в течение долгого времени, я неправильно понял часть грамматики. Я думал, что одно отличие Java от C/C++ состоит в том, что присваивания не являются выражениями. На самом деле, изменение заключалось в том, что в Java появился правильный логический тип, который нельзя использовать взаимозаменяемо с целыми числами, поэтому вы не можете использовать присваивание в операторе if, которое не возвращает логическое значение. Присваивания возвращают любой тип, задействованный в присваивании, и они возвращают правую часть выражения присваивания. - person froggythefrog; 22.11.2018
comment
@GabrielŠčerbák Я хотел бы сделать оговорку, что если сотрудник, который использует это, может выразить это таким образом, что ясно, что выполняется обмен, то ему следует поаплодировать. Недостатком этого решения является обратная сторона попытки сделать функцию подкачки в Java в первую очередь. На самом деле вы не можете поменять местами базовые типы, не вставив их сначала в объект или массив. :/ - person froggythefrog; 22.11.2018

Сортировка двух целых чисел

Короткий ответ: вы не можете этого сделать, в java нет указателей.

Но вот что-то подобное можно сделать:

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

Вы можете сделать это со всеми типами контейнерных объектов (например, коллекциями и массивами или пользовательскими объектами со свойством int), но только не с примитивами и их оболочками (поскольку все они неизменяемы). Но, думаю, единственный способ сделать это однострочным - это использовать AtomicInteger.

Кстати: если ваши данные представляют собой список, лучшим способом обмена является использование 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[]

по-видимому, настоящая цель - отсортировать массив целых чисел. Это однострочник с 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;
}
person Sean Patrick Floyd    schedule 02.09.2010
comment
Поскольку я использую некоторые алгоритмы сортировки, у меня есть массив целых чисел. Нужно ли мне приводить обычные целые числа к AtomicInteger перед вызовом swap? - person Melinda; 02.09.2010
comment
если вы хотите отсортировать массив целых чисел, используйте Arrays.sort() download.oracle.com/javase/6/docs/api/java/util/ - person Sean Patrick Floyd; 02.09.2010
comment
Кстати, нет способа привести примитивный тип к объекту, но у AtomicInteger есть конструктор с типом int - person Sean Patrick Floyd; 02.09.2010
comment
@Melinda: Arrays.sort - это ответ, но если вы хотите поменять местами два простых значения, следуйте старому хорошему методу: int aux = b; b = a; a = aux; - person helios; 02.09.2010
comment
Но не всегда нужно сортировать только целые числа, не говоря уже о сортировке только примитивов. Реальный ответ всегда будет работать в Java - это ваш метод подкачки с использованием сеттеров и геттеров. Это сработало для меня и очень помогло, спасибо. - person Benjamin R; 22.10.2014

Вот способ замены двух переменных в java всего в одной строке с помощью побитового оператора XOR(^).

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

person Prateek Joshi    schedule 12.01.2016
comment
потому что это не отвечает на вопрос. речь идет о независимой функции, которая может принимать две переменные в качестве аргумента и менять их местами. - person mightyWOZ; 20.08.2016

Используйте эту однострочную строку для любого класса примитивных чисел, включая double и float:

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

person Oleg Mikhailov    schedule 17.05.2016

В Java нет указателей. Однако каждая переменная, которая «содержит» объект, является ссылкой на этот объект. Чтобы иметь выходные параметры, вам пришлось бы использовать объекты. В вашем случае объекты Integer.

Таким образом, вам нужно будет создать объект, содержащий целое число, и изменить это целое число. Вы не можете использовать класс Integer, так как он неизменяем (т.е. его значение нельзя изменить).

В качестве альтернативы можно позволить методу возвращать массив или пару целых чисел.

person Sjoerd    schedule 02.09.2010
comment
Целочисленные объекты неизменяемы, так что это тоже не сработает. - person Michael Borgwardt; 02.09.2010
comment
Целые числа не помогут, они неизменяемы. Вам нужен контейнер, либо AtomicInteger (см. мой ответ), либо список из 1 элемента, либо массив, либо что-то в этом роде. - person Sean Patrick Floyd; 02.09.2010
comment
Опять же, объекты Integer будут передаваться по значению. Это тоже не сработает. javaworld.com/javaworld/javaqa/2000- 05/03-qa-0526-pass.html - person Lunivore; 02.09.2010
comment
@Lunivore: нет, Integer объекты не передаются по значению. Их вообще не пропускают. Ссылка на Integer объект будет передана по значению. Вы можете передавать только ссылки и примитивные значения в Java, но не объекты! - person Joachim Sauer; 02.09.2010
comment
Прости. Мне было лень, и ваше описание гораздо точнее. В свою защиту скажу, что URL очень хорошо объясняет это даже для объектов, которые не являются неизменяемыми. - person Lunivore; 02.09.2010

В таких случаях есть быстрое и грязное решение с использованием массивов с одним элементом:

public void swap(int[] a, int[] b) {
  int temp = a[0];
  a[0] = b[0];
  b[0] = temp;
}

Конечно, ваш код должен работать и с этими массивами, что неудобно. Трюк с массивом более полезен, если вы хотите изменить локальную конечную переменную из внутреннего класса:

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]);   
} 
person Landei    schedule 02.09.2010

А как насчет могучего 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;
}
person PowerApp101    schedule 15.09.2015

Фрагмент-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;
person Andreas Dolk    schedule 02.09.2010
comment
Истинный. И даже интересно. Но это больше кодирование, чем встроенная подкачка с использованием временной переменной. Возможно, было бы неплохо указать, что если программист хочет переносить два значения в какой-то объект, тогда их можно поменять местами внутри этого объекта. Однако я не могу придумать никаких алгоритмов, где это помогло бы на практике. - person ToolmakerSteve; 09.09.2015

Java использует передачу по значению. Невозможно поменять местами два примитива или объекты с помощью метода.

Хотя можно поменять местами два элемента в целочисленном массиве.

person codaddict    schedule 02.09.2010
comment
Невозможно поменять местами два объекта, передав их методу в качестве параметров, а не только примитивы. - person Lunivore; 02.09.2010
comment
@Lunivore Я думал, что объекты передаются по ссылке. Итак, в таком случае, почему вы не могли поменяться их ссылками? - person Cristian; 02.09.2010
comment
@Cristian: неверно: объекты Java - это ссылки, которые передаются по значению. это разница - person Sean Patrick Floyd; 02.09.2010
comment
@seanizer спасибо за разъяснение! - person Cristian; 02.09.2010
comment
C также использует передачу по значению, только C++ имеет передачу по ссылке. Даже в приведенном примере он передает значение обоих указателей. Вот почему отсутствие передачи по ссылке не имеет ничего общего с этим ограничением в Java. - person Trinidad; 27.01.2017

Вы не можете использовать ссылки в 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;
}
person Ming-Tang    schedule 02.09.2010
comment
Это полезное наблюдение. - person ToolmakerSteve; 09.09.2015

Вы должны сделать это в режиме онлайн. Но вам действительно не нужен этот обмен в Java.

person Bart    schedule 02.09.2010
comment
Не уверен, почему за это проголосовали, поскольку это действительно точно. Если у вас есть эти два значения и вы хотите поменять их местами, вы можете встроить метод, и он отлично работает, но я согласен, я действительно не понимаю, зачем он вам нужен в Java. - person Lunivore; 02.09.2010
comment
Спасибо. Я тоже был удивлен. Это может быть слишком лаконично, но код указывает на C-подобный стиль кодирования, который совершенно не подходит для Java. - person Bart; 02.09.2010
comment
Широкое заявление типа «Вам действительно не нужен этот своп в Java» заслуживает отрицательного голоса. Полезность свопа как концепции программирования неоспорима. Существует множество алгоритмов, в которых swap является ключевым шагом. Если Барт не хочет, чтобы его голосовали против, ему нужно предоставить альтернативное решение для ситуаций, когда swap традиционно используется в алгоритмах (как это делают некоторые другие ответы, хотя и не полностью). - person ToolmakerSteve; 09.09.2015

Ваша функция подкачки по существу меняет значения в двух частях памяти. Все, что ссылается на эти биты памяти, теперь получит разные значения.

В Java на самом деле нет указателей, так что это не сработает. Вместо этого ссылки хранятся на объектах, и вы можете изменять только вещи внутри объектов. Если вам нужно сослаться на один объект в двух местах, чтобы вы могли передавать одни и те же значения по системе и чтобы все реагировало на их изменение, попробуйте что-то вроде шаблон репозитория или внедрение зависимостей.

Мы можем только догадываться, зачем вам понадобился этот код на C. Единственный совет, который я могу дать, — подумать об изменениях объектов, которых вы хотите добиться, желательно добавить метод к реальным объектам, а не вытаскивать их внутренности, и вместо этого вызовите этот метод. Если это вам не поможет, попробуйте опубликовать вызывающий код, так как у нас, вероятно, будет хорошее представление о том, как решить реальную проблему в стиле Java.

person Lunivore    schedule 02.09.2010

Java передается по значению. Так что swap в том смысле, который вы имеете в виду, невозможен. Но вы можете поменять местами содержимое двух объектов или сделать это встроенным.

person fastcodejava    schedule 02.09.2010

Вы можете поменять местами переменные с использованием или без использования временной переменной.

Вот статья, которая предоставляет несколько методов для обмена числами без временной переменной:

http://topjavatutorial.com/java/java-programs/swap-two-numbers-without-a-temporary-variable-in-java/

person Sekhar Ray    schedule 04.02.2016

Вы можете легко написать его самостоятельно.

данный:

int array[]={1,2};

вы делаете:

int temp=array[0];
array[0]=array[1];
array[1]=temp;

И вы сделали. 3 строки кода.

person Yunus Seçgin    schedule 21.08.2013
comment
Это не работает. Вам нужно прочитать вопрос более внимательно и прочитать некоторые другие ответы. - person Andrew Martin; 22.08.2013
comment
Старайтесь делать это осторожно @AndrewMartin. Потому что я работал без каких-либо проблем. - person Yunus Seçgin; 23.08.2013
comment
Вы упустили суть вопроса. ОП спрашивал, как сделать обмен в методе как в C. Java не может сделать это, так как передается по значению. Если в методе выполняется обмен, он не может быть сохранен (если не возвращаются значения). Если бы в метод были переданы два значения и ваш код был выполнен, он не сохранил бы результаты из метода. Прочитайте вопрос против и некоторые другие ответы. - person Andrew Martin; 23.08.2013

Обмен с помощью указателя не возможен в java. Однако вы можете реализовать замену путем передачи массива, содержащего два объекта.

Код выглядит следующим образом:

public class Swap {
    public static void swap(String [] a){
        String temp;
        temp = a[0];
        a[0] = a[1];
        a[1] = temp;
    }
    public static void main(String [] args){
        String [] foo = new String[2];
        foo[0] = "str1";
        foo[1] = "str2";
        swap(foo);
        System.out.println("First value: "+ foo[0]);
        System.out.println("Second value: "+ foo[1]);
    }
}

Вывод:

First value: str2
Second value: str1
person Nabin Bhandari    schedule 31.05.2016

person    schedule
comment
Пожалуйста, попробуйте включить комментарии/объяснения в свой код, чтобы помочь другим понять его лучше. - person user2004685; 22.02.2016

person    schedule
comment
Это выглядит немного головокружительно, но это просто не ООП. Надеюсь, это тоже поможет. - person Tepken Vannkorn; 08.12.2010
comment
x и y не определены, и это не замена переданных переменных. - person Lie Ryan; 08.12.2010
comment
Это не ответ на вопрос. Это не то, что означает замена двух переменных в информатике. Вместо этого это изменяет значение двух членов. Даже не близко. - person ToolmakerSteve; 09.09.2015

person    schedule
comment
вопрос в том как написать функцию подкачки на java а не как сделать swap в java - person Muthu Ganapathy Nathan; 14.08.2011