Java library class files
Я один понят условия задачи «поверхностное копирование» буквально, (Напиши программу, которая будет считывать с клавиатуры пути к двум директориям и копировать файлы из одной директории в другую (только файлы, директории игнорируй). и стал копировать файлы из первой во вторую и из второй в первую?
Синтаксический сахар var не работает с потоками почему то , подскажите что не так ? И метод of почему то подчеркивается красным
Метод writeString(Path path, String str) предназначен для записи строки в файл, указанный в объекте Path. При вызове этого метода Java создает файл, если он еще не существует, и записывает в него указанную строку. Если файл уже существует, содержимое файла будет заменено на указанную строку. Процесс работы метода writeString выглядит следующим образом: Определяется путь к файлу, который нужно создать или перезаписать, с помощью объекта Path. Создается объект Charset с кодировкой по умолчанию, если не указано другое. Строка, которую нужно записать в файл, преобразуется в последовательность байтов с помощью выбранной кодировки. Создается объект OutputStream для записи байтов в файл. Записываются байты в файл. OutputStream закрывается, чтобы сохранить данные в файле. Вот пример использования метода writeString:
import java.nio.file.Files; import java.nio.file.Path; import java.nio.charset.StandardCharsets; import java.io.IOException; public class Example < public static void main(String[] args) < String content = "Hello, world!"; Path file = Path.of("example.txt"); try < Files.writeString(file, content, StandardCharsets.UTF_8); >catch (IOException e) < e.printStackTrace(); >> >
Этот код создаст файл «example.txt» в текущем каталоге и запишет в него строку «Hello, world!» в кодировке UTF-8. Если файл уже существует, содержимое файла будет заменено на эту строку.
Внутренности JVM, Часть 2 — Структура class-файлов
Продолжаем разговор о том, как Java Virtual Machine работает внутри. В предыдущей статье (оригинал на анг.) мы рассмотрели подсистему загрузки классов. В этой статье мы поговорим о структуре class-файлов.
Как мы уже знаем, весь исходный код, написанный на языке программирования Java, сначала компилируется в байт-код с помощью компилятора javac , входящего в состав Java Development Kit. Байт-код сохраняется в бинарный файл в специальный class-файл. Затем эти class-файлы динамически (при необходимости) загружаются в память загрузчиком классов (ClassLoader).
Рисунок — компиляция исходного кода Java
Каждый файл с расширением .java компилируется как минимум в один файл .class . Для каждого класса, интерфейса и модуля, определенных в исходном коде, создается по одному .class файлу. Это также относится к интерфейсам и вложенным классам.
Примечание — для простоты файлы с расширением .class будем называть “class-файлами”.
Давайте напишем простую программу.
public class ClassOne < public static void main(String[] args)< System.out.println("Hello world"); >static class StaticNestedClass < >> class ClassTwo < >interface InterfaceOne
Запуск javac для этого файла приведет к появлению следующих файлов.
ClassOne$StaticNestedClass.class ClassOne.class ClassTwo.class InterfaceOne.class
Как видите, для каждого класса и интерфейса создается отдельный class-файл.
Что внутри class-файла?
Class-файл имеет бинарный формат. Информация в нем обычно записывается без отступов между последовательными частями информации, все выравнивается по границам байтов. Все 16-битные и 32-битные значения записываются с помощью двух или четырех последовательных 8-битных байтов.
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, указанную ниже.
package bytecode; import java.io.Serializable; public class HelloWorld implements Serializable, Cloneable < public static void main(String[] args) < System.out.println("Hello World"); >>
Давайте скомпилируем эту программу с помощью javac , которая создаст файл HelloWorld.class , и используем javap для просмотра файла HelloWorld.class . Запустив javap с параметром -v (verbose) для HelloWorld.class получим следующий результат:
Classfile /Users/apersiankite/Documents/code_practice/java_practice/target/classes/bytecode/HelloWorld.class Last modified 02-Jul-2019; size 606 bytes MD5 checksum 6442d93b955c2e249619a1bade6d5b98 Compiled from "HelloWorld.java" public class bytecode.HelloWorld implements java.io.Serializable,java.lang.Cloneable minor version: 0 major version: 55 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #5 // bytecode/HelloWorld super_class: #6 // java/lang/Object interfaces: 2, fields: 0, methods: 2, attributes: 1 Constant pool: #1 = Methodref #6.#22 // java/lang/Object."":()V #2 = Fieldref #23.#24 // java/lang/System.out:Ljava/io/PrintStream; #3 = String #25 // Hello World #4 = Methodref #26.#27 // java/io/PrintStream.println:(Ljava/lang/String;)V #5 = Class #28 // bytecode/HelloWorld #6 = Class #29 // java/lang/Object #7 = Class #30 // java/io/Serializable #8 = Class #31 // java/lang/Cloneable #9 = Utf8 #10 = Utf8 ()V #11 = Utf8 Code #12 = Utf8 LineNumberTable #13 = Utf8 LocalVariableTable #14 = Utf8 this #15 = Utf8 Lbytecode/HelloWorld; #16 = Utf8 main #17 = Utf8 ([Ljava/lang/String;)V #18 = Utf8 args #19 = Utf8 [Ljava/lang/String; #20 = Utf8 SourceFile #21 = Utf8 HelloWorld.java #22 = NameAndType #9:#10 // "":()V #23 = Class #32 // java/lang/System #24 = NameAndType #33:#34 // out:Ljava/io/PrintStream; #25 = Utf8 Hello World #26 = Class #35 // java/io/PrintStream #27 = NameAndType #36:#37 // println:(Ljava/lang/String;)V #28 = Utf8 bytecode/HelloWorld #29 = Utf8 java/lang/Object #30 = Utf8 java/io/Serializable #31 = Utf8 java/lang/Cloneable #32 = Utf8 java/lang/System #33 = Utf8 out #34 = Utf8 Ljava/io/PrintStream; #35 = Utf8 java/io/PrintStream #36 = Utf8 println #37 = Utf8 (Ljava/lang/String;)V < public bytecode.HelloWorld(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."":()V 4: return LineNumberTable: line 4: 0 LocalVariableTable: Start Length Slot Name Signature 0 5 0 this Lbytecode/HelloWorld; public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=2, locals=1, args_size=1 0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #3 // String Hello World 5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return LineNumberTable: line 7: 0 line 8: 8 LocalVariableTable: Start Length Slot Name Signature 0 9 0 args [Ljava/lang/String; > SourceFile: "HelloWorld.java"
Здесь вы можете увидеть, что класс публичный ( public ) и у него в пуле констант 37 записей. Есть один атрибут (SourceFile внизу), класс реализует два интерфейса (Serializable, Cloneable), у него нет полей и есть два метода.
Возможно, вы заметили, что в исходном коде есть только один статический метод main, но class-файл говорит, что есть два метода. Вспомните конструктор по умолчанию — это конструктор без аргументов, добавленный компилятором javac , байт-код которого также виден в выводе. Конструкторы рассматриваются как методы.
Больше почитать про javap вы можете здесь.
Совет: вы также можете использовать javap для того, чтобы увидеть, чем лямбды отличаются от анонимных внутренних классов.