Добрый день! Начал проходить курс "Программирование на Java". Как я понимаю,курс создавался приблизительно в 2015 году. Не потерял ли данный курс свою актуальность? Стоит ли проходить его в 2023 году, или же лучше найти что-то более новое? |
Пакет java.lang
Системные классы
Следующие классы, которые будут рассмотрены, обеспечивают взаимодействие с внутренними механизмами JVM и средой исполнения приложения:
- ClassLoader – загрузчик классов; отвечает за загрузку описания классов в память JVM;
- SecurityManager – менеджер безопасности; содержит различные методы проверки допустимости запрашиваемой операции;
- System – содержит набор полезных статических полей и методов;
- Runtime – позволяет приложению взаимодействовать со средой исполнения;
- Process – представляет интерфейс для взаимодействия с внешней программой, запущенной при помощи Runtime.
ClassLoader
Это абстрактный класс, ответственный за загрузку типов. По имени класса или интерфейса он находит и загружает в память данные, которые составляют определение типа. Обычно для этого используется простое правило: название типа преобразуется в название class -файла, из которого и считывается вся необходимая информация.
Каждый объект Class содержит ссылку на объект ClassLoader, с помощью которого он был загружен.
Для добавления альтернативного способа загрузки классов можно реализовать свой загрузчик, унаследовав его от ClassLoader. Например, описание класса может загружаться через сетевое соединение. Метод defineClass() преобразует массив байт в экземпляр класса Class. С помощью метода newInstance() могут быть получены экземпляры такого класса. В результате загруженный класс становится полноценной частью исполняемого Java-приложения.
Для иллюстрации приведем пример, как может выглядеть простая реализация загрузчика классов, использующего сетевое соединение:
class NetworkClassLoader extends ClassLoader { String host; int port; public NetworkClassLoader(String host, int port) { this.host = host; this.port = port; } public Class findClass(String className) { byte[] bytes = loadClassData(className); return defineClass(className, bytes, 0, bytes.length); } private byte[] loadClassData( String className) { byte[] result = null; // open connection, load the class data return result; } }
В этом примере только показано, что наследник загрузчика классов должен определить и реализовать методы findClass() и loadClassData() для загрузки описания класса. Когда описание получено, массив байт передается в метод defineClass() для создания экземпляра Class. Для простоты в примере приведен только шаблонный код, без реализации получения байт из сетевого соединения.
Для получения экземпляров классов, загруженных с помощью этого загрузчика, можно воспользоваться методом loadClass():
try { ClassLoader loader = new NetworkClassLoader(host, port); Object main = loader.loadClass( "Main").newInstance(); } catch(ClassNotFoundException e) { e.printStackTrace(); } catch(InstantiationException e) { e.printStackTrace(); } catch(IllegalAccessException e) { e.printStackTrace(); }
Если такой класс не будет найден, будет брошено исключение ClassNotFoundException, если класс будет найден, но произойдет какая-либо ошибка при создании объекта этого класса – будет брошено исключение InstantiationException, и, наконец, если у вызывающего потока не имеется соответствующих прав для создания экземпляров этого класса (что проверяется менеджером безопасности), будет брошено исключение IllegalAccessException.
SecurityManager – менеджер безопасности
С помощью методов этого класса приложения перед выполнением потенциально опасных операций проверяют, является ли операция допустимой в данном контексте.
Класс SecurityManager содержит много методов с именами, начинающимися с приставки check ("проверить"). Эти методы вызываются из стандартных классов библиотек Java перед тем, как в них будут выполнены потенциально опасные операции. Типичный вызов выглядит примерно следующим образом:
SecurityManager security = System.getSecurityManager(); if(security != null){ security.checkX(…); }
где X – название потенциально опасной операции: Access, Read, Write, Connect, Delete, Exec, Listen и т.д.
Предотвращение вызова производится путем бросания исключения – SecurityException, если вызов операции не разрешен (кроме метода checkTopLevelWindow, который возвращает boolean значение).
Для установки менеджера безопасности в качестве текущего вызывается метод setSecurityManager() в классе System. Соответственно, для его получения нужно вызвать метод getSecurityManager().
В большинстве случаев, если приложение запускается локально, будут разрешены все действия, поскольку в системе SecurityManager отсутствует. Предполагается, что запускаемому локально приложению можно полностью доверять. Если же приложение может быть опасно (например, его код был загружен из сети, как это происходит в случае апплетов), то менеджер безопасности выставляется и его уже нельзя убрать или заменить (попытки вызовут SecurityException ). Он контролирует работу с локальной файловой системой, сетевыми соединениями, потоками исполнения и т.д.
System
Класс System содержит набор полезных статических методов и полей. Экземпляр этого класса не может быть создан или получен.
Пожалуй, наиболее широко используемой возможностью, предоставляемой System, является стандартный вывод, доступный через переменную System.out. Ее тип – PrintStream (потоки данных будут подробно рассматриваться в лекции 15). Стандартный вывод можно перенаправить в другой поток (файл, массив байт и т.д., главное, чтобы это был объект PrintStream ):
public static void main(String[] args) { System.out.println("Study Java"); try { PrintStream print = new PrintStream(new FileOutputStream("d:\\file2.txt")); System.setOut(print); System.out.println("Study well"); } catch(FileNotFoundException e) { e.printStackTrace(); } }
При запуске этого кода на экран будет выведено только
Study Java
И в файл "d:\file2.txt" будет записано
Study well
Аналогично могут быть перенаправлены стандартный ввод System.in – вызовом System.setIn(InputStream) и поток вывода сообщений об ошибках System.err – вызовом System.setErr(PrintStream) (по умолчанию все потоки – in, out, err – работают с консолью приложения).
Следующие методы класса System позволяют работать с некоторыми параметрами системы:
- public static void runFinalizersOnExit(boolean value) – определяет, будет ли производиться вызов метода finalize() у всех объектов (у кого еще не вызывался), когда выполнение программы будет окончено (по умолчанию выставлено значение false );
- public static native long currentTimeMillis() – возвращает текущее время; это время представляется как количество миллисекунд, прошедших с 1 января 1970 года;
- public static String getProperty(String key) – возвращает значение свойства с именем key.
Чтобы получить все свойства, определенные в системе, можно воспользоваться следующим методом:
- public static java.util.Properties getProperties() – возвращает объект java.util.Properties, в котором содержатся значения всех определенных системных свойств.
Метод arrayCopy(Object source, int srcPos, Object target, int trgPos, int length) предоставляет возможность быстрого копирования содержимого одного массива в другой. Первый параметр задает исходный массив, второй – номер позиции, начиная с которой брать элементы для копирования. Третий параметр – массив-"получатель", четвертый – номер позиции в нем, начиная с которого будут записываться скопированные элементы. Наконец, последний параметр задает количество элементов, которые надо скопировать. Оба массива должны быть созданы, иметь совместимые типы и достаточную длину, иначе будут сгенерированы соответствующие исключения.
Runtime
Во время исполнения приложению Java сопоставляется экземпляр класса Runtime. Этот объект позволяет взаимодействовать с окружением, в котором запущена Java-программа. Получить его можно с помощью статического метода Runtime.getRuntime().
Методы этого класса:
- public void exit(int status) – осуществляет завершение программы с кодом завершения status (при использовании этого метода особое внимание нужно уделить обработке исключений – выход будет осуществлен моментально и в конструкциях try-catch-finally управление в finally передано не будет);
- public native void gc() – сигнализирует сборщику мусора о необходимости запуска;
- public void runFinalization() – производит запуск выполнения методов finalize() у всех объектов, этого ожидающих;
- public native long freeMemory() – возвращает количество свободной памяти, доступной приложению JVM. В некоторых случаях это количество может быть увеличено, если вызвать у объекта Runtime метод gc() ;
- public native long totalMemory() – возвращает суммарное количество памяти, выделенное Java-машине. Это количество может изменяться даже в течение одного запуска, что зависит от реализации платформы, на которой запущена Java-машина. Также не стоит закладываться на объем памяти, занимаемой одним определенным объектом, – эта величина тоже зависит от реализации Java-машины;
- public void loadLibrary(String libname) – загружает библиотеку с указанным именем.
Обычно загрузка библиотек производится следующим образом: в классе, использующем native реализации методов, добавляется статический инициализатор, например:
static { System.loadLibrary("LibFile"); }
Таким образом, когда класс будет загружен и инициализирован, необходимый код для реализации native методов также будет загружен. Если будет произведено несколько вызовов загрузки библиотеки с одним и тем же именем, произведен будет только первый, а все остальные будут проигнорированы.
- public void load(String filename) – подгружает файл с указанным названием в качестве библиотеки. В принципе, этот метод работает так же, как и метод loadLibrary(), только принимает в качестве параметра именно название файла, а не библиотеки, тем самым позволяя загрузить любой файл с native кодом;
- public Process exec(String command) – в отдельном процессе запускает команду, представленную переданной строкой. Возвращаемый объект Process может быть использован для взаимодействия с этим процессом.
Process
Объекты этого класса получаются вызовом метода exec() у объекта Runtime, запускающего отдельный процесс. Объект класса Process может использоваться для управления процессом и получения информации о нем.
Process – абстрактный класс, определяющий, какие методы должны присутствовать в реализациях для конкретных платформ. Методы класса Process:
- public InputStream getInputStream() – дает возможность получать поток ввода процесса;
- getErrorStream(), getOutputStream() – методы, аналогичные getInputStream(), но получающие, соответственно, стандартные потоки сообщений об ошибках и вывода;
- public void destroy() – уничтожает процесс; все подпроцессы, запущенные из него, также будут уничтожены;
- public int exitValue() – возвращает код завершения процесса; по соглашению, код завершения, равный 0, означает нормальное завершение;
- public int waitFor() – вынуждает текущий поток выполнения приостановиться до тех пор, пока не будет завершен процесс, представленный этим экземпляром Process ; возвращает значение кода завершения процесса.
Даже если в приложении Java не будет ни одной ссылки на объект Process, процесс не будет уничтожен и будет продолжать асинхронно выполняться до своего завершения. Спецификацией не оговаривается механизм, с помощью которого будет выделяться процессорное время на выполнение процессов Process и потоков Java. Поэтому при проектировании программ не стоит полагаться ни на какой из них, так как различные Java-машины могут демонстрировать различное поведение.