Почему автобокс не использует valueOf() при вызове через отражение?

Насколько я понимаю, следующий код должен вывести "true", но когда я его запускаю, он выдает "false".

public class Test {
    public static boolean testTrue() {
        return true;
    }

    public static void main(String[] args) throws Exception {
        Object trueResult = Test.class.getMethod("testTrue").invoke(null);
        System.out.println(trueResult == Boolean.TRUE);
    }
}

Согласно JLS §5.1.7. Конвертация бокса:

Если значение p будучи в штучной упаковке является true, false, А byte, или char в диапазоне \u0000 до \u007f, или int или short номер между -128 и 127 (включительно), то пусть r 1 и r 2 будет результаты любых двух боксерских преобразований p. Это всегда тот случай, когда r 1 == r 2.

Однако в случае метода, вызванного с помощью отражения, коробочное значение всегда создается с помощью new PrimitiveWrapper().

Пожалуйста, помогите мне понять это.

Ответ 1

invoke всегда возвращает новый Object. Любые возвращаемые примитивы упакованы.

... если значение [return] имеет примитивный тип, оно сначала соответствующим образом переносится в объект.

Ваша проблема демонстрирует двусмысленность термина соответствующим образом. т.е. во время переноса, он не использует Boolean.valueOf(boolean).

Ответ 2

1.

Конкретные

в случае метода, вызванного через отражение

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

Но преобразование типов означает что-то вроде этого:

Boolean b = true;

или же

boolean b = true;
Boolean b2 = b;

Отражение не является механизмом, который применяет преобразование типов.

Когда по необходимости вызов рефлексивного метода оборачивает логическое возвращаемое значение в логический объект, он не включается в ту часть JLS, которую вы цитировали.

Это объясняет, почему JLS здесь не нарушается.

  1. 2.

Что касается того, почему рефлексия не выбирает соответствовать этому поведению в любом случае:

Это связано с тем, что в более старых версиях Java рефлексия существовала до обобщения. И дженерики - это причина, по которой автобокс внезапно стал удобной, а автобокс - причина того, почему казалось умным не дублировать "общие" значения упакованных примитивов.

Все это было определено после того, как рефлексия уже существовала некоторое время, и уже велась определенным образом. Это означает, что уже существовал код Java, который использовал отражение, и, скорее всего, существующий код, который неправильно полагался на существующее поведение. Изменение существующего поведения нарушило бы существующий код, чего поэтому избегали.

Ответ 3

Как вы можете видеть в классе java.lang.reflect.Method, метод invoke имеет следующую подпись:

 public Object invoke(Object obj, Object... args) { ... }

который возвращает объект как результат.

Кроме того, Boolean.TRUE определяется как:

public static final Boolean TRUE = new Boolean(true);

который является коробочным объектом true значения.

Оценивая trueResult == Boolean.TRUE в вашем коде, вы проверяете, равны ли ссылки на trueResult и Boolean.TRUE или нет. Поскольку == оценивает равенство значений, а в случае ссылок это означает, что две ссылки указывают на один Object в памяти?

Очевидно, что эти два объекта не являются одинаковыми (они являются двумя отдельными объектами и создаются в разных частях памяти), поэтому результат trueResult == Boolean.TRUE равен false.