Каковы общие неопределенные поведения, о которых должны знать Java-программисты - PullRequest
21 голосов
/ 18 декабря 2008

Так же, как этот вопрос, но для Java

Обновление Исходя из комментариев и ответов нескольких людей, ясно, что в Java очень мало неопределенного поведения.

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

Ответы [ 10 ]

14 голосов
/ 18 декабря 2008

Какое-то отношение к темам ...:)

Также:

  • Переопределение методов и ожидание, что они будут использоваться одинаково между версиями
  • Допущения о базовой платформе (например, разделитель файлов)
  • Подробная информация о сборке / доработке мусора
  • Некоторые подробности об инициализации класса
  • Возвращает ли Integer.valueOf (и тому подобное) одинаковые объекты
  • Производительность, задержка и использование памяти
11 голосов
/ 18 декабря 2008

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

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

Основная область, где происходит неопределенное поведение, - это точное время и расписание нескольких потоков (как уже упоминал Том Хоутин).

Есть несколько мест, где поведение неочевидно, хотя, поэтому оно может выглядеть неопределенным, но это не так (примеры сравнения строк, приведенные Оскаром Рейесом, являются отличным примером).

И несколько мест, где поведение определено как неопределенное (например, порядок элементов в HashMap определяется как зависящий от реализации и не должен быть постоянным).

8 голосов
/ 18 декабря 2008

Я думаю, что Java (TM) Puzzlers: ловушки, ловушки и угловые случаи книга будет очень полезна, она объясняет многие скрытые моменты и неопределенное поведение java.

4 голосов
/ 18 декабря 2008

Сериализация . По сути, это не неопределенно (есть детерминированный алгоритм). Однако для стороннего наблюдателя совершенно не очевидно, что вызовет или не вызовет изменение в serialVersionUID, что помешает всем вашим попыткам использовать RMI, JMS и множество других сокращений.

Так что, как правило, будет хорошей идеей рассмотреть ваши варианты , когда вы знаете, что вам нужно будет сериализовать объект. Мне особенно нравится техника «всегда включай это как поле»:

private static final long serialVersionUID = 1L;

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

3 голосов
/ 18 декабря 2008

Я не совсем уверен, что вы подразумеваете под "неопределенным поведением", но, как уже отмечали другие, базовый язык очень предсказуем для всех платформ, версий языка и JVM.

Однако это не относится к графике (Swing, AWT), которая, как правило, непредсказуема и не обязательно воспроизводима на разных платформах. Я работал над приложением для визуализации на основе Java с большим количеством графики и много времени проводил «писать один раз и везде отлаживать».

Кроме того, Object.clone () имеет некоторые серьезные проблемы, и его использование не рекомендуется в большинстве случаев. Пожалуйста, см. Пункт 11 из «Эффективной Явы» Джошуа Блоха для полного ответа.

2 голосов
/ 27 декабря 2012

Мне известны два неопределенных поведения:

a) Перегрузка метода параметром, который является подклассом того же параметра в перегруженном методе. Например:

void doSomething(Object obj);
void doSomething(String str);

Нет способа узнать, какой метод будет вызываться в doSomething («Hello world!»), Поскольку обе подписи действительны. Кроме того, это поведение может меняться от виртуальной машины к виртуальной машине и даже от выполнения к выполнению.

б) Вызов не финального метода того же класса в конструкторе. Неопределенное поведение происходит, если этот метод переопределен в подклассе. Обратите внимание, что построение происходит от суперкласса до подкласса. Случай становится особенно неприятным, если метод подкласса использует некоторые локальные атрибуты подкласса. В случае Oracle VM будут созданы локальные атрибуты, конструктор суперкласса завершит свое выполнение, а затем, когда конструктор подкласса будет достигнут, атрибуты будут созданы снова, переопределяя ранее определенные значения.

1 голос
/ 18 декабря 2008

Четко определено, но не очевидно:

Проверка объекта на равенство:

== используется для проверки ссылок (указывают ли эти две ссылки на один и тот же объект)

Хотя метод equals используется для проверки равенства объектов.

Например,

new String("test") == new String("test")  

ложно, а

new String("test").equals( new String("test") )

верно

Строковые объекты интернированы, поэтому следующее возвращает true:

String a = "test";
String b = "test";

a == b  // returns true 

НО, если строка создается где-то еще (например, из базы данных)

String a = "test";
String b = getFromDataBase(); // internally the remote returns "test"

a == b  // returns false.

Проверка неверна.

Я видел, как это происходит в jsp со скриптами, и новые программисты не понимают, почему проверка

 <%if( param == "continue" ) { %>

Никогда не бывает

0 голосов
/ 18 декабря 2008

Не определено, но неожиданное поведение - это то, как двойники округляются при преобразовании в целое число. 0.6d всегда округляется до 0; на самом деле 0.9d также округляется до 0. Но 0.99999999999999995 и выше округляют до 1.

Просто интересное поведение при приведении результатов вызова Math.random (), чтобы остерегаться.

0 голосов
/ 18 декабря 2008

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

0 голосов
/ 18 декабря 2008

Одна вещь, которую я помню, касается совместимости jvm с jni. У нас было и приложение, которое было разработано на jdk1.4, и при установке его на машину с ibm jvm (я полагаю, jikes) вызов jni просто рванул! Это было в 2006 году. Я считаю, что это не имеет ничего общего с Java в качестве языка, но больше связано с Java в качестве платформы.

...