java 8: разница между class.getName () и строковым литералом

Я работал над корпусом переключателя.

Если мы используем class.getName (), то я получаю сообщение об ошибке, что «выражения case должны быть постоянными выражениями» следующим образом:

switch(param.getClass().getName())
    {
        case String.class.getName():
            // to do
            break;
    }

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

public static final String PARAM_NAME = String.class.getName();
switch(param.getClass().getName())
    {
        case PARAM_NAME:
            // to do
            break;
    }

Но если я сделаю следующее, использую строковый литерал «java.lang.String», ошибки не будет:

public static final String PARAM_NAME = "java.lang.String";

Кто-нибудь может объяснить это, почему не взять первые два случая и не взять последний? Заранее спасибо.


person Krishna Kumar    schedule 11.11.2015    source источник


Ответы (3)


classObject.getName() - это вызов метода, и результаты вызовов метода по определению не являются константами времени компиляции. Строковый литерал является константой времени компиляции.

Обратите внимание, что в то время как во многих ситуациях ссылка static final может использоваться в качестве константы на протяжении всего времени существования программы, параметры switch должны быть жестко запрограммированы во время компиляции. Значение цели case должно быть либо значением перечисления, либо (время компиляции) _ 5_.

person chrylis -cautiouslyoptimistic-    schedule 11.11.2015
comment
Но я также беру это в переменной «static final» (то есть, константу), значит, тоже не принимаю? - person Krishna Kumar; 11.11.2015
comment
компилятор творит чудеса, и я предполагаю, что первые две вещи компилируются в один и тот же байт-код. Последнее, что вы даете, там используется строковый литерал, и поэтому он работает - person Emerson Cod; 11.11.2015
comment
@KrishnaKumar Поле static final не обязательно является константой времени компиляции, даже если для практических целей это константа во время выполнения. - person chrylis -cautiouslyoptimistic-; 11.11.2015
comment
Переменная final является константой времени компиляции тогда и только тогда, когда она немедленно инициализируется константой времени компиляции. Обратите внимание, что для этого не обязательно быть static, это даже не обязательно должно быть поле, правило применяется и к локальным переменным. - person Holger; 11.11.2015

Каждая метка case должна быть постоянным выражением. Что такое постоянное выражение, определено в Стандарте языка Java, §15.28 Постоянные выражения:

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

  • Литералы примитивного типа и литералы типа String

...

  • Простые имена, относящиеся к постоянным переменным

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

person Tagir Valeev    schedule 11.11.2015

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

String.class.getName() - это вызов метода, который оценивается во время выполнения. Да, static final гарантирует, что он не изменится после начальной загрузки класса. Но все это происходит намного позже времени компиляции.

Компилятор никогда не вызывает какой-либо код из исходного кода приложения (за возможным исключением обработки аннотаций). Он только его компилирует.

person Thilo    schedule 11.11.2015