Почему каждый публичный класс находится в отдельном файле? - PullRequest
43 голосов
/ 23 августа 2009

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

Почему Java делает это? Были ли какие-либо соображения дизайна?

Редактировать (основываясь на нескольких ответах):

Почему Java не снимает это ограничение в эпоху IDE? Это не нарушит существующий код (или так будет?).

Ответы [ 12 ]

56 голосов
/ 23 августа 2009

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

Если у вас есть несколько открытых классов в файле, у вас есть несколько проблем:

  1. Как вы называете файл? Один из публичных классов? Другое имя? У людей достаточно проблем, связанных с плохой организацией кода решения и соглашениями об именах файлов, чтобы иметь одну дополнительную проблему.

  2. Кроме того, когда вы просматриваете проводник файлов / проектов, хорошо, что все скрыто. Например, вы видите один файл и углубляетесь, и все 200 классов собраны вместе. Если у вас есть один файл на один класс, вы можете лучше организовать свои тесты и почувствовать структуру и сложность решения.

Я думаю, что Java правильно понял.

31 голосов
/ 23 августа 2009

Согласно спецификации языка Java, третье издание :

Это ограничение подразумевает, что на единицу компиляции должно быть не более одного такого типа. Это ограничение упрощает компилятору языка программирования Java или реализации виртуальной машины Java поиск именованного класса в пакете ; например, исходный код для открытого типа wet.sprocket.Toad будет найден в файле Toad.java в каталоге wet / sprocket, а соответствующий объектный код будет найден в файле Toad.class в том же каталоге.

Акцент мой.

Кажется, что в основном они хотели перевести разделитель каталогов ОС в точки для пространств имен и наоборот.

Так что да, это было какое-то конструктивное соображение.

17 голосов
/ 25 августа 2009

С Мышление на Java

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


Из спецификации (7.2.6)

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

  • На тип ссылается код в других единицах компиляции пакета, в котором объявлен тип.
  • Тип объявлен как открытый (и поэтому потенциально доступен из кода в других пакетах).
  • Это ограничение подразумевает, что на единицу компиляции должно быть не более одного такого типа.
  • Это ограничение позволяет компилятору для языка программирования Java или реализации виртуальной машины Java найти именованный класс в пакете ; например, исходный код для общедоступного типа wet.sprocket.Toad будет найден в файле Toad.java в каталоге wet / sprocket, а соответствующий объектный код будет найден в файле Toad.class в том же каталоге.

Вкратце: речь может идти о поиске классов без необходимости загружать все в ваш путь к классам.

Редактировать: «может выбрать», похоже, что он оставляет возможность не следовать этому ограничению, и значение «может», вероятно, такое, которое описано в RFC 2119 (т.е. "дополнительный")
Однако на практике это применяется на столь многих платформах и зависит от такого количества инструментов и IDE, что я не вижу никакой «хост-системы», которая выбирает , а не , чтобы применять это ограничение.


Из " Однажды Дуб ... "

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

(Примечание:

Спецификация языка Oak для Oak версии 0.2 (постскриптум): Oak было первоначальным названием того, что сейчас широко известно как Java, и это руководство является самым старым доступным руководством для дуба (т.е. Java).
Чтобы узнать больше о происхождении Java, ознакомьтесь с технологией Green Project и Java (TM): ранняя история
)

6 голосов
/ 23 августа 2009

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

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

3 голосов
/ 25 августа 2009

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

3 голосов
/ 23 августа 2009

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

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

2 голосов
/ 23 августа 2009

Почему java не снимает это ограничение в эпоху IDE? Это не нарушит существующий код (или так будет?).

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

2 голосов
/ 23 августа 2009

Технически допустимо иметь несколько классов верхнего уровня Java в одном файле. Однако это считается плохой практикой, и многие инструменты Java (включая IDE) не работают, если вы делаете это.

JLS говорит это:

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

  • На тип ссылается код в других единицах компиляции пакета, в котором объявлен тип.
  • Тип объявлен как открытый (и поэтому потенциально доступен из кода в других пакетах).

Обратите внимание на использование может в тексте JLS. Это говорит о том, что компилятор может отклонить это как недопустимое или нет. Это не очень хорошая ситуация, если вы пытаетесь сделать свой Java-код переносимым на уровне исходного кода . Таким образом, даже если на вашей платформе разработки работает несколько классов в одном исходном файле, это плохая практика.

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

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

1 голос
/ 04 декабря 2017

Ну, на самом деле это необязательное ограничение в соответствии со спецификацией языка Java (раздел 7.6, стр. № 209), но за ним следует компилятор Oracle Java в качестве обязательного ограничения. Согласно спецификации языка Java,

Когда пакеты хранятся в файловой системе (§7.2.1), система хоста может выбрать принудительное ограничение, что это ошибка времени компиляции если тип не найден в файле с именем, состоящим из типа имя плюс расширение (например, .java или .jav), если любой из верно следующее:

  • На тип ссылается код в других единицах компиляции пакета, в котором объявлен тип.
  • Тип объявлен как открытый (и поэтому потенциально доступен из кода в других пакетах).

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

На практике многие программисты выбирают каждый класс или интерфейс введите свой собственный модуль компиляции, является ли он общедоступным или упоминается кодом в других единицах компиляции.

Например, исходный код для открытого типа wet.sprocket.Toad будет найти в файле Toad.java в каталоге wet / sprocket, а соответствующий объектный код будет найден в файле Toad.class в тот же каталог.

Чтобы получить более ясную картину, давайте представим, что в одном и том же исходном файле есть два открытых класса: публичный класс A и публичный класс B, а класс A имеет ссылку на еще не скомпилированный класс B. И мы компилируем (compiling-linking-loading ) класс A теперь, когда ссылка на компилятор класса B будет вынуждена проверять каждый файл * .java в текущем пакете, потому что класс B не имеет своего конкретного файла B.java. Таким образом, в приведенном выше случае компилятору требуется немного времени, чтобы найти, какой класс находится в каком исходном файле и в каком классе лежит основной метод. Таким образом, причина сохранения одного общедоступного класса на исходный файл состоит в том, чтобы фактически ускорить процесс компиляции, поскольку он позволяет более эффективно искать исходные и скомпилированные файлы во время компоновки (операторы импорта). Идея в том, что если вы знаете имя класса, вы знаете, где его нужно найти для каждой записи пути к классу, и индексация не требуется.

А также, как только мы выполняем наше приложение, JVM по умолчанию ищет открытый класс (поскольку нет ограничений и может быть доступен из любого места), а также ищет public static void main(String args[]) в этом открытом классе. Открытый класс действует как начальный класс, с которого начинается экземпляр JVM для приложения (программы) Java. Поэтому, когда мы предоставляем более одного открытого класса в программе, компилятор сам останавливает вас, выдавая ошибку. Это потому, что позже мы не можем спутать JVM с тем, какой класс должен быть его начальным классом, потому что только один открытый класс с public static void main(String args[]) является начальным классом для JVM.

Подробнее о можно узнать, почему один исходный файл Java не может иметь более одного открытого класса

1 голос
/ 25 августа 2009

В одном файле может быть много открытых классов. Тем не менее, класс верхнего уровня на файл. В одном файле может быть сколько угодно открытых внутренних / вложенных классов.

Мне кажется, вам нравится эта ссылка - Может ли файл Java иметь более одного класса?

...