Класс BigDecimal
Класс BigDecimal расположен в пакете j ava.math. Каждый объект этого класса хранит два целочисленных значения: мантиссу вещественного числа в виде объекта класса BigInteger и неотрицательный десятичный порядок числа типа int. Например, для числа 76,34862 будет храниться мантисса 7 634 862 в объекте класса BigInteger и порядок 5 как целое число типа int. Таким образом, мантисса может содержать любое количество цифр, а порядок ограничен значением константы Integer.MAX_VALUE.
Результат операции над объектами класса BigDecimal округляется по одному из восьми правил, определяемых следующими статическими целыми константами:
? round_ceiling — округление в сторону большего целого;
? round_down — округление к нулю, к меньшему по модулю целому значению;
? round_floor — округление к меньшему целому;
? round_half_down — округление к ближайшему целому, среднее значение округляется к меньшему целому;
? round_half_even — округление к ближайшему целому, среднее значение округляется к четному числу;
? round_half_up — округление к ближайшему целому, среднее значение округляется к большему целому;
? round_unnecessary — предполагается, что результат будет целым, и округление не понадобится;
? round_up — округление от нуля, к большему по модулю целому значению.
Три константы — zero, one и ten — моделируют вещественные нуль, единицу и вещественное число десять в операциях с объектами класса BigDecimal.
В классе BigDecimal около двадцати конструкторов. Четыре из них были введены еще в Java 2.
? BigDecimal (BigInteger bi) - объект будет хранить большое целое bi, порядок равен
нулю;
? BigDecimal(BigInteger mantissa, int scale) — задается мантисса mantissa и неотрицательный порядок scale объекта; если порядок scale отрицателен, возникает исключительная ситуация;
? BigDecimal(double d) — объект будет содержать вещественное число удвоенной точности d; если значение d бесконечно или NaN, то возникает исключительная ситуация;
? BigDecimal (String val) - число задается строкой символов val, которая должна со
держать запись числа по правилам языка Java.
При использовании третьего из перечисленных конструкторов возникает неприятная особенность, отмеченная в документации. Поскольку вещественное число при переводе в двоичную форму представляется, как правило, бесконечной двоичной дробью, то при создании объекта, например BigDecimal (0.1), мантисса, хранящаяся в объекте, окажется очень большой. Она показана на рис. 4.5. Но при создании такого же объекта четвертым конструктором, BigDecimal ("0.1"), мантисса будет равна просто 1.
Остальные конструкторы определяют точность представления числового значения объекта и правила его округления с помощью объекта класса MathContext или непосредственно.
В классе переопределены методы doubleValue (), floatValue (), intValue (), longValue ( ).
Три константы — zero, one и ten — моделируют нуль, единицу и число десять в операциях с объектами класса BigDecimal.
Большинство методов этого класса моделируют операции с вещественными числами. Они возвращают объект класса BigDecimal. Ниже в описании методов буква x обозначает объект класса BigDecimal, буква n — целое значение типа int, буква r — способ округления, одну из восьми перечисленных ранее констант:
? abs () — абсолютное значение объекта this;
? add (x) — операция сложения this + x;
? divide (x, r) — операция деления this / x с округлением по способу r;
? divide (x, n, r) — операция деления this / x с изменением порядка и округлением по способу r;
? max(x) — наибольшее из this и x;
? min(x) — наименьшее из this и x;
? movePointLeft (n) — сдвиг влево на n разрядов;
? movePointRight(n) — сдвиг вправо на n разрядов;
? multiply(x) — операция умножения this * x;
? negate () — возвращает объект с обратным знаком;
? scale () — возвращает порядок числа;
? setScale(n) — устанавливает новый порядок n;
? setScale (n, r) — устанавливает новый порядок n и округляет число при необходимости по способу r;
? signum () — знак числа, хранящегося в объекте;
? subtract (x) — операция вычитания this — x;
? toBiginteger () — округление числа, хранящегося в объекте;
? unscaledValue () — возвращает мантиссу числа;
? upl () — возвращает расстояние до следующего числа.
Листинг 4.7 показывает примеры использования этих методов, а рис. 4.5 — вывод результатов.
Начиная с версии Java SE 5 в класс BigDecimal введено еще много методов преобразования объекта и получения его характеристик.
Листинг 4.7. Методы класса BigDecimal в программе BigDecimalTest
import java.math.*; class BigDecimalTest{
public static void main(String[] args){
BigDecimal x = new BigDecimal("-12345.67890123456789");
BigDecimal y = new BigDecimal("345.7896e-4");
BigDecimal z = new BigDecimal(new BigInteger("123456789"), 8); System.out.println("|x| = " + x.abs());
System.out.println("x + y = " + x.add(y));
System.out.println("x / y = " + x.divide(y, BigDecimal.ROUND DOWN)); System.out.println("x / y = " + x.divide(y, 6, BigDecimal.ROUND HALF EVEN)); System.out.println("max(x, y) = " + x.max(y));
System.out.println("min(x, y) = " + x.min(y));
System.out.println("x << 3 = " + x.movePointLeft(3)); System.out.println("x >> 3 = " + x.movePointRight(3)); System.out.println("x * y = " + x.multiply(y)); System.out.println("-x = " + x.negate());
System.out.println("scale of x = " + x.scale());
System.out.println("increase scale of x to 20 = " + x.setScale(20)); System.out.println("decrease scale of x to 10 = " + x.setScale(10, BigDecimal.ROUND HALF UP));
System.out.println("sign(x) = " + x.signum());
System.out.println("x — y = " + x.subtract(y)); System.out.println("round x = " + x.toBigInteger()); System.out.println("mantissa of x = " + x.unscaledValue()); System.out.println("mantissa of 0.1 = = " +
new BigDecimal(0.1).unscaledValue());
}
}
Приведем еще один пример. Напишем простенький калькулятор, выполняющий четыре арифметических действия с числами любой величины. Он работает из командной строки. Программа представлена в листинге 4.8, а примеры использования калькулятора — на рис. 4.6.
Листинг 4.8. Простейший калькулятор
import java.math.*; class Calc{
public static void main(String[] args){ if (args.length < 3){
System.err.println("Usage: java Calc operand operator operand"); return;
}
BigDecimal a = new BigDecimal(args[0]);
BigDecimal b = new BigDecimal(args[2]); switch (args[1].charAt(0)){
case ' + ': case '-': case '*': case ?/': default :System.out.println(a.add(b)); break;
System.out.println(a.subtract(b)); break; System.out.println(a.multiply(b)); break; System.out.println(a.divide(b,
BigDecimal.ROUND_HAL F_EVEN)); break; System.out.println("Invalid operator");
}
Почему символ умножения — звездочка — заключен на рис. 4.6 в кавычки? Приверженцам ОС UNIX это понятно, а для других дадим краткое пояснение.
Это особенность операционной системы, а не языка Java. Введенную с клавиатуры строку вначале просматривает командная оболочка (shell) операционной системы, а звездочка для нее — указание подставить на это место все имена файлов из текущего каталога. Оболочка сделает это, и интерпретатор Java получит от нее длинную строку, в которой вместо звездочки стоят имена файлов, отделенные друг от друга пробелом.
Звездочка в кавычках понимается командной оболочкой как обычный символ. Командная оболочка снимает кавычки и передает интерпретатору Java звездочку, что нам и надо.
Класс Class
Класс Object, стоящий во главе иерархии классов Java, представляет все объекты, действующие в системе, является их общей оболочкой. Всякий объект можно считать экземпляром класса Object.
Класс с именем Class представляет характеристики класса, экземпляром которого является объект. Он хранит информацию о том, не является ли объект на самом деле интерфейсом, массивом, перечислением или примитивным типом, каков суперкласс объекта, каково имя класса, какие в нем конструкторы, поля, методы и вложенные классы.
В классе Class нет конструкторов, экземпляр этого класса создается исполняющей системой Java во время загрузки класса и предоставляется методом getclass () класса Object, например:
String s = "Это строка";
Class c = s.getClass();
Таким образом, у каждого действующего в программе объекта есть ссылка на экземпляр класса Class, содержащий описание класса этого объекта. Такое свойство объекта называется рефлексией (reflection). Кроме того, мы можем получить такую ссылку на классы по их имени.
Статический метод forName(String class) класса Class возвращает объект класса Class для класса, указанного в аргументе, например:
Class c1 = Class.forName("java.lang.String");
Третий способ получения экземпляра класса Class — к имени класса через точку добавить слово class:
Class c2 = java.lang.String.class;
Логические методы isAnnotation(), isArray(), isInterface(), isEnum(), isPrimitive() позволяют уточнить, не является ли объект аннотацией, массивом, интерфейсом, перечислением или примитивным типом.
Если объект ссылочного типа, то можно извлечь сведения о вложенных классах, конструкторах, методах и полях методами getDeclaredClasses(), getDeclaredConstructors(), getDeclaredMethods(), getDeclaredFields() в виде массива классов: Class, Constructor, Method, Field соответственно. Последние три класса расположены в пакете j ava. lang.reflect и содержат сведения о конструкторах, полях и методах аналогично тому, как класс Class хранит сведения о классах.
Методы getClasses (), getConstructors (), getInterfaces (), getMethods (), getFields ( ) возвращают такие же массивы, но не всех, а только открытых членов класса.
Метод getSuperclass() возвращает суперкласс объекта ссылочного типа, getPackage ( ) — пакет, getModifiers() — модификаторы класса в битовой форме. Модификаторы можно затем расшифровать методами класса Modifier из пакета java.lang.reflect.
Листинг 4.9 показывает применение этих методов, а рис. 4.7 — вывод результатов.
Листинг 4.9. Методы класса class в программе ciassTest
import java.lang.reflect.*; class ClassTest{
public static void main(String[] args){
Class c = null, c1 = null, c2 = null;
Field[] fld = null;
String s = "Some string";
c = s.getClass();
try{
cl = Class.forName("java.lang.String"); // Старый стиль
c2 = java.lang.String.class; if (!c1.isPrimitive())
fld = c1.getDeclaredFields(); }catch(Exception e){}
System.out.println("Superclass c: " System.out.println("Package c: ' System.out.println("Modi fiers c: ' for(int i = 0; i < fld.length; i++) System.out.println(fld[i]);
}
}
// Новый стиль
// Все поля класса String
+ c);
+ c1);
+ c2);
+ c.getSuperclass()); + c.getPackage());
+ c.getModifiers());
Методы, возвращающие свойства классов, вызывают исключительные ситуации, требующие обработки. Поэтому в программу введен блок try{}catch(){}. Рассмотрение обработки исключительных ситуаций мы откладываем до главы 21.
Начиная с версии Java SE 5 класс Class сделан настраиваемым: Class<string> — это описание класса string, Class<Long> — описание класса Long и т. д. Это полезно, когда ссылка на класс Class передается в метод как параметр и надо определить, на какой же класс она направлена.
Вопросы для самопроверки
1. Зачем кроме примитивных типов в язык Java введены еще соответствующие классы-оболочки?
2. Можно ли использовать объекты числовых классов-оболочек в арифметических выражениях?
3. Какое наибольшее целое значение можно занести в объект класса BigInteger?
4. Какое наибольшее вещественное значение можно занести в объект класса BigDecimal?
5. Можно ли использовать в одном выражении значения примитивных типов и распакованные значения числовых классов-оболочек?
6. Для чего в язык Java введены настраиваемые типы?
7. Можно ли создавать настраиваемые интерфейсы или настраиваемыми могут быть только классы?
8. Должны ли методы настраиваемого класса быть настраиваемыми?
9. Можно ли создавать настраиваемые методы в обычных, не настраиваемых классах?
ГЛАВА 5