Когда использовать класс-оболочку и примитивный тип

99

Когда мне следует использовать класс-оболочку вместо примитивных типов? Или при каких обстоятельствах мне следует выбирать между типами обертки / примитивы?

Гопи
источник
1
w3resource.com/java-tutorial/java-wrapper-classes.php Эта статья будет полезна для обсуждения.
pankaj

Ответы:

69

Другие упоминали, что определенные конструкции, такие как Collectionsrequire объектов, и что объекты имеют больше накладных расходов, чем их примитивные аналоги (память и упаковка).

Еще одно соображение:

Может быть удобно инициализировать объекты nullили отправлять nullпараметры в метод / конструктор, чтобы указать состояние или функцию. Этого нельзя сделать с примитивами.

Многие программисты для обозначения этого инициализируют числа равными 0 (по умолчанию) или -1, но в зависимости от сценария это может быть неверным или вводящим в заблуждение.

Это также установит сцену для случая, NullPointerExceptionкогда что-то используется неправильно, что гораздо удобнее для программистов, чем какая-то произвольная ошибка в дальнейшем.

пстантон
источник
15
«Может быть удобно инициализировать объекты нулевым значением». Это не может быть удобно, потому что это неверно, если поле является необязательным, вы должны указать это явно.
Эдди Джемсессион
8
lol @EddieJamsession, спасибо, я больше никогда не инициализирую значение null. (pfffft)
pstanton 01
@EddieJamsession Если инициализация объектов нулевым значением как способ указать на сбой при установке фактического значения не удалась, как еще вы предложили бы решить эту проблему? О, я только что понял, набирая это: исключения. Исключение NullPointerException слишком общее; было бы лучше использовать очень конкретные пользовательские исключения, чтобы указать, что пошло не так. Хорошо, с этого
момента
1
@EddieJamsession Прочитав по этому поводу, я столкнулся с концепцией необязательного объекта. Правильно.
klaar
18

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

Мэтью Флашен
источник
3
снижение производительности не настолько велико, чтобы разборчивость / надежность кода отошли на второй план.
pstanton
2
Во-первых, правильное использование примитивов не сделает ваш код неразборчивым. Во-вторых, в некоторых случаях существенно снижается производительность. Абсурдно говорить, что этого никогда не было.
Мэтью Флашен,
1
@pstanton: объясните, пожалуйста, как Integerразборчивее, чем int.
Стивен С.
Во многих случаях Integer не более разборчив, чем int, и в этих случаях я всегда буду использовать int, или, если я знаю, что определенная переменная НИКОГДА не будет иметь значение null, я буду использовать int, потому что int, как вы указали, немного более эффективен. Однако во многих случаях другому программисту легче понять состояние переменной при использовании объекта, поскольку он может быть инициализирован нулевым значением, чтобы указать, что он не готов. Например, если у вас есть несохраненная запись базы данных с уникальным увеличивающимся числовым идентификатором, должен ли этот идентификатор быть 0, -1 или нулем до того, как ему будет назначен действительный идентификатор? В этом случае объекты лучше.
pstanton
в отношении производительности - в особых случаях снижение производительности может быть значительным, например, если вы создаете множество этих объектов очень быстро или если многие из них накапливаются за определенный период времени. Тем не менее, я ожидаю, что порядочный программист сможет определить эти особые случаи, либо избежать, либо исправить соответственно. Я никогда не говорил, что это НИКОГДА не важно, но в целом это не так.
pstanton
12

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

1.

class Person {
   int SSN ; // gets initialized to zero by default 
}

2.

class PersonBetter {
  Integer SSN; //gets initialized to null by default
}

В первом случае нельзя оставить значение SSN неинициализированным. Это может повредить, если вы не проверяете, было ли установлено значение перед попыткой его использования.

Во втором случае вы можете оставить SSN инициализированным значением null. Что может привести к NullPointerException, но это лучше, чем бессознательная вставка значений по умолчанию (ноль) в качестве SSN в базу данных всякий раз, когда вы пытаетесь использовать его без инициализации поля SSN.

Коди
источник
3
Паттерн строитель предназначен для того, чтобы обойти это. В этом сценарии вы создаете PersonBuilderисключение, если SSN не установлен до вызова «build» для получения Personэкземпляра. Я думаю, что такого рода вещи излишни, но это то, что язык Java продвигает для правильных шаблонов.
Sandy Chapman
8

Я бы использовал типы обертки только в случае необходимости.

Используя их, вы ничего не выиграете, кроме того, что они есть Objects.

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

jjnguy
источник
4
Вы можете не получить много, но и не потеряете много. если только вы не работаете на ладонном пилоте 1990-х годов.
pstanton
Тот факт, что они являются объектами, также дает им гораздо больше контекста и инкапсуляции, чем простой примитив. Таким образом, вы действительно можете многое получить в зависимости от того, для чего предназначены эти примитивы и где они используются.
aberrant80
4

Практически я столкнулся с ситуацией, когда можно объяснить использование класса-оболочки.

Я создал класс обслуживания с longпеременной типа

  1. Если переменная имеет тип long- когда она не инициализирована, она будет установлена ​​в 0 - это будет сбивать с толку пользователя при отображении в графическом интерфейсе.
  2. Если переменная имеет тип Long- когда она не инициализирована, ей будет присвоено nullзначение - это нулевое значение не будет отображаться в графическом интерфейсе.

Это также относится к тем Booleanслучаям, когда значения могут быть более запутанными, когда мы используем примитив boolean(поскольку значение по умолчанию - false).

Мохамед Афзал
источник
3

Коллекции - типичный случай для простых объектов-оболочек Java. Однако вы можете подумать о том, чтобы придать Wrapper более конкретное значение в коде (объект значения).

ИМХО почти всегда есть преимущество в использовании объектов значений, когда все сводится к удобочитаемости и поддержке кода. Обертывание простых структур данных внутри объектов, когда у них есть определенные обязанности, часто упрощает код. Это очень важно в доменно-ориентированном дизайне .

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

Маттиас Холмквист
источник
3

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

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

«Примитивные типы считаются вредными», потому что они смешивают «процедурную семантику с единой объектно-ориентированной моделью».

Многие программисты для обозначения этого инициализируют числа равными 0 (по умолчанию) или -1, но в зависимости от сценария это может быть неверным или вводящим в заблуждение.

Локнатх
источник
1

Если вы хотите использовать Коллекции, вы должны использовать классы Wrapper.

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

После автобокса граница «когда использовать примитив или оболочку» стала довольно нечеткой.

Но помните, что оболочки - это объекты, поэтому вы получаете все модные функции Java. Например, вы можете использовать отражение для создания объектов типа Integer, но не значений типа int. Классы-оболочки также имеют такие методы, как valueOf.

Том
источник
Кроме коллекций, мне не следует использовать классы-оболочки? Как насчет использования его для обычного объявления типа Integer i = new Integer (10); Это хорошо?
Гопи
автобокс позволяет делать Integer i = 10;
Том
1
Нет, Шри. Если у вас нет требования, чтобы я был объектом, не делайте этого.
Мэтью Флашен,
Autoboxing распакует объявленный выше i в int i = 10 или Integer i = 10?
Гопи,
3
int pi = новое целое число (10); работает. Целое число oi = 10; работает. int ni = ноль; не работает. LHS преобразуется во все, что требуется для RHS.
pstanton
0

Если вы хотите создать тип значения. Что-то вроде ProductSKU или AirportCode.

Когда примитивный тип (строка в моих примерах) определяет равенство, вы захотите переопределить равенство.

Крис Миссал
источник
5
строка - это не примитив
pstanton
2
по-прежнему есть веские причины использовать тип значения, содержащий строку, в качестве базового объекта.
Крис Миссал,
ваш ответ просто не имеет смысла. я не уверен, что вы говорите. Я согласен с вашим комментарием, классы-оболочки - хорошая идея, если они улучшают читаемость.
pstanton
Типы значений или объекты значений должны создаваться и быть неизменными. Например, не имеет смысла создавать объект "CountryCode", например: new CountryCode ("USA"), а затем таким же образом создавать другой объект, но позже они будут другими. Это просто нити для начала, но за ними стоит смысл. Используя строки, вы можете изменять их (добавляя больше данных и т. Д.), Но они больше не будут равны. См. Эту статью для лучшего описания того, что я пытаюсь объяснить :) Надеюсь, это имеет смысл c2.com/cgi/wiki?ValueObject
Крис Миссал
0

Примитивные значения в Java не являются объектами. Чтобы управлять этими значениями как объектами, пакет java.lang предоставляет класс-оболочку для каждого примитивного типа данных.

Все классы Wrapper являются окончательными. Объекты всех классов оболочки, которые могут быть инициированы, являются неизменяемыми, что означает, что значение в объекте оболочки не может быть изменено.

Хотя класс void считается классом-оболочкой, но он не содержит никаких примитивных значений и не инициируется. У него нет общедоступного конструктора, он просто обозначает объект класса, представляющий ключевое слово void.

Ахмад Сайид
источник