Почему каждый открытый class в отдельном файле?

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

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

Изменить (на основе нескольких ответов):

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

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

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

Акцент мой.

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

Так что да, это был какой-то проект.

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

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

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

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

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

От мышления в Java

:

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


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

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

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

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

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


Из « Когда-то на дубе … »

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

(Заметка:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

На самом деле это не ответ на вопрос, а точка данных.

Я grepped заголовки моей личной библиотеки C ++ utilty (вы можете получить ее отсюда ), и почти все файлы заголовков, которые фактически объявляют classы (некоторые просто объявляют свободные функции), объявляют более одного classа. Мне нравится думать о себе как о хорошем C ++-дизайнере (хотя в библиотеке немного места, я его единственный пользователь), поэтому я предлагаю, что для C ++ по крайней мере несколько classов в одном файле являются нормальными и даже хорошая практика.

Это позволяет упростить эвристику для перехода от Foobar.class к Foobar.java.

Если Foobar может быть в любом файле Java, у вас есть проблема с отображением, что может в конечном итоге означать, что вам нужно выполнить полную проверку всех java-файлов, чтобы найти определение classа.

Лично я нашел это одним из странных правил, которые в совокупности привели к тому, что Java-приложения могут расти очень большими и по-прежнему быть прочными.

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

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

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

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

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

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

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

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

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

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

Вы можете прочитать больше о том, почему в одном исходном файле Single Java не может быть больше одного открытого classа

  • Будет ли .hashcode () возвращать другой int из-за уплотнения пространства владения?
  • Сколько памяти использует строка в Java 8?
  • Разбор массива JSON в java.util.List с Gson
  • Как добавить прослушиватель действий, который прослушивает несколько кнопок
  • Создание classа JAXB, который реализует интерфейс
  • Избегайте синхронизации (это) в Java?
  • Добавить эскизы изображений к макету в сетке?
  • Как найти ansible порт?
  • Почему поведение пула констант Integer изменяется на 127?
  • Как использовать Integer без знака в Java 8 и Java 9?
  • Сочетание весеннего проекта и Джерси
  • Давайте будем гением компьютера.