Ошибка «недопустимый универсальный тип для instanceof» при использовании локальных классов - PullRequest
61 голосов
/ 16 апреля 2019

У меня есть следующий код Java, который использует локальный класс .

import java.util.Arrays;

public class X<T> {
    void m() {
        class Z {}

        for (Object o : Arrays.asList(1, 2, 3))
            if (o instanceof Z) {}
    }
}

Не компилируется следующее сообщение об ошибке:

X.java:8: error: illegal generic type for instanceof
            if (o instanceof Z) {}
                             ^
1 error

Я понимаю, что локальный класс Z наследует сигнатуру общего типа X<T>, являющуюся внутренним классом. Такая же ошибка компиляции появляется в этом примере, где Z не локально, а по-прежнему внутренне:

import java.util.Arrays;

public class X<T> {
    class Z {}

    void m() {
        for (Object o : Arrays.asList(1, 2, 3))
            if (o instanceof Z) {} // Compilation error
    }
}

Это можно обойти, либо сделав Z не внутренним / статическим:

import java.util.Arrays;

public class X<T> {
    static class Z {}

    void m() {
        for (Object o : Arrays.asList(1, 2, 3))
            if (o instanceof Z) {} // Compiles now
    }
}

Или квалификация X.Z:

import java.util.Arrays;

public class X<T> {
    class Z {}

    void m() {
        for (Object o : Arrays.asList(1, 2, 3)) {
            if (o instanceof X.Z) {}    // Compiles now
            if (o instanceof X<?>.Z) {} // Also
        }
    }
}

Но как я могу квалифицировать локальный класс или обойти это ограничение, не меняя сам локальный класс?

Ответы [ 4 ]

43 голосов
/ 16 апреля 2019

Мне кажется, это упущение или ограничение в языке Java, и я не думаю, что это возможно.

Указанный тип в выражении instanceof должен быть пригоден для повторного использования в соответствии с JLS 4.7 , что означает, что он должен быть выражен как тип reifiable его полностью определенным именем.В то же время, JLS 6.7 утверждает, что локальные классы не имеют полностью определенного имени, поэтому они не могут быть выражены как reifiable.

Если вы объявите Z как универсальный, instanceof оператор обрабатывает Z как необработанный тип, где все его общие свойства - в данном случае включающий класс - также считаются необработанными.(Подобно универсальным методам необработанного типа, рассматриваемым как необработанные, несмотря на какую-либо универсальную сигнатуру. Это является мерой для сохранения обратной совместимости при обобщении типов.) Поскольку любой необработанный тип является переопределимым, объявление Z как универсального будет компилироваться.

28 голосов
/ 16 апреля 2019

Возможный обходной путь - использовать отражение:

import java.util.Arrays;

public class X<T> {
    void m() {
        class Z {}

        for (Object o : Arrays.asList(1, 2, 3))
            if (Z.class.isInstance(o)) {}
    }
}
5 голосов
/ 16 апреля 2019

По-видимому, создание Z-компиляции завершается успешно.Я ожидал, что потребуется <T> в качестве параметра типа, но вы просто должны сделать его универсальным, чтобы что-нибудь делало

import java.util.Arrays;

public class X<T> {
    void m() {
        class Z<Anything> {}

        for (Object o : Arrays.asList(1, 2, 3))
            if (Z.class.isInstance(o)) {}
    }
}

Правильное решение будет квалифицировать локальный класс, но я не думаю, чтовы можете.Либо вы реорганизуете его в закрытый статический класс, либо, возможно, это лучшее, что вы можете получить.

3 голосов
/ 16 апреля 2019

Это тоже должно работать. Используя отражение тоже. Но кажется верным решением.

import java.util.Arrays;

public class X<T> {


    void m() {

        class Z2 {
        }

        for(Object o: Arrays.asList(1,2,3)) {
            if(Z2.class.isAssignableFrom(o.getClass())) {

            }
        }

    }

}
...