Операции
Над целочисленными типами
- операторы сравнения (>, <, >=, <=) и равенства (==, !=)
- унарные операторы (+, -)
- мультипликативные (*, /, %) и аддитивные (+, -) операторы
- инкремент (++) и декремент (--) в префиксной и постфиксной формах
- знаковые (>>, <<) и без знаковые (>>>) операторы сдвига
- побитовые операторы (~, &, ^, |)
- условный оператор (? : )
- оператор приведения типов
Над Floating-Point типами
Над числами с плавающей точкой можно проводить все те же операции, что и с целыми числами, за исключением побитовых операторов и операторов сдвига.
Над логическим типом
- операторы равенства (== и !=)
- логические операторы (!,&, |, ^)
- условные логические операторы (&&, ||)
- условный оператор (? : )
Преобразование
Существует три типа преобразований:
- расширяющее преобразование (widening)
- суживающее преобразование (narrowing)
- widening + narrowing (преобразование byte к char, сначала byte преобразовываем в int, а потом int — в char)
Расширяющее преобразование
Если оба типа совместимы и длина целевого типа больше длины исходного типа выполняется расширяющее преобразование (напримерbyte преобразуется в int). Следующая таблица демонстрирует все возможные расширяющее преобразования. Курсовом помечены типы, преобразования в которые, возможно, приведут к потери данных.
byte |
short, int, long, float, double |
short |
int, long, float, double |
char |
int, long, float, double |
int |
long, float, double |
long |
float, double |
float |
double (если использовать strictfp потери данных не будет) |
Суживающее преобразование
При суживающем преобразовании возможна потеря информации об общей величине числового значения, также можно потерять точность и диапазон. Все возможные суживающее преобразования показаны в таблице:
short |
byte, char |
char |
byte, short |
int |
byte, short, char |
long |
int, byte, short, char |
float |
long, int, byte, short, char |
double |
float, long, int, byte, short, char |
Чтобы выполнить преобразование двух несовместимых типов необходимо воспользоваться приведением (casting). Если значения исходного целочисленного типа больше допустимого диапазона значений целевого типа, то оно будет сведено к результату деления по модулю на диапазон целевого типа. Если же значения типа с плавающей точкой приводится к значению целочисленного типа, то происходит усечение (отбрасывается дробная часть).
byte a = (byte)128;
byte b = (byte)42;
int i1 = (int)1e20f;
int i2 = (int)Float.NaN;
float f1 = (float)-1e100;
float f2 = (float)1e-50;
Продвижение
Когда требуемая точность промежуточного значения выходит за пределы допустимого диапазона значений любого с операндов в выражении используется автоматическое продвижение типов.
int a = 100;
float b = 50.0f;
double c = 50.0;
double result = a - b + c;
Правила продвижения хорошо демонстрирует следующая диаграмма:
Классы-обертки
Для представления примитивных типов как объектов было сделаны классы-обертки (wrapper classes). Какие преимущества дают нам классы-обертки?
- возможность использования объектов классов-оберток в качестве параметров к методам или как generic-параметры
- возможность использования констант, которые отвечают за границы соответствующего типа данных (MIN_VALUE и MAX_VALUE)
- возможность использования методов для преобразования в другие примитивные типы, конвертации между системами счисления
Wrapper-классов восемь, по одному на каждый примитивный тип:
Примитивный тип |
Класс-обертка |
boolean |
Boolean |
byte |
Byte |
char |
Character |
float |
Float |
int |
Integer |
long |
Long |
short |
Short |
double |
Double |
Почти все классы (кроме Boolean и Character) унаследованы от абстрактного класса Number и являются сравнимыми (реализуют интерфейс Comparable). Иерархия, примерно, такая:
Integer i1 = new Integer("10");
Integer i2 = new Integer(10);
Integer i3 = Integer.valueOf(10);
Integer i4 = Integer.valueOf("10", 10);
Character c1 = new Character('c');
int i5 = i1.intValue();
char c2 = c1.charValue();
Автоупаковка и распаковка
В версии JDK 5 были введены два важных средства:
- Автоупаковка (autoboxing) — процесс автоматического инкапсулирования примитивного типа в соответствующий класс-обертку. Отпадает необходимость явно создавать объект.
- Распаковка (unboxing) — процесс автоматического извлечения примитивного типа с соответствующего класса-обертки. Отпадает необходимость явного вызова метода для получения примитивного типа.
Эти средства облегчают создания объектов, получения примитивных типов, упрощают работу с коллекциями.
public static void main(String... s) {
Integer i1 = 10;
int i2 = i1;
method(10);
++i1;
}
private static int method(Integer i) {
return i;
}
Некоторые полезные методы
Integer i1 = 128;
i1.compareTo(5);
Integer.decode("0xabc");
Integer.parseInt("10", 3);
i1.byteValue();
Float f = 20.5f;
Boolean badFloat = f.isInfinite() || f.isNaN();
f.toString();
Спасибо за внимание. Все дополнения, уточнения и критика приветствуются.
|