Каким должно быть имя файла в котором хранится код java класса solution

Обновлено: 07.07.2024

Приведём простейший пример кода (решение задачи A + B):

Общие замечания

Пример использования (устанавливаем размер стека в 64 МБ):

Ввод и вывод данных

Как правило, для ввода используют один из четырёх способов, которые различаются по скорости и удобству использования. Ввод/вывод в Java может стать очень медленным, если пользоваться им неправильно.

Scanner

Класс Scanner является самым удобным средством для чтения входных данных в большинстве задач, но скорость его работы оставляет желать лучшего. Имеет много методов для чтения примитивных типов, длинных чисел, строки до разделителя, строки до переноса, строки по регулярному выражению и т. д. Все это богатство основывается на регулярных выражениях, поэтому работает медленно. Когда размер входного файла примерно мегабайт, с помощью сканера его удастся прочитать примерно за полсекунды-секунду. Поэтому, прежде чем использовать сканер, убедитесь, что размер входного файла небольшой. Подводные камни: конструктор Scanner(String) читает данные из строки, а не из файла, который так назван.

Пример чтения всех целых чисел из файла input.txt (до конца файла):

BufferedReader

Обеспечивает достаточно быстрый ввод для большинства задач. Но самостоятельно этот класс позволяет лишь читать отдельные символы и строки.

Пример чтения чисел из файла input.txt , где каждое число записано в отдельной строке, после последнего может следовать, а может и не следовать перевод строки, но пустые строки недопустимы:

StreamTokenizer + BufferedReader

Класс, изначально предназначенный для токенизации исходных текстов на Java. По этой причине имеет слегка запутанный интерфейс и кучу нетривиальных настроек. Работает быстро, но имеет некоторые подводные камни:

  1. Если вы настраиваете его на чтение чисел, все они хранятся в double после прочтения. Это очень плохо, когда среди входных данных попадаются long 'и (64-битные числа): они теряют точность, если их хранить в double .
  2. В одном из своих режимов автоматически распознает backslash escape-последовательности. То есть \n во входном файле превращается в один символ перевода строки. При решении задач такое поведение может только мешать.

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

Резюме по StreamTokenizer : его имеет смысл использовать в задачах на парсинг. В таких задачах решения получаются существенно короче.

Пример чтения всех целых чисел из файла input.txt (до конца файла):

StringTokenizer + BufferedReader

Довольно простая по смыслу комбинация: из файла читаем по строкам, далее строку бьём на токены. В итоге получается метод String next() , который читает «следующий токен», поверх которого делаются int nextInt() , long nextLong() , double nextDouble() через соответственно Integer.parseInt , Long.parseLong , Double.parseDouble . Все это работает почти так же быстро, как StreamTokenizer , за вычетом того, что строк создается побольше. Тем не менее, файлы порядка десяти мегабайт читаются на ура.

По сравнению с другими перечисленными выше способами для этого нужно больше всего кода. Однако код можно написать один раз и использовать в нескольких задачах.

Подводные камни: когда файл кончается, метод readLine класса BufferedReader возвращает null . Если в задаче нужно читать данные до конца файла, нужно предусмотреть корректный путь этого null в написанных методах.

Приведём расширенный пример написания обёртки над StringTokenizer для чтения всех чисел из файла. Числа могут быть записаны по несколько в строке, возможны пустые строки и т. д.

Вывод

Класс PrintWriter подходит для всех случаев и работает достаточно быстро.

Важно не забывать по окончании работы вызывать у writer 'а метод close() или flush() , чтобы очищать буфер и сбрасывать таким образом несохранённые изменения на диск.

В PrintWriter имеются методы print и println , перегруженные для множества встроенных типов. Есть даже printf с семантикой, похожей на то же самое из языка C, только в Java переменное число аргументов функции (varargs) реализовано через массивы, поэтому этот метод медленный. Зато он полезен, когда необходимо вывести, например, вещественное число с нужной точностью:

Синтаксис написания форматной строки отличается от такового в C, подробности есть в документации.

Также медленно работают вызовы типа println(a + " " + b) . Выводите по одной переменной за раз, и тогда вы добьётесь максимальной эффективности.

В Java есть ещё класс PrintStream , он делает то же самое, что PrintWriter , но работает с byte , а не с char .

Локализация

Использование свойства ONLINE_JUDGE

Запуск программы на сервере осуществляется с определенным свойством ONLINE_JUDGE . С его помощью в коде программы можно определить, что она запущена на сервере. Например, это можно использовать для решения, использовать ли для работы файлы или стандартный ввод/вывод:

1. Имя класса отличается от имени файла, в котором он хранится

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

Начинающие студенты (программисты) часто забывают об этом соглашении, и, например, задают имя файла в соответствии с заданием: Lab6.java. Ошибочный пример: Имя файла Lab6.java Исправленный пример: Имя файла Airplane.java Заметьте: предполагается, что имя класса начинается с заглавной буквы. В операционных системах, которые учитывают регистр символов в именах файлов, могут появиться дополнительные проблемы, особенно у студентов, изучающих Java под Unix, и привыкших к системеm именования файлов в DOS. Класс MotorVehicle должен храниться в файле MotorVehicle.java , но не в файле motorvehicle.java .

2. Сравнение с помощью ==

В Java строки — это объекты класса java.lang.String . Оператор == , применяемый к объектам, проверяет на равенство ссылки на объекты! Иногда студенты не понимают семантики оператора == и пытаются применить его для сравнения строк. Ошибочный пример: Правильный способ сравнения 2х строк на равенство — это использование метода equals() класса java.lang.String . Он возвращает true , если строки одинаковой длины и состоят из одних и тех же символов. (Прим. перев.: вообще-то это не гарантирует равенство. На самом деле, equals проверяет, равны ли посимвольно 2 строки) Исправленный пример: Эта ошибка — дурацкая, потому что на самом деле Java код получается синтаксически правильным, а в итоге работает не так как нужно. Некоторые студенты также пытаются применять операторы сравнения > и , вместо метода compareTo() класса java.lang.String . Эту ошибку обнаружить проще, потому что она вызывает ошибки на этапе компиляции.

3. Забыл проинициализировать объекты, являющиеся элементами массива.

В Java массив объектов - это на самом деле массив ссылок на объекты. Создание массива — это просто создание набора ссылок, ни на что не указывающих (то есть равных null). Чтобы на самом деле создать "полноценный" массив объектов, необходимо проинициализировать каждый элемент массива. Многие студенты не понимают этого; они считают, что, создавая массив объектов, они автоматически создают сами объекты. (В большинстве случаев, студенты приносят эту концепцию из C++, где создание массива объектов приводит к созданию самих объектов путем вызова их конструктора по умолчанию). В примере ниже, студент хочет создать 3 объекта класса StringBuffer . Код будет откомпилирован без ошибок, но в последней строке произойдет исключение NullPointerException , где происходит обращение к несуществующему объекту. Ошибочный пример: Чтобы не допускать эту ошибку, необходимо не забывать проинициализировать элементы массива. Исправленный пример:

4. Помещение в один файл сразу нескольких классов с модификатором public

5. Подмена поля класса локальной переменной.

немного сумбурно, но смысл такой

то есть в конструкторе все смотрится красиво, но для обычных методов применять это не следует.

6. Забыл вызвать конструктор родителя (суперкласса)

Когда класс расширяет другой класс, каждый конструктор подкласса должен вызвать какой либо конструктор суперкласса. Обычно это достигается вызовом конструктора суперкласса методом super(x) , помещенным в первой строке конструктора. Если в первой строке конcтруктора нет вызова super(x) , компилятор самостоятельно вставляет этот вызов, но без параметров: super() . (прим. перев.: х. се, а я и не знал ) Иногда студенты забывают об этом требовании. Обычно это не является проблемой: вызов конструктора суперкласса вставляется компилятором и все работает отлично. Однако если у суперкласса нет конструктора по умолчанию (прим. перев.: то есть конструктора без параметров), то компилятор выдаст ошибку. В примере ниже все конструкторы суперкласса java.io.File имеют 1 или 2 параметра: Ошибочный пример: Решением проблемы является вставка явного вызова правильного конструктора суперкласса: Исправленный пример: Более неприятная ситуация возникает, когда у суперкласса есть конструктор по умолчанию, но он не полностью инициализирует объект. В таком случае код скомпилируется, но результат работы программы может быть неправильным или может возникнуть исключение.

7. Неправильный перехват исключений

8. Метод доступа имеет тип void

Почему с именем класса ArrayApp всё хорошо, а если назвать класс LowArrayApp , то получается ошибка?

Только не надо говорить, что второй класс надо кинуть в другой файл ;)

8,657 16 16 золотых знаков 68 68 серебряных знаков 178 178 бронзовых знаков 86 1 1 золотой знак 1 1 серебряный знак 13 13 бронзовых знаков если второй класс public - то нужно бросать в другой файл. Если private - нет. KoVadim, если дописать private к классу ArrayApp в Eclipse будет ошибка ну если приписать error, то тоже лучше не будет:) нужно знать где и как можно "дописать". Как называется ваш файл? В одном ли файле оба класса?

Я скомпилировал программой javac ваш код.

Код выполняется без проблем :

В результате получается два файла LowArray.class и LowArrayApp.class

Код выполняется без проблем :

В результате получается два файла LowArray.class и ArrayApp.class

Кстати. все кто писал про неправильное имя файла с исходником, о том что его имя должно совпадать с именем класса, у которого объявлен метод main.

Ребята, вы ошибаетесь! Это условие действует только когда класс имеет модификатор доступа public. Здесь же в коде модификаторы доступа не указаны и имя файла может быть любым.
и после компиляции одного .java файла будет получено два .class файла.


А Вы название файла с этим классом меняли? Файл с классом, содержащим метод main, должен иметь то же имя, что и этот класс.

23.6k 2 2 золотых знака 33 33 серебряных знака 63 63 бронзовых знака Очень странно, только сейчас попробовал у себя дать классу такое имя - и без проблем все прошло. Что компилятор пишет? это если я второй класс назвал LowArrayApp, а если я его называю ArrayApp ошибки нет

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

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

нет смысла классу DefaultLogger давать модификатор public, так как он не будет никем наследоватся и вообще где-то использоватся кроме класса BaseLogger. он нужен лишь для того чтоб потом не надо было вкручивать еще один отдельный класс для "дефолтного" логгера. так как он не public и используется в пределах класса BaseLogger, то нет смысла хранить его в отдельном файле.

в java public class всегда хранится в отдельном файле, имя которого совпадает с его именем (без имени пакета). package private классы (без модификатора public) можно хранить как в отдельных файлах (если они используются многими классами пакета) так и в одном файле в как в примере.




Продолжаем разговор о том, как Java Virtual Machine работает внутри. В предыдущей статье (оригинал на анг.) мы рассмотрели подсистему загрузки классов. В этой статье мы поговорим о структуре class-файлов.

Как мы уже знаем, весь исходный код, написанный на языке программирования Java, сначала компилируется в байт-код с помощью компилятора javac , входящего в состав Java Development Kit. Байт-код сохраняется в бинарный файл в специальный class-файл. Затем эти class-файлы динамически (при необходимости) загружаются в память загрузчиком классов (ClassLoader).



Рисунок — компиляция исходного кода Java

Каждый файл с расширением .java компилируется как минимум в один файл .class . Для каждого класса, интерфейса и модуля, определенных в исходном коде, создается по одному .class файлу. Это также относится к интерфейсам и вложенным классам.

Примечание — для простоты файлы с расширением .class будем называть “class-файлами”.

Давайте напишем простую программу.


Запуск javac для этого файла приведет к появлению следующих файлов.


Как видите, для каждого класса и интерфейса создается отдельный class-файл.

Что внутри class-файла?

Class-файл содержит следующую информацию.

Магическое число, сигнатура. Первые четыре байта каждого class-файла всегда 0xCAFEBABE . Эти четыре байта идентифицируют class-файл Java.

Версия файла. Следующие четыре байта содержат мажорную и минорную версию файла. Вместе эти номера определяют версию формата class-файла. Если class-файл имеет основной мажорную версию M и минорную m, то мы обозначаем эту версию как M.m.

У каждой JVM есть ограничения по поддерживаемым версиям class-файлов. Например, Java 11 поддерживает major версию с 45 до 55, Java 12 — с 45 по 56.

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

Флаги доступа. Список флагов, которые указывают класс это или интерфейс, public или private, финальный класс или нет. Различные флаги, такие как ACC_PUBLIC , ACC_FINAL , ACC_INTERFACE , ACC_ENUM и т. д. описаны спецификации Java Virtual Machine Specification.

This class. Ссылка на запись в пуле констант.

Super class. Ссылка на запись в пуле констант.

Интерфейсы. Количество интерфейсов, реализованных классом.

Количество полей. Количество полей в классе или интерфейсе.

Поля. После количества полей следует таблица структур переменной длины. По одной для каждого поля с описанием типа поля и названия (со ссылкой на пул констант).

Количество методов. Количество методов в классе или интерфейсе. Это число включает только методы, которые явно определены в классе, без методов, унаследованных от суперклассов.

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

Количество атрибутов. Количество атрибутов в этом классе, интерфейсе или модуле.

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

Хотя class-файл напрямую не человекочитаемый, в JDK есть инструмент под названием javap, который выводит его содержимое в удобном формате.

Давайте напишем простую программу на Java, указанную ниже.


Давайте скомпилируем эту программу с помощью javac , которая создаст файл HelloWorld.class , и используем javap для просмотра файла HelloWorld.class . Запустив javap с параметром -v (verbose) для HelloWorld.class получим следующий результат:


Здесь вы можете увидеть, что класс публичный ( public ) и у него в пуле констант 37 записей. Есть один атрибут (SourceFile внизу), класс реализует два интерфейса (Serializable, Cloneable), у него нет полей и есть два метода.

Возможно, вы заметили, что в исходном коде есть только один статический метод main, но class-файл говорит, что есть два метода. Вспомните конструктор по умолчанию — это конструктор без аргументов, добавленный компилятором javac , байт-код которого также виден в выводе. Конструкторы рассматриваются как методы.

Читайте также: