Java: доступ подкласса без доступа к пакету

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

Разве это не полностью назад? Скажем, у меня есть класс ControlledInstantiation в некотором пакете. Если у меня есть еще один класс, то иControlledInstantiation расширяет ControlledInstantiation, я не могу вызвать конструктор ControlledInstantiation, если я не настроил его на защищенный или открытый. И если я установил его для защиты, теперь любой другой класс в пакете может создавать его так часто, как ему нравится. Таким образом, что-то, что обязано быть заменяемым для своего суперкласса (и, синтаксически, есть), получает тот же или менее доступ к суперклассу, чем то, что служит отдельной, но связанной функции. Мне нравится рассказывать своему ребенку, что он не может играть с вашим кошельком, потому что вы не позволите своим соседам сделать это, а затем разрешите своим сосерам спать в вашем доме, потому что ваш ребенок делает.

Итак, я думаю, я спрашиваю, что мотивировало это решение, и как я могу обойти его?

Ответ 1

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

На самом деле у Java действительно был модификатор private protected, который достиг бы того, что вам нужно, но он был удален, я думаю, потому что он смутил людей. Я не уверен, как вы могли бы достичь этого, не отбрасывая каждую пару класса/подкласса в свой собственный пакет. Но это грязное решение, которое противоречит принципам Java, и в любом случае оно не будет работать для иерархии наследования более двух классов.

Ответ 2

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

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

  • Если вы действительно хотите избежать доступа к защищенному методу членами пакета, вы можете решить эту проблему хотя бы во время выполнения, используя Throwable.getStacktrace():

    if(!getClass().isAssignableFrom(
        Class.forName(new Throwable().getStackTrace()[1].getClassName()))) {
            throw new IllegalAccessException(
                "This method can be accessed by subclass only");
    }
    

Ответ 3

Вы можете запечатать пакет. См. Спецификацию файла JAR.