Подтвердить что ты не робот

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

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

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

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

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

4b9b3361

Ответ 1

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

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

Акцент мой.

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

Итак, это было какое-то конструктивное решение.

Ответ 2

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

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

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

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

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

Ответ 3

Из Мышление в 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 версии 0.2 (документ с надписями): Дуб был оригинальным именем того, что теперь широко известный как Java, и это руководство является самым старым руководством, доступным для Oak (т.е. Java).
Для получения дополнительной истории о происхождении Java, пожалуйста, посмотрите Зеленый проект и Технология Java (TM): ранняя история
)

Ответ 4

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

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

Ответ 5

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

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

Ответ 6

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

Ответ 7

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

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

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

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

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

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

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

Ответ 8

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

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

Ответ 9

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

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

Ответ 10

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

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

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

Ответ 11

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

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

Ответ 12

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

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

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