Создание нового массива с объектом класса в GWT - PullRequest
4 голосов
/ 11 февраля 2011

Я хотел бы создать новый массив с заданным типом из объекта класса в GWT.

Я имею в виду, что я хотел бы эмулировать функциональность

java.lang.reflect.Array.newInstance(Class<?> componentClass, int size)

Мне нужно, чтобы это произошло, потому что у меня есть библиотека, которая иногда должна делать следующее:

Class<?> cls = array.getClass();
Class<?> cmp = cls.getComponentType();

Это работает, если я передаю ему класс массива нормально, но я не могу динамически создать новый массивот какого-то произвольного типа компонента.

Мне хорошо известно, что у GWT нет отражения;Это я поняла.Тем не менее, это кажется возможным даже с учетом ограниченного отражения GWT.Причина, по которой я считаю, заключается в том, что в реализации существует недоступный статический метод для создания объекта класса для массива.

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

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

Ответы [ 3 ]

4 голосов
/ 25 ноября 2012

Если вы не против создания начального массива правильного типа, вы можете использовать jsni вместе с некоторыми знаниями о супер-супер-источнике для создания массивов БЕЗ копирования через ArrayList (я избегаю издержек java.util, таких как чума):

public static native <T> T[] newArray(T[] seed, int length)
/*-{
return @com.google.gwt.lang.Array::createFrom([Ljava/lang/Object;I)(seed, length);
}-*/;

Где seed - массив нулевой длины нужного вам типа, а length - желаемая длина (хотя в производственном режиме массивы на самом деле не имеют верхних границ, это заставляет поле [] .length работать правильно).

Пакет com.google.gwt.lang представляет собой набор основных утилит, используемых в компиляторе для базовой эмуляции, и находится в gwt-dev! Com / google / gwt / dev / jjs / intrinsic / com / google /gwt/lang.

Вы можете использовать эти классы только через вызовы jsni и только в производственном коде gwt (используйте if GWT.isProdMode ()). В общем, если вы обращаетесь только к классам com.google.gwt.lang в супер-исходном коде, вы гарантированно никогда не потеряете ссылки на классы, которые существуют только в скомпилированном javascript.

if (GWT.isProdMode()){
  return newArray(seed, length);
}else{
  return Array.newInstance(seed.getComponentType(), length);
}

Обратите внимание, что вам, вероятно, потребуется супер-исходный код класса java.lang.reflect.Array, чтобы избежать ошибки компилятора gwt, из-за чего вы захотите поместить туда свой собственный вспомогательный метод. Тем не менее, я не могу помочь вам больше, чем это, поскольку это вышло бы за рамки моего трудового договора.

0 голосов
/ 22 июля 2014

Мне пришлось сделать нечто подобное, я обнаружил, что это возможно, используя класс ObjectArrays библиотеки Guava .Вместо объекта класса требуется ссылка на существующий массив.

T[] newArray = ObjectArrays.newArray(oldArray, oldArray.length);
0 голосов
/ 11 февраля 2011

То, что я сделал подобным образом, было передать пустой массив 0 длины конструктору объекта, из которого нужно создать массив.

public class Foo extends Bar<Baz> {

    public Foo()
    {
        super(new Baz[0]);
    }
...
}

Baz:

public abstract class Baz<T>
{
    private T[] emptyArray;

    public Baz(T[] emptyArray)
    {
        this.emptyArray = emptyArray;
    }
...
}

В этом случае класс Bar не может напрямую создать новый T [10], но мы можем сделать это:

ArrayList<T> al = new ArrayList<T>();

// add the items you want etc

T[] theArray = al.toArray(emptyArray);

И вы получите ваш массив безопасным для типов способом (иначе в вашемвызов super (новый Baz [0]); вызовет ошибку компилятора).

...