Як зробити метод Java Generic статичним?


172

Далі наведено фрагмент про те, як зробити загальний клас java для додавання одного елемента до масиву. Як я можу зробити appendToArray статичним методом. Додавання статики до підпису методу призводить до помилок компіляції.

public class ArrayUtils<E> {

        public E[] appendToArray(E[] array, E item) {
            E[] result = (E[])new Object[array.length+1];
            result[array.length] = item;
            return result;
        }
}

Які помилки компіляції ви отримуєте? Крім того, чому б не просто використовувати один із стандартних бібліотечних контейнерів?
Карл Кнечтел

1
Помилка компіляції: я фактично додавав статичний модифікатор неправильно. Використання колекцій: Так, використання колекції було б ідеально, але питання не про колекції проти масиву, мій випадок використання вимагає масиву.
Кріс Джонсон

Зауважте, що вам потрібно використовувати відображення (EVIL), щоб зупинити скидання коду клієнта у деяких, але не у всіх обставинах (приємно). Краще уникати референтних масивів.
Том Хотін - тайклін

Відповіді:


283

єдине, що ви можете зробити - це змінити свій підпис на

public static <E> E[] appendToArray(E[] array, E item)

Важливі деталі:

Загальні вирази, що передують поверненному значенню, завжди вносять (оголошують) нову змінну загального типу.

Крім того, змінні типу між типами ( ArrayUtils) та статичними методами ( appendToArray) ніколи не заважають один одному.

Отже, що ж це означає: У моїй обороні <E>приховати б Eвід , ArrayUtils<E>якщо метод не буде static. І <E>не має нічого спільного з Eз ArrayUtils<E>.

Для кращого відображення цього факту правильнішою була б відповідь:

public static <I> I[] appendToArray(I[] array, I item)

30
Будь ласка, майте на увазі, що між змінною типу класу рівня Eта змінною типу статичного методу абсолютно не існує зв'язку E. Я вважаю набагато кращою практикою використовувати інше ім'я змінної при оголошенні загальних методів, статичних чи інших способів, всередині загальних класів.
Суддя ментальних

але в цьому випадку я можу передавати в парами один об'єкт різного типу. Можливо, я можу передати масив Integer [] як перший парам і подвійний елемент.
pinkpanther

pinkpanther: Правда, але це не приносить ніякої шкоди, оскільки статичний метод оперує лише коли-небудь об'єктом масиву, який передається йому через параметр, тому його елементи, безумовно, мають правильний тип.
Даблер

80
public static <E> E[] appendToArray(E[] array, E item) { ...

Зверніть увагу на <E>.

Статичним родовим методам потрібна своя родова декларація ( public static <E>) окремо від загальної декларації класу ( public class ArrayUtils<E>).

Якщо компілятор скаржиться на неоднозначність типу при виклику статичного загального методу (знову ж не вірогідно у вашому випадку, але, загалом кажучи, про всяк випадок), ось як явно викликати статичний загальний метод, використовуючи певний тип ( _class_.<_generictypeparams_>_methodname_):

String[] newStrings = ArrayUtils.<String>appendToArray(strings, "another string");

Це станеться лише в тому випадку, якщо компілятор не може визначити загальний тип, оскільки, наприклад, загальний тип не пов'язаний з аргументами методу.


10

Вам потрібно перемістити параметр типу на рівень методу, щоб вказати, що у вас є загальний метод, а не загальний клас:

public class ArrayUtils {
    public static <T> E[] appendToArray(E[] array, E item) {
        E[] result = (E[])new Object[array.length+1];
        result[array.length] = item;
        return result;
    }
}

1
Це не спрацює, оскільки ви не визначили загальний тип E. У цьому випадку вам все одно повинен бути загальний тип <E> у визначенні класу.
Джордж Ксав'є

0

Я поясню це простим способом.

Генерики, визначені на рівні класу, повністю відокремлені від дженериків, визначених на рівні (статичного) методу.

class Greet<T> {

    public static <T> void sayHello(T obj) {
        System.out.println("Hello " + obj);
    }
}

Коли ви бачите вищезазначений код де завгодно, зауважте, що T, визначений на рівні класу, не має нічого спільного з T, визначеним статичним методом. Наступний код також є повністю дійсним і еквівалентним вищевказаному коду.

class Greet<T> {

    public static <E> void sayHello(E obj) {
        System.out.println("Hello " + obj);
    }
}

Чому статичному методу потрібно мати власні дженерики, окремі від класів?

Це тому, що статичний метод можна викликати, навіть не ініціюючи клас. Тож якщо Клас ще не встановлений, ми ще не знаємо, що таке Т. Це причина, чому статичним методам потрібно мати власні дженерики.

Отже, кожного разу, коли ви викликаєте статичний метод,

Greet.sayHello("Bob");
Greet.sayHello(123);

JVM трактує це наступним чином.

Greet.<String>sayHello("Bob");
Greet.<Integer>sayHello(123);

Обидва дають однакові результати.

Hello Bob
Hello 123
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.