Можете ли вы передать массив int в общий метод в Java? - PullRequest
6 голосов
/ 25 апреля 2009

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

Два вопроса,

# 1 Могу ли я избежать приведения к T в splitBottom и splitTop? Это не правильно, или я поступаю неправильно (не говорите мне использовать python или что-то в этом роде;;))

# 2 Нужно ли писать отдельные методы для работы с примитивными массивами или есть лучшее решение?

public class Util {

    public static <T> void print(T[] array) {
        System.out.print("{");
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i]);
            if (i < array.length - 1) {
                System.out.print(", ");
            }
        }
        System.out.println("}");
    }

    public static <T> T[] splitTop(T[] array, int index) {
        Object[] result = new Object[array.length - index - 1];
        System.arraycopy(array, index + 1, result, 0, result.length);
        return (T[]) result;
    }

    public static <T> T[] splitBottom(T[] array, int index) {
        Object[] result = new Object[index];
        System.arraycopy(array, 0, result, 0, index);
        return (T[]) result;
    }

    public static void main(String[] args) {

        Integer[] integerArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        print(integerArray);
        print(splitBottom(integerArray, 3));
        print(splitTop(integerArray, 3));

        String[] stringArray = {"one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"};
        print(stringArray);
        print(splitBottom(stringArray, 3));
        print(splitTop(stringArray, 3));

        int[] intArray = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
        // ???
    }
}

Ответы [ 6 ]

9 голосов
/ 25 апреля 2009

Дженерики не обрабатывают примитивы согласованным образом. Это потому, что Generics не похожи на шаблоны в C ++, это всего лишь дополнение времени компиляции к одному классу.

Когда универсальный компилируется, вы получите Object [] в приведенном выше примере в качестве реализующего типа. Так как int [] и byte [] и т. Д. Не расширяют Object [], вы не можете использовать их взаимозаменяемо, даже если соответствующий код будет идентичен (опять же, дженерики не являются шаблонами)

Единственный общий доступ к классам int [] и Object [] - это Object. Вы можете написать вышеупомянутые методы Object как тип (см. System.arraycopy, Array.getLength, Array.get, Array.set)

3 голосов
/ 25 апреля 2009

1 Могу ли я избежать приведения к T в splitBottom и splitTop? Это не чувствую себя хорошо, или я собираюсь об этом неправильный путь (не говорите мне использовать питон или что-то ..;))

Мало того, что вы не можете избежать этого, но вы не должны этого делать. В Java разные типы массивов фактически являются разными типами среды выполнения. Массив, созданный как Object[], не может быть назначен переменной AnythingElse []. Приведение там не будет завершено немедленно, потому что в обобщенных типах тип T стирается, но позже он генерирует исключение ClassCastException, когда код пытается использовать его как Something [], как вы их обещали, но это не так.

Решением является либо использование методов Arrays.copyOf... в Java 6 и более поздних версиях, либо, если вы используете более раннюю версию Java, используйте Reflection для создания правильного типа массива. Например,

T [] result = (T []) Array.newInstance (array.getClass (). GetComponentType (), size);

2 Должен ли я написать отдельные методы для работы с примитивными массивами или есть лучшее решение?

Вероятно, лучше всего написать отдельные методы. В Java массивы примитивных типов полностью отделены от массивов ссылочных типов; и нет хорошего способа работать с ними обоими.

Можно использовать Отражение, чтобы иметь дело с обоими одновременно. В Reflection есть методы Array.get() и Array.set(), которые будут работать как с простыми, так и с эталонными массивами. Однако вы теряете безопасность типов, делая это, поскольку единственным супертипом как примитивных массивов, так и эталонных массивов является Object.

1 голос
/ 25 апреля 2009

Java не позволяет создавать универсальные массивы безопасным для типов образом. Вместо этого используйте общий тип последовательности (например, java.util.List).

Вот как я бы написал вашу тестовую программу, используя общий контейнерный класс fj.data.Stream:

import fj.data.Stream;
import static fj.data.Stream.range;

// ...

public int[] intArray(Stream<Integer> s) {
  return s.toArray(Integer.class).array()
}

public static void main(String[] args) {
  Stream<Integer> integerStream = range(1, 10);
  print(intArray(integerStream));
  print(intArray(integerStream.take(3)));
  print(intArray(integerStream.drop(3)));

  // ...
}
1 голос
/ 25 апреля 2009

Вопрос 1: Приведение массивов не работает так, как вы ожидаете. String - это Object, но массив String не является массивом Object.

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

public static <T> T[] splitTop(T[] array, int index) {
    T[] result = Arrays.copyOfRange(array, index + 1, array.length);
    return result;
}

Вопрос 2: Для массивов примитивов моя функция, очевидно, тоже не работает. Нет элегантного решения - посмотрите, например, на библиотеку Arrays, в которой есть несколько копий одного и того же метода для каждого типа примитивного массива.

0 голосов
/ 04 февраля 2014

Возможно, вам придется обернуть примитивы в соответствующие коллекции.

Я также предлагаю взглянуть на примитивные коллекции Trove (http://trove.starlight -systems.com ). Это не связано с вашим вопросом об общих, но может быть довольно интересным.

0 голосов
/ 25 апреля 2009

У вас есть две проблемы с тем, чего вы пытаетесь достичь.

Прежде всего, вы пытаетесь использовать примитивные типы, которые на самом деле не наследуются от Object. Это испортит вещи. Если вам действительно нужно это сделать, явно используйте Integer, а не int и т. Д.

Вторая и более серьезная проблема заключается в том, что у дженериков Java есть стирание типов. Это означает, что во время выполнения вы не можете ссылаться на тип универсального. Это было сделано для того, чтобы вы могли смешивать общий и не поддерживающий общий код, и в конечном итоге (IMHO) стал основным источником головной боли для разработчиков Java и еще одним доказательством того, что дженерики должны были быть в Java с первого дня. Прочтите об этом часть в уроке , она прояснит этот вопрос.

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