Почему для исходных файлов java требуются объявления пакетов?

Я думаю, что я не понимаю структуру пакета java, мне показалось излишним, что в java файлах есть декларация пакета внутри, а затем также должны присутствовать в каталоге, соответствующем имени пакета. Например, если у меня есть файл MyClass.java:

package com.example;

public class MyClass {
    public static void main(String[] args) {
        System.out.println("Hello, World");
    }
}

Тогда мне потребуется, чтобы этот файл находился в com/example относительно базового каталога, и я выполнил бы java com.example.MyClass из базового каталога, чтобы запустить его.

Почему компилятор не смог бы вывести имя пакета, просмотрев структуру каталогов? Например, если я скомпилировал файл из базового каталога javac com\example\MyClass.java, я не понимаю, почему MyClass.java не будет подразумевать принадлежность к пакету com.example.

Я понимаю, что есть пакет по умолчанию, но все же кажется, что объявление пакета в исходном файле является избыточной информацией?

Ответ 1

Как вы (неявно) подтвердили, вам не требуется объявлять имя пакета... в случае, если пакет по умолчанию.

Игнорируя этот вопрос... причина этой кажущейся избыточности заключается в том, что без требования для объявления package значение исходного кода Java будет неоднозначным. Например, исходный файл, чей путь был "/home/steve/project/src/com/example/Main.java", мог иметь 7 разных полных имен... в зависимости от того, как вы скомпилировали код. Скорее всего, только один из них будет "правильным". Но вы не сможете сказать, какой из них правильный, посмотрев (просто) файл исходного кода.

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

Ответ 2

Поверните вопрос на голову:

Предположим, что инструкция пакета является важной вещью. Она представляет пространство имен класса и принадлежит к файлу класса.

Итак, теперь вопрос: почему классы должны быть в папках, соответствующих их пакету?

Ответ заключается в том, что он упрощает их поиск - это просто хороший способ организовать их.

Помогает ли это?

Ответ 3

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

Пакет необходим для устранения неоднозначности класса из других классов с тем же именем. Например, java.util.Date отличается от java.sql.Date. Пакет также предоставляет доступ к методам или членам, которые являются package-private, другим классам в одном пакете.

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

Ответ 4

На самом деле таких обязательств вообще нет.

Oracle JDKs javac (и я верю, что большинство других реализаций тоже) с удовольствием скомпилирует ваш класс HelloWorld, независимо от того, в какой директории он находится и какой пакет вы объявляете в исходном файле.

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

Во время выполнения история похожа: когда класс должен быть загружен, его полное имя является отправной точкой. Теперь задание загрузчика класса должно найти файл .class (или запись в ZIP файле или любой другой воображаемый источник) на основе только FQN, и снова простейшей вещью в иерархической файловой системе является преобразование имени пакета в структуру каталогов.

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