Сложение и вычитание (+ и -)
За сложение и вычитание отвечают соответсвенно операторы + и -. Они применимы для операндов любых численных типов. Помимо этого, операция + применяется и для операндов типа String. Когда один из операндов типа String, то результат будет объектом типа String.
Особенности оператора +
В Java не допускается определять перегрузку операторов (то есть перепрограммирование операторов в зависимости от типа), как в С/С++. Но сам язык Java перегружает операторы автоматически. И это в общем-то не ново, поскольку многие языки программирования, которые поддерживают множественные арифметические типы, определяют автоматическую перегрузку арифметических операторов для примитивных типов. Java, помимо этого, имеет перегрузку оператора + для строкового типа (String). И результат действия оператора + в данном случае - это конкатенация, сцепление строк. Если один из операндов не строковый, то к нему будет предварительно применено приведение типа к строке.
Перегрузка (overloading) - это термин, упоминаемый в том случае, когда одна и та же операция (оператор) используется для операндов (аргументов) различного типа. При этом поведение операции (оператора) определяется типом операндов, к котором она должна быть применена. Например, метод println() может применяться как для операндов строкового, так и целочисленного типа. Эти два использования, на самом деле, относятся к совершенно различным методам. Просто было использовано одно и то же имя операции. Аналогично сложение (+) используется, как для целочисленных, так и для дробных типов. Но код, реализующий это сложение совершенно различный.
Вы все знаем, что произойдёт при сложении двух знацений численного типа: операнды будут суммированы. Конечно, может случится и переполнение, если мы суммироем слишком большие числа. Но в общем и целом, поведение арифметических операторов не изобилует сюрпризами.
Если переполнение происходит при арифметическом сложении или вычитании, никаких сообщений об ошибках или исключений мы не получаем. Дело обстоит совсем по-другому, если мы конкатенируем строки. Если оба оператора строки, то результат - это "скленная" строка. Если один из операторов строка, а второй - число, то число будет приведено к типу String.
Приведение численных типов к строке
Для объектных типов приобразование к типу String происходит посредством вызова метода toString(). Этот метод определён в классе java.lang.Object, который является прародителем всех остальных классов. Поэтому все объекты наследуют от Object метод toString(). Однако, этот метод выдаёт некое зашифрованное значение объекта. Например, если мы рассмотрим такой код:
1. public class Test {
2. private static class MyClass {
3. private String name;
4. private int age;
5. public MyClass() {
6. name = "Natalia Macheda";
7. age = 28;
8. }
9.
10. }
11. public static void main (String[] args) {
12. MyClass myObj = new MyClass();
13. System.out.println(myObj.toString());
14. }
15.}
То результат, выводимый 13-й строкой будет такого вида: Test$MyClass@c17164. Здесь мы видим имена классов объекта (разделённые символом $) и какой-то идентификатор после символа @. Идентификатор - это, как правило, ссылка на объект.
Это не очень удобно для понимания, но может быть использовано, например, для отладки программы. С другой строны, для предания читаемости результату операции toString() необходимо перегрузить эту операцию. Например, если в 9-й строке вставить код:
9. public String toString(){
9'. return (name + " " + age);
9''. }
то результат будет Natalia Macheda 28. Заметьте, что втрой аргумент - целочисленного типа. Как же произошло его преобразование в строку?
Преобразование чесленных аргументов к строчному типу неявно использует метод toString() классов-оболочек (wrapper). Например, значение типа int конвертируется вызовом статической функции Integer.toString().
Резюмируем сведения о сложении. Сложение двух числовых значений примтивных типов даёт результат:
- примитивного численного типа;
- по крайней мере самого длинного типа среди типов операндов, участвующих в сложении;
- вычисленный приведением обоих операндов к типу результата и их дальнейшим суммированием.
- Результат может переполнить тип и точность вычисления может потеряться.
Если один из операндов - НЕпримитивного типа:
- второй операнд должен быть строкового типа. Иначе операция нелегальна;
- операнд НЕстрокового типа приводится к типу String и результат - сцепление двух строк.
Приведение операнда объектного типа к строке производится путём вызова метода toString().
Приведение операнда примитивного типа к строке производится неявно путём вызова статичского метода класса-оболочки.
Если вы хотите держать под контролем форматирование результата приведения типа, обратитесь к коду пакета java.text.
Теперь, когда мы разобрались с арифметическими операциями, приведениями типов и конкатенацией строк при помощи оператора +, мы должны вспомнить, что имеем дело с компьютером, который ограничер в своих возможностях представления неких математических абстракций. А значит, всем известные арифметические операции могут работать неправильно и выдавать ошибки.
Арифметические ошибки
Мы ожидаем от арифметических операций результата, который выдаёт знаяение с математическим смыслом. Но, как уже было сказано выше, результат может не соответсвовать нашим ожиданиям в виду ограниченности ресурсов компьютера. В частности:
- Деление на ноль (в том числе и для операции %) выдаёт ArithmeticException;
- Никаких других исключений для арифметических операций не выдаётся, но результат может быть арифметически неправильным ввиду переполнения.
- Дробные типы представляют абстрактные значения при помощи следующих значений: IEEE 754 бесконечности, минус бесконечности и Не-числа NaN (Not a Number). Именные константы, представляющие эти значения, объявлены в классах Float и Double.
NaN сигнализирует о том, что вычисление не имеет результата в математическом понимании. Например, бесконечность или вычисление квадратного корня из отрицательного числа.
Сравнение с НЕ-числом
Два НЕ-числа NaN определены в пакете java.lang. Это Float.NaN и Double.NaN. Следующие сравнения всегда дают false, даже если x равен NaN:
x < Float.NaN
x <= Float.NaN
x == Float.NaN
x > Float.NaN
x >= Float.NaN
В тестах Float.NaN != Float.NaN и Doube.NaN != Double.NaN результат будет true.
Если же вы хотите проверить, что число (не) является NaN, то нужно использовать статические методы Float.isNaN(float) или Double.isNaN(double), определённые в пакете java.lang.
Комментариев нет:
Отправить комментарий