Почему в Java отсутствует директива friend?

Мне было интересно, почему Java была разработана без директивы friend, которая доступна на С++, чтобы позволить более тонкий контроль над тем, какие методы и переменные экземпляра доступны извне пакета, в котором был определен класс.

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

Ответ 1

Вот несколько причин от головы:

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

Ответ 2

В целом, я думаю, что это связано с добавленной когнитивной сложностью и небольшим количеством случаев, когда оно создает улучшение.

Я бы сказал, что чрезвычайно большое количество строк java в производстве на данный момент может подтвердить, что ключевое слово friend на самом деле не большая потеря:).

Пожалуйста, см. @dwb ответ на некоторые более конкретные причины.

Ответ 3

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

Вопреки распространенному мнению, здесь много случаев, в частности, для инфраструктурных возможностей, когда доступ к друзьям ведет к более легкому дизайну, а не к худшему дизайну. Инкапсуляция часто нарушается, когда метод FORCED становится общедоступным, когда его действительно не должно быть, но у нас нет выбора, потому что Java не поддерживает друзей.

Ответ 4

В дополнение к вышеупомянутой видимости пакета Java также предлагает внутренние и анонимные классы, которые по умолчанию являются не только друзьями, но также автоматически ссылаются на содержащийся класс. Поскольку создание таких вспомогательных классов, вероятно, является единственным разумным способом использования friend в С++, Java не нуждается в нем, поскольку для этого есть другой механизм. Итераторы - очень хороший пример этого.

Ответ 5

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

Ответ 6

Просто добавьте к другим ответам:

В Java есть видимость пакета по умолчанию. Таким образом, вы можете вызвать все классы в одном сосете пакетов. В этом случае у вас есть явный контроль над тем, что вы показываете соседям - просто члены с видимостью пакета.

Итак, это не совсем друг, но может быть похожим. И да, это тоже приводит к плохому дизайну...

Ответ 7

По моему мнению, какая-то особенность друга (не обязательно очень похожая на С++) была бы очень полезна в некоторых ситуациях на Java. В настоящее время у нас есть хакеры для доступа к частным/дефолтным пакетам для совместной работы между тесно связанными классами в одном пакете (например, String и StringBuffer), но это открывает частный интерфейс реализации для всего пакета. Между пакетами у нас есть злые рефлексивные хаки, которые вызывают целый ряд проблем.

В Java есть несколько дополнительных осложнений. С++ игнорирует ограничения доступа при разрешении перегрузок функций (и подобных) - если компиляция программы #define private public не должна ничего делать. Java (в основном) отбрасывает не доступных членов. Если нужно учитывать дружбу, то резолюция является более сложной и менее очевидной.

Ответ 8

Полностью согласен с косвенным выражением в его ответе

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

Мой пример прост - если класс A должен предоставить специальный интерфейс "friend" для класса B в java, мы должны поместить их в один и тот же пакет. Без исключений. В этом случае, если A является другом B и B является другом C, A должен быть другом C, что не всегда верно. Эта "транзитивность дружбы" разрушает инкапсуляцию больше, чем любые проблемы, к которым может привести дружба С++.