Java - эффективный способ доступа к массиву - PullRequest
1 голос
/ 15 ноября 2011

Прошло некоторое время с тех пор, как я последний раз программировал на Java, но мне нужен небольшой совет.У нас есть простая функция - обратите внимание, что это C:

void update(double *source, double *target, int n) {
      for(int i = 0; i < n; ++i)
            target[i] = source[i] * i; // well, actually a bit more complicated, just some kind of calculation
}

Итак, теперь мне нужно эффективно перекодировать эту функцию в Java.Мои проблемы:

  • В Java, конечно, нет указателей, так как я могу эффективно передавать массивы без большого количества операций копирования памяти из-за вызова по значению
  • Какая структура данныхЛучше всего хранить массивы

Обратите внимание, что источником и целью являются большие массивы, хранящие до 1 миллиона элементов

Ответы [ 6 ]

6 голосов
/ 15 ноября 2011

В Java это почти одно и то же:

static void update(double[] source, double[] target, int n)
{
    for (int i = 0; i < n; i++)
        target[i] = source[i] * i;
}

Вы не копируете память.Когда вы передаете массив в эту функцию, он передает ссылку на массив по значению .

В общем случае Java передает аргументы функции по значению.Но в случае массивов и пользовательских классов объекты, с которыми вы имеете дело, всегда являются ссылочными типами.Поэтому вызовы функций для классов и массивов всегда передают ссылку на класс / массив по значению.

Так что если у вас есть класс, который выглядит следующим образом:

class Foo
{
  int[] A; // For arguments say let's say this contains 1 million items always
}

, и у вас есть функция,может вызвать его:

static void Bar(Foo f)
{
    ....
}

Он передает только ссылку на Foo, он вообще не копирует данные.

2 голосов
/ 15 ноября 2011

Массивы передаются по ссылке (значение ссылки передается). Так что не будет никакой новой копии массива.

Код будет довольно похож:

void update(double source[], double target[], int n)
{
    for (int i = 0; i < n; i++)
        target[i] = source[i] * i;
}

Что вы подразумеваете под «структурой данных для массива»? Сам массив является структурой данных. В любом случае вам необходимо получить доступ к каждому элементу для типа операции, которую вы пытаетесь выполнить. Так что сам массив - хорошая структура данных. Вы можете посмотреть на ArrayList .

1 голос
/ 15 ноября 2011

Как уже отмечали некоторые другие, by-ref / by-value - это вещь C / C ++ и не применима к Java.

Теперь, если вы не делаете какое-то реальное собственное кодирование, передавая эти массивы C / C ++ в / из Java:

Учитывая, что в коде C массив передается как указатель (void update(double *source, double *target, int n)), я предполагаю, что его размер является динамическим, в таком случае ваша подпись в Java должна быть void update(List<Double> source, List<Double> target, int n). Пусть вызывающий абонент решит, является ли он ArrayList или Vector или LinkedList или ...

Но если вы в какой-то JNI (передавая эти массивы C / C ++ в / из Java), то, возможно, нам нужно рассмотреть другие аспекты.

1 голос
/ 15 ноября 2011

Спецификация Java говорит, что все в Java передается по значению.В Java нет такой вещи, как «передача по ссылке».Но не обманывайтесь этим, внутренняя работа довольно сложна, и вы можете фактически манипулировать массивами так, как вам хочется.Параметры эталонного типа данных, такие как объекты, также передаются в методы по значению.Это означает, что когда метод возвращается, переданная ссылка все еще ссылается на тот же объект, что и раньше.Однако значения полей объекта могут быть изменены в методе, если они имеют надлежащий уровень доступа.

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

код для использования похож и прост:

void update(double source[], double target[], int n)
{
    for (int i = 0; i < n; i++)
        target[i] = source[i] * i;
}

Чтобы лучше понять, что я упомянул, взгляните на этот вопрос: Является ли Java "передачей по ссылке" или "передачей по значению"?

Что касается вашего вопроса о структурах данных, используйте массив.Глядя на ваш фрагмент, становится ясно, что вам нужен произвольный доступ, поэтому просто придерживайтесь хороших старых массивов ..

1 голос
/ 15 ноября 2011

Java использует семантику вызовов по объектам, поэтому копирование отсутствует.

1 голос
/ 15 ноября 2011

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

В противном случае рассмотрим ArrayList .Но они намного дороже, как по скорости, так и по размеру, потому что каждый дубль "упакован" в объект Double.

Третий вариант - использовать соответствующий класс списка с изменяемым размером из библиотеки с высокопроизводительными примитивными коллекциями, например Trove's TDoubleArrayList .

Вопрос, который вы не задавали't спрашивает, будет ли Java использовать какие-либо соответствующие SIMD функции вашего процессора для простого цикла, подобного этому.И я рад, что ты не сделал, потому что я не знаю.Но я вполне уверен, что если достаточно достаточно умный, чтобы использовать их, то это будет только для простых массивов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...