Почему автобокс не использует valueOf () при вызове через отражение? - PullRequest
0 голосов
/ 08 января 2019

Насколько я понимаю, следующий код должен печатать "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.1. Бокс Конверсия :

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

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

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

Ответы [ 3 ]

0 голосов
/ 08 января 2019

1.

Конкретный

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

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

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

Boolean b = true;

или

boolean b = true;
Boolean b2 = b;

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

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

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

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

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

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

0 голосов
/ 08 января 2019

Как видно из класса 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.

0 голосов
/ 08 января 2019

invoke will всегда возвращает новое Object. Все возвращаемые примитивы упакованы.

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

Ваша проблема демонстрирует двусмысленность термина соответственно . во время переноса он не использует Boolean.valueOf (логический) .

...