SCJP: нельзя расширять, а затем боксировать, но можно боксировать, а затем расширять

Я готовлюсь к экзамену SCJP и столкнулся с проблемой, с которой не могу разобраться.

В книге сказано, что вы не можете расширяться, а затем боксировать, но вы можете боксировать, а затем расширяться. Пример невозможности упаковать - это метод, ожидающий Long, и метод, вызываемый с байтом.

Их объяснение таково:

Подумайте об этом... если бы он попытался сначала упаковать, байт был бы преобразован в байт. Теперь мы вернулись к попытке расширить байт до длинного, и, конечно же, тест IS-A терпит неудачу.

Но это звучит как коробочка, а затем расширяется, а не расширяется, а затем коробится для меня.

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

Изменить: для уточнения: я говорю о страницах 252 и 253 сертифицированного программиста SCJP для java 6 книги. http://books.google.be/books?id=Eh5NcvegzMkC&pg=PA252#v=onepage&q&f=false


person Jack    schedule 15.09.2010    source источник
comment
Но это звучит как блок, а затем расширение, вам нужно понимать, что в этом примере происходит сначала преобразование byte в long, поэтому сначала это расширение. Все еще не ясно?   -  person The Student    schedule 21.12.2010


Ответы (5)


язык сбивает с толку.

По сути, вы не можете использовать этот способ:
byte -> Byte -> Long,
потому что Byte и Long не имеют отношения is-a.
Итак, он пытается сделать это:
byte -> long -> Long
Но и этого он сделать не может (видимо, из-за ограничений компилятора). Итак, он терпит неудачу и выдает ошибку.

Но, с другой стороны, вы МОЖЕТЕ сделать это:
byte -> Byte -> Object
потому что байт — это объект.

рассмотрим 2 функции и байтовую переменную:

toLong(Long x)
toObject(Object x)
byte b = 5;

Тогда это утверждение будет недопустимым:
toLong(b);
// потому что b -> new Byte(b) -> new Long(new Byte(b)) недопустимо.
AND byte -> long -> Long нельзя сделать из-за ограничений компилятора.

но это утверждение допустимо:
toObject(b);
// потому что b -> новый байт(b) -> новый объект(новый байт(b)) является допустимым.

person user492883    schedule 31.10.2010

Причина, по которой «расширение, а затем бокс» не разрешено, может быть связана со следующей причиной (стр. 249 книги SCJP):

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

person Bipin    schedule 10.11.2012

В основном это означает, что расширение работает только с примитивными типами, а не с оболочками. Если вы сначала боксируете, вы получаете обертку (byte -> Byte). А вот обертки - Byte, Double, Float, Integer, Long и Short не имеют отношения наследования (IS-A). Например, параметр Long не может принимать Byte.

Таким образом, вы должны сначала расширить (byte -> long), а затем боксировать (long -> Long).

person samitgaur    schedule 15.09.2010
comment
Причина невозможности расширения мне ясна. В конце концов, Byte не является экземпляром Long. Но они, похоже, не делают различий. Я знаю, что легко согласиться с тем, что расширение, а затем бокс не разрешено, как правило, но мне очень любопытно, почему. - person Jack; 15.09.2010
comment
Я думаю, что язык книги сбивает с толку. Но вышесказанное, вероятно, имелось в виду. Не существует понятия расширения для оберток, т.е. Byte -> Short -> Integer -> Long -> Double, поэтому вопрос расширения после бокса в этом контексте не возникает. - person samitgaur; 15.09.2010

Это не расширение, потому что Byte не помещается в Long. Вот почему это не работает.

Вы можете упаковать в байт, а затем расширить в Object или Number.

Как говорится в вашей книге:

мы вернулись к попыткам расширить байт до длинного


В вашем случае, я полагаю, код выглядит так:

byte b = 1;
Long l = b;

b изменяется на Byte (сначала бокс), но не может быть изменен на Long, потому что Byte не является подклассом Long.

В дополнительных шагах:

byte b = 1;
Byte byteB = b; //works
Long l = byteB; //doesn't work
person Colin Hebert    schedule 15.09.2010
comment
Но для того, чтобы байт был байтом, его нужно было бы сначала поместить в коробку, и речь идет о расширении, а затем о запрещении упаковки... Я имею в виду, что если я вручную расширяю байт до длинного, я могу вызвать функцию Long, используя второй. Так разработчики просто запретили это, потому что это могло быть слишком медленным? Я не могу просто уложить в голове рассуждения о том, почему бокс, а затем расширение разрешены, а расширение и бокс — нет. - person Jack; 15.09.2010
comment
Часть книги, которую вы читаете, не о расширении и боксе, а о примере того, чем бокс и расширение не являются. Это прямо перед вашей цитатой. Почему компилятор не попытался использовать логику box-then-widen, когда он пытался работать с классом WidenAndBox? - person Colin Hebert; 15.09.2010
comment
На самом деле, кажется, речь идет об обоих. Или я действительно неправильно истолковываю это. Я обновил свой исходный пост со ссылкой на страницу. - person Jack; 15.09.2010
comment
Вы неверно истолковываете это. Расширение и бокс не работают. Это факт, больше сказать об этом нечего. Та часть книги, которую вы читаете, действительно сосредоточена на операции бокса/расширения. java.sun.com/docs/books/jls/ третье_издание/html/ - person Colin Hebert; 15.09.2010
comment
Я читал, что в нем говорится, что вопрос больше о ПОЧЕМУ. бокс, а затем расширение возможно, но не наоборот. Я имею в виду, если бы я сделал это вручную с ‹code›byte b = 1; long l = (long)b;‹/code› Это расширение, и тогда возможен вызов метода Long с l. И конечным результатом является расширение, за которым следует бокс. - person Jack; 15.09.2010
comment
Потому что эти два решения являются эксклюзивными. Как компилятор выберет решение между Long l = b и Object o = b ? Что нужно было бы сделать здесь? Два разных решения для похожего кода. Таким образом, было выбрано одно решение, l = b не сработает, а o = b сработает. - person Colin Hebert; 15.09.2010
comment
Я не вижу причин для того, чтобы они были взаимоисключающими. Хотя тогда надо быть немного осторожнее. - person Jack; 15.09.2010

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

Хотя показанный пример пытается упаковать, а затем расширить, причина, по которой он недействителен, заключается в том, что байт не является длинным, т. е. они не находятся в одном и том же дереве наследования. Однако, если в примере использовались байты и числа, то вам было бы правильно преобразовать байты в байты, а затем расширить байты в числа, поскольку байты являются числовыми (они НАХОДЯТСЯ в одном дереве наследования)

person Craig    schedule 28.01.2011