Общий примитивный тип с кастингом - PullRequest
0 голосов
/ 11 июня 2018

У меня проблема с моим кодом Java.Я хочу сделать мой метод универсальным с использованием обобщенных типов.Проще объяснить это с помощью кода:

public interface Destroyable {

    void destroy();

    default void destroyArray(byte[] array) {
        Arrays.fill(array, (byte)0);
    }

    default void destroyArray(char[] array) {
        Arrays.fill(array, (char)0);
    }

}

Дело в том, что я хочу, чтобы мой метод по умолчанию destroyArray работал с любым типом, например так:

public interface Destroyable {

    void destroy();

    default <E> void destroyArray(Class<E>[] array) {
        Arrays.fill(array, (E)0);
    }

}

Это дает мне ошибку:

Необратимые типы;не может привести 'int' к 'E'

Есть ли простое решение для достижения этой цели?

Ответы [ 3 ]

0 голосов
/ 11 июня 2018
default <E> void destroyArray(E[] array) {
    Arrays.fill(array, null);
}

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

Кроме того, destroyArray, похоже, не принадлежит Destroyable.Разве это не должно быть просто во вспомогательном классе, полном статических методов?На вашем месте я бы перенес его туда.Он даже не вызывает метод destroy, поэтому у него нет причин находиться в Destroyable.

0 голосов
/ 11 июня 2018

Ваш оригинальный подход со многими перегруженными методами вполне подходит.

Для примитивных типов обобщенные типы будут работать для их массивов как:

default <A> void destroyArray(A array) {
    Class<?> arrayType = array.getClass();
    if (!arrayType.isArray()) {
        return;
    }
    Class<?> type = arrayType.getComponentType();
    if (type == int.class) {
        Arrays.fill((int[])array, 0);
    } else if (type == char.class) {
        Arrays.fill((char[])array, '\0');
    }
    //...
}

Как вы можетеПонимаете: это вряд ли более компактно, медленнее и менее безопасно для типов, а также защищено забытыми примитивными типами.

0 голосов
/ 11 июня 2018

Значение по умолчанию для объектов

Проблема с вашим кодом:

default <E> void destroyArray(E[] array) {
    Arrays.fill(array, (E) 0);
}

заключается в том, что общий тип E, конечно, не обязательно int (или что-то, что можетбыть автоматически упакованным как Integer).Но вы на самом деле хотите написать какое-то значение по умолчанию .Поэтому вам необходимо создать действительные экземпляры E.Что, в общем, сложно, потому что вы ничего не знаете о типе, включая его конструкторы.

Однако для всех Object есть одно допустимое значение, а именно null.Это означает, что в данный момент просто нет экземпляра.

Таким образом, следующее будет работать для произвольных типов E:

default <E> void destroyArray(E[] array) {
    Arrays.fill(array, null);
}

Примитивы

Однакопри этом вы по-прежнему не можете заполнять массивы примитивного типа, например int[], поскольку E можно использовать только для Object s, но не для примитивов.Вам нужно было бы жестко закодировать дополнительные методы для каждого примитива:

default void destroyArray(int[] array) {
    Arrays.fill(array, 0);
}

default void destroyArray(double[] array) {
    Arrays.fill(array, 0.0);
}

// ...

Примечание к Class<E>

Ваш исходный код имел Class<E>[] вместо E[].Обратите внимание, что Class<E> означает что-то совершенно иное, чем E[].

Class<E> - это объект Class, оболочка, обеспечивающая доступ Reflection-API к для анализа содержимого класса ,Как получить имена методов и тому подобное.Принимая во внимание, что E - это сам класс.

Таким образом, Person будет Person классом, а Class<Person> подобен классу, который знает что-то о классе Person, например, имена его методов.

См. документацию из Class для получения более подробной информации.

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