Плюсы и минусы частных классов пакетов в Java?

Недавно я изучаю Java и наткнулся на понятие package-private классов, которое используется по умолчанию, если мы ничего не указываем. Но потом я понял:

  1. Я редко вижу использование класса package-private. В чем причина, например, в нем есть серьезные недостатки, он избыточен или просто я мало читаю? Есть ли веские аргументы за/против его использования?

  2. Если это действительно бесполезно в большинстве случаев, почему это должно быть по умолчанию?

  3. В какой ситуации мы должны использовать package-private в реальном мире? То есть, когда он станет незаменимым?

Другими словами, каковы основные плюсы и минусы модификатора package-private по умолчанию?


person zw324    schedule 24.06.2011    source источник


Ответы (8)


Короткий ответ - это немного более широкая форма частного.

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

Что ж, в дополнение к этому - если вы думаете о создании своего программного обеспечения по модульному принципу, вы можете подумать об общедоступном интерфейсе для вашего модуля, внутри которого будет несколько классов, взаимодействующих друг с другом. . В этом контексте имеет смысл сделать методы public, если они будут вызываться потребителями; private если они являются внутренними по отношению к классу; и package private, если они используются для вызова между классами в этом модуле, т. е. это деталь реализации вашего модуля (как ее видят публичные вызывающие программы), но она охватывает несколько классов.

Это редко используется на практике, потому что система пакетов оказывается не очень полезной для такого рода вещей. Вам придется свалить все классы для данного модуля в один и тот же пакет, что для чего-то нетривиального станет немного громоздким. Итак, идея великолепна — сделать метод доступным только для нескольких «близлежащих» классов, как немного более широкий private — но ограничения на то, как вы определяете этот набор классов, означают, что он редко используется/полезен.

person Andrzej Doyle    schedule 24.06.2011
comment
Я понимаю, почему кто-то мог так сказать — модификатор protected такой же, как package private, за исключением того, что подклассы также приглашаются на вечеринку. Но было бы неправильно создавать отношения подкласса (только для целей доступа), если бы они не существовали естественным образом. Обычно это не имеет смысла, например. класс EmailSender должен быть подклассом класса DomainObjectFilter или наоборот. В этой ситуации метод обычно просто делается public (возможно, с комментарием о том, что он концептуально не является общедоступным...). - person Andrzej Doyle; 24.06.2011
comment
сбрасывать все классы данного модуля в один и тот же пакет -- громоздко -- Правильно, но я использовал этот подход даже в нетривиальных случаях, например, 20-30 классов в пакете. Все, что больше, конечно, нуждается в рефакторинге. - person Victor Sorokin; 24.06.2011
comment
Не могли бы вы организовать свои исходные файлы в иерархию каталогов, а затем во время сборки сбросить их все в один и тот же каталог/пакет перед компиляцией? Это дало бы вам организационную структуру и преимущества частного доступа к пакету, верно? - person jmrah; 28.09.2015
comment
@jrahhali, вы могли бы это сделать, но я сомневаюсь, что вы найдете IDE, которая согласится на это. Я думаю, это было бы довольно раздражающим, если бы вы не написали расширение IDE, которое знает, что вы имеете в виду. - person froginvasion; 24.01.2019
comment
Чтобы использовать модификатор частной видимости пакета, а также использовать модули с модификаторами на основе иерархии, вы можете использовать экспериментальный проект github.com /odrotbohm/moduliths, который хорошо подходит для такого сценария, - person Lubo; 31.03.2020

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

person David    schedule 24.06.2011

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

В качестве примера вы можете взглянуть на библиотеку, которую я разработал. javadoc содержит только 5 интерфейсов и 12 классов, хотя исходный код содержит намного больше. Но то, что скрыто, — это в основном внутренние слои, которые не предоставляют никакой дополнительной ценности для клиента (обычно скрыты все абстрактные базовые классы).

В JDK также есть много примеров.

person assylias    schedule 01.07.2013

Уровень доступа для пакетов более строгий, чем protected: к защищенным атрибутам и методам по-прежнему можно получить доступ, просто создав подкласс класса. Члены Protected предназначены (или могут быть) для наследования, а члены package-private — нет.

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

Хорошими примерами этого являются закрытый для пакета конструктор String и массив символов StringBuilder.value:

/*
* Package private constructor which shares value array for speed.
* this constructor is always expected to be called with share==true.
* a separate constructor is needed because we already have a public
* String(char[]) constructor that makes a copy of the given char[].
*/
String(char[] value, boolean share) {
    // assert share : "unshared not supported";
    this.value = value;
}

Таким образом, классы внутри пакета java.lang могут эффективно создавать новые Strings, если содержимое уже присутствует в char[], без ущерба для безопасности. Вы не можете сделать это из своего приложения, потому что, если бы вы могли, у вас был бы доступ (ссылка) к внутреннему массиву символов String, который является неизменным (отражение не учитывается!).

В StringBuilder (или, скорее, AbstractStringBuilder, откуда берется реализация) массив символов, содержащий текущее значение char[] value, и метод доступа к этому char[] getValue() также являются частными для пакета, поэтому различные служебные методы String, такие как contentEquals(StringBuffer sb) и contentEquals(CharSequence cs), могут использовать это для повышения эффективности и более быстрого сравнения. без раскрытия внутреннего массива символов «миру».

person icza    schedule 10.02.2015

Что касается вопроса «почему это значение по умолчанию», в этом контексте термин «по умолчанию» просто означает отсутствие другого квалификатора. Думаю, они могли бы придумать другое ключевое слово ("пакет" уже занят), но не сделали этого.

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

Другая причина, по которой вы не видели, чтобы он использовался чаще, заключается в том, что люди склонны исключать классы с доступом по умолчанию из своих javadocs.

person jtoberon    schedule 24.06.2011
comment
Он не неправильно понимает термин «по умолчанию», он спрашивает, почему это уровень доступа по умолчанию. Одной из причин значения по умолчанию является то, что что-то используется чаще всего. Есть и другие причины, и он спрашивает о них. - person B T; 26.07.2011
comment
Я не уверен, что вы правы, но я рад обновить ответ для ясности. - person jtoberon; 26.07.2011

1 - Зависит от архитектуры. Обычно, если вы пишете код только для себя и в небольших проектах, вы, вероятно, не будете его использовать. В более крупных проектах может быть полезно убедиться, что вы можете контролировать, где и как вызываются определенные методы.

2 - По умолчанию (т.е. не общедоступный/защищенный/частный) не то же самое, что частный - это 4-е состояние. См. раздел управление доступом к Java.

3. Это может облегчить жизнь, когда вы пишете библиотеки, которые вы не хотите, чтобы третьи стороны полагались на то, как вы реализуете базовый код — вы просто делаете общедоступным сам API.

person BZ.    schedule 24.06.2011
comment
@BZ Разве пакет по умолчанию не является частным? - person zw324; 24.06.2011
comment
@BZ Который сказал: если у класса нет модификатора (по умолчанию, также известный как частный пакет). Спасибо за ответ, терминология тривиальна :) - person zw324; 24.06.2011
comment
Посмотрите на таблицу разрешений - есть разница между приватным и без модификатора. Ни один модификатор в пакете не может его прочитать, поэтому он не является действительно приватным. Это ОГРОМНОЕ отличие от частного класса. - person BZ.; 24.06.2011
comment
@BZ - термины по умолчанию и частный пакет часто используются как синонимы. Похоже, вы не заметили, что Зияо использовал составной термин из двух слов, а не просто частное. - person Andrzej Doyle; 24.06.2011
comment
@BZ Да, я это заметил, поэтому я сказал, что пакет приватный. Думаю, я забыл дефис :) РЕДАКТИРОВАТЬ: Хорошо, дефис добавлен. - person zw324; 24.06.2011
comment
По умолчанию используется частный пакет. Тем не менее, это не то же самое, что private. - person Fabian Barney; 24.06.2011

«Частный пакет» используется, когда у вас есть несколько пакетов, и это означает, что другие классы в том же пакете могут получить доступ к этому классу или члену класса как «общедоступный», классы в других пакетах не могут получить доступ, это как «частный, как они».

person umlcat    schedule 24.06.2011

Обратите внимание, что когда вы говорите о классах, у вас есть только два варианта:

  1. публичные занятия
  2. пакетные частные занятия

Понятие «частный класс» бессмысленно. (Зачем делать класс, который нигде не используется?!)

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

Кроме того, когда вы определяете много классов в одном и том же исходном файле, только один класс может быть общедоступным (его имя соответствует имени файла .java). Если какой-либо другой класс определен в том же файле, он должен быть «приватным для пакета».

person AbdelRahman Shabana    schedule 03.01.2013
comment
Этот ответ в лучшем случае вводит в заблуждение. Статический вложенный класс — это пример, когда концепция закрытого класса может иметь смысл. См. также: stackoverflow.com/a/34551507 - person Synoli; 26.04.2018