Для чего используются обертки примитивов в java
Перейти к содержимому

Для чего используются обертки примитивов в java

  • автор:

Классы Integer, Character, Boolean

Часто бывает предпочтительней работать с объектами, а не с примитивными типами. Так, например, при использовании коллекций, просто необходимо значения примитивных типов каким-то образом представлять в виде объектов. Для этих целей и предназначены так называемые классы-обертки (wrapper classes). Для каждого примитивного типа Java существует свой класс-обертки. Такой класс является неизменяемым, то есть, для изменения значения необходимо создавать новый объект. К тому же класс-обертка имеет атрибут final и его нельзя наследовать.

Все классы-обертки (кроме Void) реализуют интерфейс java.io.Serializable, поэтому объекты любого класса-обертки (кроме Void) могут быть сериализованы. Это имеет важное значение для «сетевых» пересылок объектов.

Классы-обертки содержат статическое поле TYPE — содержащее объект Class, соответствующий примитивному оборачиваемому типу. Также классы-обертки содержат статические методы для обеспечения удобного манипулирования соответствующими примитивными типами, например, преобразование к строковому виду.

Примитивный тип Класс-обертка
byte Byte
short Short
char Character
int Integer
long Long
float Float
double Double
boolean Boolean

Wrapper classes числовых типов (Byte, Short, Integer, Long, Float, Double) наследуются от класса Number, который содержит код, общий для всех классов-оберток числовых типов. Все классы-обертки реализуют интерфейс Comparable.

Классы-обертки числовых типов имеют метод equals(Object), сравнивающий примитивные значения объектов. Но с этим надо быть предельно внимательным. Так в результате выполнения следующего кода

public static void main(String[] args)

мы увидим в консоли следующий текст :

i = 1, b = 1 i.equals(b) = false, b.equals(i) = false

Данный результат связан с тем, что во всех классах-обертках метод equals() сначала производит проверку на совпадение типов (классов), и если нет совпадения, то сразу же возвращает false. В JDK 1.3.1 для класса-обертки Integer метод equals() определен следующим образом :

public boolean equals(java.lang.Object obj)

Класс Number

Абстрактный класс Number является суперклассом для классов Byte, Double, Float, Integer, Long и Short. Наследники Number должны обеспечить методы преобразовывания числовых значений в byte, double, float, int, long и short.

Класс Number имеет один конструктор :

public Number()

Методы класса Number :

Метод Описание
byte byteValue() преобразование значения в тип byte
abstract double doubleValue() преобразование значения в тип double
abstract float floatValue() преобразование значения в тип float
abstract int intValue() преобразование значения в тип int
abstract long longValue() преобразование значения в тип long
short shortValue() преобразование значения в тип short

Класс Integer

Конструкторы класса Integer
  • Integer(int value) — создание объекта Integer на основе аргумента int
  • Integer(String s) — создание объекта Integer на основе строкового аргумента
Поля класса Integer
  • static int MAX_VALUE — максимальная величина типа int
  • static int MIN_VALUE — минимальная величина типа int
  • static Class TYPE — объект класса, представляющий простой тип int
Наиболее значимые методы класса Integer
Метод Описание
byte byteValue() преобразование значения в тип byte
int compareTo(Integer integer) сравнение двух целых чисел
int compareTo(Object o) сравнение значения с другим объектом
Integer decode(String nm) перевод строки в Integer
double doubleValue() преобразование значения в тип double
boolean equals(Object obj) сравнение с другим объектом
float floatValue() преобразование значения в тип float
int hashCode() получение hashcode для обьекта
int intValue() преобразование значения в тип int
long longValue() преобразование значения в тип long
int parseInt(String s) преобразование текстового значения в тип int
int parseInt(String s, int radix) преобразование текстового значения со знаком в системе счисления, определенной во втором аргументе, в тип int
short shortValue() преобразование значения в тип short
String toBinaryString(int i) преобразование целочисленного значения i в текстовый вид с базой 2 (двоичный)
String toHexString(int i) преобразование целочисленного значения i в текстовый вид с базой 16(шестнадцатиричный)
String toOctalString(int i) преобразование целочисленного значения i в текстовый вид с базой 8(восьмиричный)
String toString() преобразование значения в тип String
String toString(int i) преобразование значения i в тип String
String toString(int i, int radix) преобразование целочисленного значения i в строку в заданной системе счисления radix
Integer valueOf(String s) создание объекта Integer, инициализированного величиной, определенной в строковой переменной s
Integer valueOf(String s, int radix) создание объекта Integer, инициализированного величиной, определенной в строковой переменной s, записанной в системе счисления radix

Методы parseInt(), преобразующие текстовое значение в целочисленное, не следует путать с методами valueOf(), возвращающие класс-обертку. Если переданная на вход строка содержит нецифровые символы, то методы возбуждают исключение NumberFormatException.

Дополнительную информацию о классе Integer можно получить на странице Кэширование класса Integer

Класс Byte

Класс Byte является стандартной оболочкой для байтовых величин.

Конструкторы класса Byte
  • Byte (byte value) — создание объекта Byte с определенным значением value;
  • Byte (String s) — создание объекта Byte на основе текстового значения s.
Поля класса Byte
  • static int MAX_VALUE — максимальная величина типа byte
  • static int MIN_VALUE — минимальная величина типа byte
  • static Class TYPE — объект класса, представляющий простой байтовый тип byte
Методы класса Byte
Метод Описание
byte byteValue() получение значения типа byte
int compareTo(Byte byte) сравнение с объектом Byte
int compareTo(Object o) сравнение с другим объектом
static Byte decode(String nm) преобразование строки в Byte
double doubleValue() преобразование значения в double
boolean equals(Object obj) проверка на равенство с другим объектом
float floatValue() преобразование значения в float
int hashCode() получение hash-кода объекта
int intValue() преобразование значения в int
long longValue() преобразование значения в long
static byte parseByte(String s) преобразование текстового значения в byte
static byte parseByte(String s, int radix) преобразование текстового значения в системе счисления radix в байт
short shortValue() преобразование значения в short
String toString() преобразование значения в String
static String toString(byte b) преобразование байтового значения в String
static Byte valueOf(String s) преобразование текстового значения в Byte
static Byte valueOf(String s, int radix) преобразование текстового значения в системе счисления radix в Byte

Класс Boolean

Класс Boolean является оболочкой простого логического объекта. Объект типа Boolean содержит единственное поле логического типа. Кроме того, этот класс включает методы преобразования boolean в String и обратно, а также константы и методы полезные при работе с логическим типом.

Конструкторы класса Boolean
  • Boolean (boolean value) — создание логического объекта на основе аргумента;
  • Boolean (String s) — создание логического объекта на основе текстового значения s [«true» | «false»].
Поля класса Boolean
  • static Boolean FALSE — логический объект, соответствующий значению «ложь»
  • static Boolean TRUE — логический объект, соответствующий значению «истина»
  • static Class TYPE — объект класса, представляющий простой логический тип
Методы класса Boolean
Метод Описание
boolean booleanValue() получение логического значения
boolean equals(Object obj) функция возвращает логическое значение по результату сравнения переданного объекта с текущим
static boolean getBoolean(String name) преобразование текстового значения в логическое
int hashCode() получение hash-кода объекта
String toString() преобразование в текстовое значение
static Boolean valueOf(String s) преобразование текстового значения в Boolean

Класс Void

Класс-обертка Void, в отличии от остальных, НЕ реализует интерфейс java.io.Serializable и не имеет открытого конструктора. Более того, экземпляр класса Void вообще не может быть получен. Он нужен только для получения ссылки на объект, соответствующий void. Эта ссылка представлена статической константой TYPE. Выражение void.class == Void.TYPE вернет «true».

В большинстве случаев, если нужно проверить возвращаемый тип метода (например, через рефлексию) можно использовать void.class — не перепутаешь с Void.class.

Использовать Void можно, например, в случаях, когда имеется обобщенный класс (generic) и необходимо, чтобы метод ничего не возвращал :

interface IVoid  < T doStuff(); >class A implements IVoid  < @Override public Void doStuff() < // . return null; // ничего другого вернуть нельзя (если // не хитрить с рефлексией, конечно) >>

Класс Character

Для хранения символов Java использует специальный тип char. В отличие от языка C/C++, где char представляет собой целочисленный тип с размером 8 бит, в Java для char применяется кодировка Unicode и для хранения Unicode-символов используется 16 бит. Диапазон допустимых значений — от 0 до 65536 (отрицательных значений не существует).

Класс Character является оболочкой вокруг типа char. Чтобы получить значение типа char, содержащее в объекте Character, необходимо вызвать метод charValue().

Конструктор класса Character

Character имеет только один конструктор, которому в качестве параметра передается значение char.

Character ch = new Character('a');

Помимо констант MIN_VALUE и MAX_VALUE, Character содержит две константы MIN_RADIX и MAX_RADIX, которые равны минимальному и максимальному основанию системы счисления, которые используются методами (представленными ниже) для перевода отдельного цифрового символа в его целочисленный эквивалент и наоборот. Основание должно находиться в диапазоне 2–36; цифры свыше 9 представлены буквами от A до Z или их эквивалентами в нижнем регистре.

Классы-обертки

У многих мог возникнуть вопрос: зачем задавать целочисленную переменную не int , а Integer ? Часто классы-обертки используют для того, чтобы сохранять данные в коллекции. Все дело в том, что коллекции — это набор объектов, и для того, чтобы оперировать примитивными типами как объектами, и были придуманы классы обертки.

Рассмотрим классы-обертки для примитивных типов данных.

Данные классы имеют название, которое происходит от названия примитивного типа данных, который они представляют: Double, Float, Long, Integer, Short, Byte, Character, Boolean .

Данные классы очень напоминают класс String . Объект обертку для примитивного типа можно создать как явно (используя конструктор), так и не явно (прямым присвоением примитива классу обертке) с помощью оператора = либо при передаче примитива в параметры метода (типа «класса-обертки»). Последнее еще называют автоупаковка (autoboxing).

public class AutoBoxing < public static void main(String[] args)< Integer a = new Integer(777); //явное создание переменной обертки int b = a; //неявное создание. > > 

Как и все объекты, переменные, созданные с помощью классов-оберток, будут храниться в куче ( heap ). Но, есть одно важное замечание, о котором часто любят спрашивать в тестах или на собеседованиях. Оно касается целочисленных классов оберток. Неявное создание таких переменных со значением в диапазоне -128 +127 будут храниться в пуле int-ов (В Java есть пул ( pool ) целых чисел в промежутке [-128;127]. Т.е. если мы создаем Integer в этом промежутке, то вместо того, чтобы каждый раз создавать новый объект, JVM берет их из пула). Потому такие обертки с одинаковыми значениями будут являться ссылками на один объект.

Автоупаковка переменных примитивных типов требует точного соответствия типа исходного примитива типу «класса-обертки». Попытка автоупаковать переменную типа byte в Short , без предварительного явного приведения byte->short вызовет ошибку компиляции.

public class AutoBoxing < public static void main(String[] args)< Integer integerA = new Integer(23); Integer integerB = new Integer(777); integerB = new Integer(888); System.out.println("integerA = " + integerA); Integer integerC = new Integer(666); Integer integerD = new Integer(2412); integerD = new Integer(1991); System.out.println("integerD = " + integerD); > > 

Результат работы программы:

integerA = 23 integerD = 1991 

Классы-обертки удобны еще тем, что они предоставляют методы для работы с соответствующими типами данных.

Давайте посмотрим на самые популярные:

public class AutoBoxing < public static void main(String[] args)< String a = "45"; double b = Double.parseDouble(a); // наверное, самый популярный метод перевод из строки в целочисленный или дробный тип int c = Integer.parseInt(a); System.out.println(b); System.out.println(c); System.out.println(Integer.MAX_VALUE); // константа максимального значения System.out.println(Integer.bitCount(78)); // представляет число в двоичном виде System.out.println(Float.valueOf("80")); // возвращает целочисленный объект, содержащий значение указанного типа System.out.println(Integer.valueOf("444", 16)); // возвращает целочисленный объект, содержащий целое значение указанного строкового представления в 16-ричной системе счисления > > 

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

results matching » «

No results matching » «

Pro Java

Мы уже сталкивались с классами обертками (wrapper classes) для примитивных типов, но пока не заостряли на них внимание. Сейчас же мы рассмотрим их более подробно, чтобы понять что такое методы классов и что такое поля классов.

Как вы уже знаете, в Java для хранения базовых типов данных, поддерживаемых языком, используются примитивные типы (также называемые простыми типами), такие как int или double. Примитивные типы, в отличие от объектов, используются для таких значений из соображений производительности. Применение объектов для этих значений добавляет нежелательные накладные расходы, даже в случае простейших вычислений.

Несмотря на то что примитивные типы обеспечивают выигрыш производительности, бывают случаи, когда вам может понадобиться объектное представление. Например, вы не можете передать в метод примитивный тип по ссылке. Кроме того, многие из стандартных структур данных, реализованных в Java, оперируют с объектами, что означает, что вы не можете применять эти структуры данных для сохранения примитивных типов. Чтобы справиться с такими (и подобными) ситуациями, Java предлагает обертки примитивных типов, которые представляют собой классы, помещающие примитивный тип в объект.

Обертки для примитивных типов — это Double, Float, Long, Integer, Short, Byte, Character и Boolean. Эти классы предоставляют широкий диапазон методов, позволяющий в полной мере интегрировать примитивные типы в иерархию объектных типов Java.

И далее уже рассмотрим примеры работы с методами этих классов.

W00001

По существу мы много раз использовали поле length массива args, для поучения количества его элементов. Это один из примеров работы с полями объекта класса.

Примером работы с методами класса являются строки 11 и 13.

В 11 строке мы проверяем если первый аргумент командной строки является строкой true, то тогда переменной wBoolean присваивается значение true. В ином случае оно остается равным false, как было задано при инициализации.

Пример вывода этой программы представлен ниже.

W00002

Теперь небольшой пример использования класса Character:

W00001

В данном примере использован статический метод isDigit класса Character, для определения является ли элемент массива символом или числом.

Метод isDigit возвращает true, если переданный ему как параметр тип char является числом, во всех других случаях возвращается false.

Кроме того здесь еще так же использован оператор continue, который переводит цикл на следующую итерацию, если бы его не было, то вывод в строке 15 совершался бы даже тогда, когда проверяемое значение являлось бы числом.

Класс Charaster содержит множество полезных методов и полей. Все это можно узнать из оригинальной документации.

Вывод данной программы может быть таким (зависит от аргументов командной строки):

W00002

Ну и несколько примеров с классами обертками для числовых типов:

W00003

Тут просто показано использование некоторых статических методов классов Byte и Integer, а так же использование статических полей типа MAX_VALUE.

Статический метод parseInt преобразует строку в число типа int.

Статический метод bitCount подсчитывает количество битов равных единице в переданном, как аргумент числовом типе.

Кроме этих методов и полей, у классов-оберток есть еще множество других. Поэтому, если вам понадобятся какие-либо операции над этими типами, то посмотрите сперва в стандартной библиотеке.

Данная программа генерирует следующий вывод:

W00004

На этом я думаю с этой темой закончим. Цель была познакомиться с тем, что такое методы и поля классов. Хотя пока, может, это все ясности и не добавило, но на подкорку должно было осесть.

Далее будем рассматривать массивы и строки. Все они относятся к ссылочным типам данных Java и соответственно имеют свои поля и методы. То есть мы будем еще глубже знакомиться с тем что такое объекты и с чем их едят. И затем уже перейдем непосредственно к понятию класса.

Объектные обёртки. Autoboxing

Объекты и примитивы в Java — две абсолютно разные группы типов. Виртуальная машина работает с ними по-разному. Аналогично, массивы примитивов и массивы объектов — разные типы. Generics работают только со ссылочными типами. Это значит, что можно создать, например, List, List, List, List, List> , но нельзя — List или List , т. к. int и long — примитивные типы.

Так как иногда таки возникает необходимость создать список, например, целых чисел, можно создать класс, который позволит представить целое число как объект.

public class Int < private final int value; public Int(int value) < this.value = value; >public int getValue() < return value; >>

К величайшей радости, этот костыль уже написан за нас. В основном пакете, java.lang , уже есть классы Boolean , Byte , Short , Character , Integer , Float , Long , Double . Эти классы называют объектными обёртками (boxed primitives). Они предоставляют тот же функционал, что и примитивные типы, только делают это как объекты — посредством классов и методов.

Это даёт возможность создать, например, List .

Для преобразования значения примитивного типа есть статические методы valueOf , например, Integer.valueOf(4) вернёт объект типа Integer . Для обратного преобразования есть методы intValue() , longValue() и т. п..

Integer objTen = Integer.valueOf(10); int iTen = objTen.intValue();

Autoboxing

Компилятор может вставить вызовы valueOf и *Value автоматически, это называется autoboxing и autounboxing соответственно.

Integer objTen = 10; int iTen = objTen;

Кэш объектов

Так как объекты класса Integer неизменяемы (immutable), их можно кешировать и переиспользовать. Но кэш всего диапазона int’ов, [-2 147 483 648, 2 147 483 647] , занимал бы очень много места, поэтому Integer ‘ы кешируются только в диапазоне [-128, 127] . То есть Integer.valueOf(127) каждый раз возвращает один и тот же объект, а Integer.valueOf(128) каждый раз выделяет новый.

С этой особенностью связан известный паззлер, т. е. код, поведение которого сбивает с толку:

Integer a = 127; Integer b = 127; Integer c = 128; Integer d = 128; System.out.println(a == b); // true System.out.ptintln(c == d); // false

При этом, конечно же, c.equals(d) == true .

Пример использования

List ints = new ArrayList<>(); ints.add(1); ints.add(2); System.out.println(ints); // [1, 2]

При этом можно использовать все преимущества списков — методы contains , indexOf и прочие.

Используйте обёртки только при необходимости

Обёртки (boxed primitives) занимают в памяти больше места, чем примитивы. Так как объектные обёртки иммутабельны, любая арифметическая операция выделяет новый объект с новым значением. Например, в этом коде вычисления проводятся с примитивами, как и должно быть:

long sum = 0; for (long n : numbers) < sum += n; >System.out.println(sum);

Но если в первой строке (без причины) использовать объектную обёртку,

Long sum = 0; for (long n /* unboxing */ : numbers) < sum += n; // boxing — здесь выделяется новый объект // эквивалентно sum = Long.valueOf(sum.longValue() + n) >System.out.println(sum);

то этот код отработает в несколько раз медленнее и выделит много новых объектов, создавая лишнюю работу для сборщика мусора.

Не используйте конструкторы обёрток

Правильный способ получить boxed primitive — это метод valueOf . Есть также неправильный — явный вызов конструктора. По ошибке конструктор публичный, хотя должен быть приватным. Integer.valueOf(0) при каждом вызове будет возвращать один и тот же объект из кэша, а new Integer(0) каждый раз будет создавать новый.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *