Немножко о безумии языка Java

Nov 03, 2020 10:31

Готовлюсь к сертификационному экзамену по Java (OCA, 1Z0-808), с трудом прохожу тесты Enthuware. Вот уже неделю волосы стоят дыбом и не опускаются от вопроса - что же курили создатели?

Образец кода:

public class TestClass {
public static void main(String[] args){
byte b = 127;
System.out.println((b+=1)+" "+((Object)b).getClass());
byte a = 127;
Read more... )

информатика

Leave a comment

natpy November 3 2020, 11:45:45 UTC
Ну a = a+1 не компилируется понятно почему, у тебя результат вычисления действительно вываливается из байта и джава сохраняется его в integer. А затем ты пытаешься присвоить integer в byte.

И соответственно тебе без ошибки выдаёт System.out.println((a+1)+" "+((Object)(a+1)).getClass()); ты ведь результат вычисления a+1 не пытаешься ничему присвоить, сразу выводишь на печать

А вот результат операции += меня удивил. Оказывается он автоматически кастит к нужному типу. То есть a+=1 не эквивалетно a=a+1, а эквивалетно a = (byte)(a+1) возможно я даже знал это когда то, но забыл

На самом деле такого безумия в джаве много

Например Integer.valueOf(127) == Integer.valueOf(127) тебе вернёт true, а Integer.valueOf(128) == Integer.valueOf(128) вернёт false. Выглядит нелепо, а по факту для значений меньше 128 Integer.valueOf не создёт постоянно новые объекты а берёт их из кеша если это возможно.

Но если честно, на практике вся эта ересь никогда почти не встречается. Не понимаю почему ею так любят мучить людей на собеседованиях.

Reply

eternele November 3 2020, 12:23:44 UTC
Нет, не поэтому а=а+1 не компилируется. Если я инициализирую а любым другим числом, результат такой же. На самом деле, при любой математической операции short, byte и, кажется, char превращаются в int. А += считается не математической операцией, а operator overloading, и у него другие правила.

Reply

morfizm November 3 2020, 20:19:09 UTC
Уверен, что это только кажется, а на самом деле причина в том, что численный literal "1" имеет по умолчанию тип int.

Попробуйте вместо 1 использовать переменную "c", которую вы заранее объявили как byte и присвоили туда 1. Если оба операнда имеют тип byte, то и сложение a = a + c будет происходит в рамках byte, не будет расширения диапазона. И просто standalone выражение a + c будет byte.

В Джаве есть трюки, чтобы сказать, что числовая константа имеет тип long (напр., 123L), но нет ни единого трюка, чтобы сказать, что она byte. Надо брать интовое число и down-cast'ить. Видимо, это редко кому надо, поэтому так сделано. Если вместо 1 вы напишете ((byte)1), то будут вам байты без выхода в инты.

https://stackoverflow.com/questions/5193883/how-do-you-specify-a-byte-literal-in-java

Reply

morfizm November 3 2020, 20:26:33 UTC
По ходу, вы были правы в том, что у byte нет своего +, используется интовый и upcast'ит оба операнда.

Т.е.
byte a = 127
byte c = 1
System.out.println((a+c)+" "+((Object)(a+c)).getClass());

Печатает
128 class java.lang.Integer

А вот:
byte a = 127;
byte c = 1;
System.out.println(((byte)(a+c))+" "+((Object)((byte)(a+c))).getClass());

Печатает
-128 class java.lang.Byte

В общем, тип Byte он только для хранения, арифметики у него своей нет.

Reply

eternele November 3 2020, 20:55:09 UTC
"Widening primitive conversion (§5.1.2) is applied to convert either or both operands as specified by the following rules:

If either operand is of type double, the other is converted to double.

Otherwise, if either operand is of type float, the other is converted to float.

Otherwise, if either operand is of type long, the other is converted to long.

Otherwise, both operands are converted to type int.

Binary numeric promotion is performed on the operands of certain operators:

The multiplicative operators *, / and % (§15.17)

The addition and subtraction operators for numeric types + and - (§15.18.2)

The numerical comparison operators <, <=, >, and >= (§15.20.1)

The numerical equality operators == and != (§15.21.1)

The integer bitwise operators &, ^, and | (§15.22.1)

In certain cases, the conditional operator ? : (§15.25)

https://docs.oracle.com/javase/specs/jls/se7/html/jls-5.html#jls-5.6.2

Reply

morfizm November 3 2020, 20:57:18 UTC
Похоже им просто плевать на тип байт, они воспринимают его только для storage. (Впрочем, это оправданно - для чего ещё нужен тип byte?)

Reply

eternele November 4 2020, 06:37:29 UTC
Вопрос, кстати, изначально даже не в этом был, а в том, почему а=a+1 и a+=1 дают разный результат.

Reply

eternele November 3 2020, 12:25:34 UTC
Вот да! Нафига эта ересь?! Про String такой же дурдом. Если
String string1 = "hello";
String string2 = "hello";
, то string1==string2 вернет true.

А если
String string1 = new String("hello");
String string2 =new String("hello");

, то false

Reply

mamontopotam November 3 2020, 17:46:21 UTC

На практике времени на вылавливание ошибок вылазящих из-за неявного пребразования типов тратится значительно больше, чем при отлове чисто алгоритмических/логических багов. Соотвественно продуктивность повышать логичнее всего именно дрессируя на подобную хрень .. чтобы обходить такие засады и не тратить на их отлов кучу времени и нервов единственный способ - "просто знать".

Reply

eternele November 3 2020, 20:56:23 UTC
Это понятно. Вопрос - зачем язык так создавать "здесь мы тип меняем, здесь сохраняем, а тут рыбу заворачиваем"?

Reply

mamontopotam November 4 2020, 06:32:30 UTC

Ну дело в любом алго-языке в балансе избыточности (которая нужна для приближенности к человеческим языкам и по легкости понимания) и однозначности трансляции. В детской загадке "сколько будет два плюс два умножить на два" всегда найдутся те, кто имплицитно "видит" скобки и получает 8 и кто их "не видит" и получает 6😃 Тут то вопромы не к тем кто язык пооектировал концептуально, поскольку они о таких деталях не думают , а скорее к тем, кто транслятор пишет и кому скорее всего разрешение подобных коллизий отдано на откуп. Архитектор может мыслить сколь угодно стройно и красиво, но вопрос, как именно завести вот эту самую трубу на месте решает прораб на своем уровне компетентности и зарплаты, т.е мотивации в конечном результате 😃

Reply

morfizm November 3 2020, 20:15:25 UTC
Тут нет дурдома ( ... )

Reply

eternele November 3 2020, 20:57:29 UTC
Это всё я, конечно, знаю ;) только язык менее безумным от этого не кажется

Reply

morfizm November 3 2020, 20:58:48 UTC
Тогда вам бы чистый C понравился. Там нет переменных, хитрожопо маскирующихся под указатели. Указатели всегда имеют * после типа и их надо явно разыменовывать :)

Reply

eternele November 4 2020, 06:47:18 UTC
Начинаю скучать по С, ага

Reply


Leave a comment

Up