2016-09-21 5 views
8

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

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

Class getFooClass() 

Long getFooId() 

Я прохожу класс и идентификатор метода с этой подписью, который делегирует в спящем режиме, который извлекает объект на основе его класса и ID:

public <T> T get(Class<T> clazz, Serializable id); 

Есть разные реализаторы Foo, а некоторые из этих спящих объектов имеют идентификатор Long, а другие имеют идентификатор Integer. Хотя этот метод принимает и то, что дальше, лучше иметь правильный. Поэтому, когда я попытался вызвать get() на объекте с Integer идентификатором, следующим образом, я понятно получил ошибку, жалуясь, что я предоставил Long где Integer требовалось:

get(bar.getFooClass(), bar.getFooId()); 

Там нет проблем зимуют здесь, я просто необходимо указать Integer, где требуется идентификатор Integer, и Long, где требуется идентификатор Long. Поэтому я добавил метод bar, hasLongId() и попытался это: (в этот момент вы можете думать, что это не очень хороший дизайн, но это не мой вопрос прямо сейчас)

get(bar.getFooClass(), 
    bar.hasLongId() ? bar.getFooId() : bar.getFooId().intValue()); 

И еще жаловался, что Я предоставил Long. Это показалось странным. Тогда я пробовал это:

get(bar.getFooClass(), 
    bar.hasLongId() ? bar.getFooId() 
        : new Integer(bar.getFooId().intValue())); 

Такая же ошибка! Как это может быть? Поэтому я прошел через отладчик, и да, он прошел через intValue(), а также через конструктор Integer, но затем в методе get переданный параметр был фактически Long - тот же объект Long, который был возвращен с getFooId().

Я не понимаю, что происходит, так что я просто попробовать различные вещи:

Integer intId = bar.getFooId().intValue(); 
get(bar.getFooClass(), bar.hasLongId() ? bar.getFooId() : intId); 
// same error 

и

Serializable id = bar.hasLongId() ? bar.getFooId() 
           : new Integer(bar.getFooId().intValue()); 
get(bar.getFooClass(), id); 
// same error 

И, наконец:

Serializable id; 
if (bar.hasLongId()) { 
    id = bar.getFooId(); 
} else { 
    id = bar.getFooId().intValue(); 
} 
get(bar.getFooClass(), id); 

Это один работает. По-видимому, это как-то связано с тернарным оператором. Но почему? Может кто-нибудь объяснить, что здесь произошло?

+6

Информация не достаточна. Не перефразируйте код и не суммируйте сообщения об ошибках. Я мог бы или не мог бы понять, что не так, основываясь на том, что вы нам дали, но я не собираюсь тратить много времени на это, потому что могу сказать, что вы не дали нам ничего полного. – arcy

+0

Не связано с вашим вопросом, но почему бы вам не заставить 'getFooId()' возвращать 'Number' вместо дополнительного метода и преобразования типа? – shmosel

+1

Голосование для повторного открытия, потому что в другом вопросе не рассматриваются тройные выражения или значения в штучной упаковке. – shmosel

ответ

10

Это отличный вопрос и идет в подробные подробные сведения о семантике тернарного выражения. Нет, ваш компилятор не сломан или не играет на вас.

В этом случае, если типы второго и третьего операндов тройного выражения long и int, то результирующий тип всегда long. Это связано с binary numeric promotion.

Согласно JLS (Java Language Specification):

..., двоичное числовое расширение применяется к типам операндов, и типа условного выражения является расширенным типом вторых и третьих операндов.

Значения получают распакованный из-за правило # 1 из Binary числовое расширение:

Если какой-либо из операндов имеет ссылочного типа, он подвергается распаковки преобразования

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

+0

Как насчет явно вложенного типа? Получается ли он распакован? Зачем? – shmosel

+0

Хороший ответ. Это будет более полно, как упомянуто @shmosel, чтобы рассказать, почему компилятор, когда сталкивается с тройным оператором с условием? Long: int 'или' condition? Long: Integer', решает автоматически распаковать условие 'Long' to form'? long: int'. Форма 'условие? Long: Integer' также должен быть действительным здесь? –

+0

Отредактировано для ответа на вышеуказанные вопросы. –

 Смежные вопросы

  • Нет связанных вопросов^_^