Передача динамического списка примитивов в метод Java - PullRequest
2 голосов
/ 02 декабря 2011

Мне нужно передать динамический список примитивов в метод Java.Это может быть (int, int, float) или (double, char) или что-то еще.Я знаю, что это невозможно, поэтому я думал о правильных решениях этой проблемы.

Поскольку я занимаюсь разработкой игры для Android, в которой я хочу максимально избегать сбора мусора, я не хочу использоватьлюбые объекты (например, из-за автоматического бокса), но только примитивные типы данных.Таким образом, коллекция или массив объектов примитивного класса (например, Integer) не является опцией в моем случае.

Поэтому я подумал, могу ли я передать объект класса в мой метод, который будет содержать все примитивные вейлы, которые янеобходимость.Однако это не является решением моей проблемы, потому что, как сказано, список примитивов является переменным.Поэтому, если бы я пошел по этому пути в своем методе, я бы тогда не знал, как получить доступ к этому динмическому списку примитивов (по крайней мере, без преобразования в объекты, чего я хочу избежать).

ТеперьЯ чувствую себя немного потерянным здесь.Я не знаю другого возможного пути в Java, как решить мою проблему.Я надеюсь, что это просто недостаток знаний на моей стороне.Кто-нибудь из вас знает решение без преобразования в и из объектов?

Ответы [ 6 ]

1 голос
/ 02 декабря 2011

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

Концептуально, вы пытаетесь сделать что-то, что всегда сложно на любом языке, который передает параметры в управляемый стек. Что вы ожидаете от плохого компилятора? Либо он позволяет выдвинуть произвольное количество аргументов в стек и получить к ним доступ с помощью некоторой арифметики указателя стека (хорошо в C, которая позволяет вам играть с указателями сколько угодно, не так хорошо в управляемом языке, таком как Java), или это будет необходимо передать ссылку на хранилище в другом месте (что подразумевает выделение или некоторую форму буфера).

К счастью, в Java есть несколько способов эффективной передачи примитивных параметров. Вот мой список наиболее перспективных подходов, примерно в порядке их рассмотрения:

  • Перегрузка - есть несколько методов с разными примитивными аргументами для обработки всех возможных комбинаций. Вероятно, будет лучшим / самым простым / наиболее легким вариантом, если имеется относительно небольшое количество аргументов. Также отличная производительность, так как компилятор будет статически определять, какой перегруженный метод вызывать.
  • Примитивные массивы - Хороший способ передачи произвольного числа примитивных аргументов. Обратите внимание, что вам, вероятно, нужно будет хранить массив примитивов в качестве буфера (в противном случае вам придется распределять его при необходимости, что противоречит вашей цели избежать выделения!). Если вы используете частично заполненные массивы примитивов, вам также нужно будет передать в массив аргументы offset и / или count.
  • Передача объектов с примитивными полями - работает хорошо, если набор примитивных полей относительно хорошо известен заранее. Обратите внимание, что вам также нужно будет хранить экземпляр класса в качестве буфера (в противном случае вам придется выделять его при необходимости, что противоречит вашей цели избежать выделения!).
  • Использовать специализированную библиотеку примитивных коллекций - например, библиотека Trove . Отличная производительность и избавляет вас от необходимости писать много кода, так как это, как правило, хорошо разработанные и поддерживаемые библиотеки. Довольно хороший вариант, если эти коллекции примитивов будут долгоживущими, то есть вы не создаете коллекцию исключительно для передачи некоторых параметров.
  • NIO Buffers - примерно эквивалентно использованию массивов или примитивных коллекций с точки зрения производительности. Они имеют некоторые издержки, но могут быть лучше, если вам нужны буферы NIO по другой причине (например, если примитивы передаются в сетевом коде или коде библиотеки 3D, которые используют те же типы буфера, или если данные должны передаваться в / из нативного кода). Они также обрабатывают смещения и рассчитывают для вас, что может быть полезным.
  • Генерация кода - написать код, который генерирует соответствующий байтовый код для специализированных примитивных методов (либо раньше, либо динамически). Это не для слабонервных, но это один из способов получить абсолютно оптимальную производительность. Вы, вероятно, захотите использовать библиотеку, подобную ASM , или в качестве альтернативы выбрать язык JVM, который может легко выполнить генерацию кода для вас (на ум приходит Clojure).
0 голосов
/ 02 декабря 2011

Fwiw, что-то вроде sum (int ... numbers) не будет автоматически вставлять целые числа. Было бы создать один int [] для их хранения, поэтому было бы выделение объекта; но это не было бы по int.

public class VarArgs {
    public static void main(String[] args) {
        System.out.println(variableInts(1, 2));
        System.out.println(variableIntegers(1, 2, 3));
    }   

    private static String variableInts(int... args) {
        // args is an int[], and ints can't have getClass(), so this doesn't compile
        // args[0].getClass();
        return args.getClass().toString() + " ";
    }   

    private static String variableIntegers(Integer... args) {
        // args is an Integer[], and Integers can have getClass()
        args[0].getClass();
        return args.getClass().toString();
    }   
}

выход:

class [I 
class [Ljava.lang.Integer;
0 голосов
/ 02 декабря 2011

Вы также можете привести все свои примитивы к double, а затем просто передать массив double.Единственная хитрость в том, что вы не можете использовать тип boolean.

0 голосов
/ 02 декабря 2011

Вы можете использовать BitSet аналогично битовому полю C ++. http://docs.oracle.com/javase/1.3/docs/api/java/util/BitSet.html

0 голосов
/ 02 декабря 2011

Попробуйте использовать оператор ...:

static int sum (int ... numbers)
        {
           int total = 0;
           for (int i = 0; i < numbers.length; i++)
                total += numbers [i];
           return total;
        }
0 голосов
/ 02 декабря 2011

Там просто нет. Единственный способ иметь переменную число параметров в методе - это использовать оператор ..., который не поддерживает примитивы. Все дженерики также поддерживают только примитивы.

Единственное, о чем я могу подумать, это такой класс:

class ReallyBadPrimitives {
    char[] chars;
    int[] ints;
    float[] floats;
}

И изменяйте размеры массивов по мере их добавления. Но это ДЕЙСТВИТЕЛЬНО, ДЕЙСТВИТЕЛЬНО плохо, поскольку вы теряете в основном ВСЕ ссылочную целостность в вашей системе.

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

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