Привет, дорогой мой друг!
В этой статье я хотел бы поговорить с тобой о базовых понятиях в Java-мире. Как ты, возможно, слышал, "Java-программы пишутся единожды - выполняются везде" (по-английски это звучит так "Write once, run anywhere")

Если коротко, то это означает что java-код является переносимым. То есть его можно написать один раз, а потом запускать на самых разных архитектурах и операционных системах. Например,
- Windows (архитектуры x32, x64)
- Linux (x64, arm и так далее)
- MacOS (x64, aarch64)
- другие операционные системы, о которых мы слышали реже

Если сказать это по другому, то вы можете запускать свой java-код на любой системе, для которой реализована виртуальная машина java. Здесь, вот, мы подошли к первому понятию - JVM (Java Virtual Machine). Это и есть та самая виртуальная машина java, за счет которой достигается переносимость java-кода между платформами.
Чтобы не быть голословным, предлагаю тебе прям сейчас взглянуть на страницу выбора Java для скачивания: Latest Releases | Adoptium

Это страница одного из поставщиков JDK/JRE (другими словами Java). Таких поставщиков есть, как минимум несколько. Но обо всем по порядку. Как ты можешь увидеть, этот поставщик предлагает Java для нескольких операционных систем и для самых разных компьютерных архитектур: 32-битных, 64-битных и так далее.
Итак, что такое JVM
Есть виртуальная машина java, она же JVM (Java Virtual Machine), за счет которой достигается выполнение java-кода (java-программ) на разных операционных системах.
Продолжаем дальше
JVM - это тоже программа, только большая по размеру. Может быть написана, например, на языке С++. Цель этой программы - выполнять java байт-код. Байт-код - это промежуточный код наших java-программ. Давайте посмотрим на примере, чтобы было понятней.
Я написал небольшую программу на Java, которая читает построчно текстовый файл, создает из прочитанных данных HashMap (карту/мапу) и затем выводит этот результат на экран:
import java.io.File; import java.io.FileNotFoundException; import java.util.HashMap; import java.util.Map; import java.util.Scanner; public class Application { public static void main(String[] args) { Map<String, Integer> goods = new HashMap<>(); try { File goodsFile = new File("goods.txt"); Scanner reader = new Scanner(goodsFile); while (reader.hasNext()) { String line = reader.nextLine(); String[] columns = line.split(":"); if (columns.length == 2) { String good = columns[0].strip(); try { int amount = Integer.parseInt(columns[1].strip()); goods.put(good, amount); } catch (NumberFormatException e) { System.out.printf("%s cannot be parsed. Continue...%n", columns[1]); } } } reader.close(); } catch (FileNotFoundException e) { System.out.println("goods.txt cannot be found on a disk"); } goods.forEach((key, value) -> System.out.println("Product: " + key + ", amount: " + value)); } }
Файлик с данными, которые эта программа читает: goods.txt
apple: 200 orange: 150 avocado: 80 banana: 230
Как эту программу выполнить?
Любая java-программа проходит два важных этапа:
- Компиляция
- Выполнение
Компиляция
Компиляция - это, когда мы исходный код программы превращаем в промежуточный код (байт-код). Выше ты мог увидеть исходных код программы. Тот код, который понятен разработчику. Это код, написанный на языке программирования Java.
После компиляции этого кода мы получим байт-код. Он будет выглядеть примерно вот так:
Classfile /home/hp/projects/pet/app/Application.class Last modified Mar 4, 2023; size 2566 bytes SHA-256 checksum ec326395fb3e756a44d5f2d35a660f9424c8e0445acb7d962bce993f5bc00277 Compiled from "Application.java" public class Application minor version: 0 major version: 61 flags: (0x0021) ACC_PUBLIC, ACC_SUPER this_class: #95 // Application super_class: #2 // java/lang/Object interfaces: 0, fields: 0, methods: 3, attributes: 3 Constant pool: #1 = Methodref #2.#3 // java/lang/Object."<init>":()V #2 = Class #4 // java/lang/Object #3 = NameAndType #5:#6 // "<init>":()V #4 = Utf8 java/lang/Object #5 = Utf8 <init> #6 = Utf8 ()V #7 = Class #8 // java/util/HashMap #8 = Utf8 java/util/HashMap #9 = Methodref #7.#3 // java/util/HashMap."<init>":()V #10 = Class #11 // java/io/File #11 = Utf8 java/io/File #12 = String #13 // goods.txt #13 = Utf8 goods.txt #14 = Methodref #10.#15 // java/io/File."<init>":(Ljava/lang/String;)V #15 = NameAndType #5:#16 // "<init>":(Ljava/lang/String;)V #16 = Utf8 (Ljava/lang/String;)V #17 = Class #18 // java/util/Scanner #18 = Utf8 java/util/Scanner #19 = Methodref #17.#20 // java/util/Scanner."<init>":(Ljava/io/File;)V #20 = NameAndType #5:#21 // "<init>":(Ljava/io/File;)V #21 = Utf8 (Ljava/io/File;)V #22 = Methodref #17.#23 // java/util/Scanner.hasNext:()Z #23 = NameAndType #24:#25 // hasNext:()Z #24 = Utf8 hasNext #25 = Utf8 ()Z #26 = Methodref #17.#27 // java/util/Scanner.nextLine:()Ljava/lang/String; #27 = NameAndType #28:#29 // nextLine:()Ljava/lang/String; #28 = Utf8 nextLine #29 = Utf8 ()Ljava/lang/String; #30 = String #31 // : #31 = Utf8 : #32 = Methodref #33.#34 // java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String; #33 = Class #35 // java/lang/String #34 = NameAndType #36:#37 // split:(Ljava/lang/String;)[Ljava/lang/String; #35 = Utf8 java/lang/String #36 = Utf8 split #37 = Utf8 (Ljava/lang/String;)[Ljava/lang/String; #38 = Methodref #33.#39 // java/lang/String.strip:()Ljava/lang/String; #39 = NameAndType #40:#29 // strip:()Ljava/lang/String; #40 = Utf8 strip #41 = Methodref #42.#43 // java/lang/Integer.parseInt:(Ljava/lang/String;)I #42 = Class #44 // java/lang/Integer #43 = NameAndType #45:#46 // parseInt:(Ljava/lang/String;)I #44 = Utf8 java/lang/Integer #45 = Utf8 parseInt #46 = Utf8 (Ljava/lang/String;)I #47 = Methodref #42.#48 // java/lang/Integer.valueOf:(I)Ljava/lang/Integer; #48 = NameAndType #49:#50 // valueOf:(I)Ljava/lang/Integer; #49 = Utf8 valueOf #50 = Utf8 (I)Ljava/lang/Integer; #51 = InterfaceMethodref #52.#53 // java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; #52 = Class #54 // java/util/Map #53 = NameAndType #55:#56 // put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; #54 = Utf8 java/util/Map #55 = Utf8 put #56 = Utf8 (Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; #57 = Class #58 // java/lang/NumberFormatException #58 = Utf8 java/lang/NumberFormatException #59 = Fieldref #60.#61 // java/lang/System.out:Ljava/io/PrintStream; #60 = Class #62 // java/lang/System #61 = NameAndType #63:#64 // out:Ljava/io/PrintStream; #62 = Utf8 java/lang/System #63 = Utf8 out #64 = Utf8 Ljava/io/PrintStream; #65 = String #66 // %s cannot be parsed. Continue...%n #66 = Utf8 %s cannot be parsed. Continue...%n #67 = Methodref #68.#69 // java/io/PrintStream.printf:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; #68 = Class #70 // java/io/PrintStream #69 = NameAndType #71:#72 // printf:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; #70 = Utf8 java/io/PrintStream #71 = Utf8 printf #72 = Utf8 (Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; #73 = Methodref #17.#74 // java/util/Scanner.close:()V #74 = NameAndType #75:#6 // close:()V #75 = Utf8 close #76 = Class #77 // java/io/FileNotFoundException #77 = Utf8 java/io/FileNotFoundException #78 = String #79 // goods.txt cannot be found on a disk #79 = Utf8 goods.txt cannot be found on a disk #80 = Methodref #68.#81 // java/io/PrintStream.println:(Ljava/lang/String;)V #81 = NameAndType #82:#16 // println:(Ljava/lang/String;)V #82 = Utf8 println #83 = InvokeDynamic #0:#84 // #0:accept:()Ljava/util/function/BiConsumer; #84 = NameAndType #85:#86 // accept:()Ljava/util/function/BiConsumer; #85 = Utf8 accept #86 = Utf8 ()Ljava/util/function/BiConsumer; #87 = InterfaceMethodref #52.#88 // java/util/Map.forEach:(Ljava/util/function/BiConsumer;)V #88 = NameAndType #89:#90 // forEach:(Ljava/util/function/BiConsumer;)V #89 = Utf8 forEach #90 = Utf8 (Ljava/util/function/BiConsumer;)V #91 = InvokeDynamic #1:#92 // #1:makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/Integer;)Ljava/lang/String; #92 = NameAndType #93:#94 // makeConcatWithConstants:(Ljava/lang/String;Ljava/lang/Integer;)Ljava/lang/String; #93 = Utf8 makeConcatWithConstants #94 = Utf8 (Ljava/lang/String;Ljava/lang/Integer;)Ljava/lang/String; #95 = Class #96 // Application #96 = Utf8 Application #97 = Utf8 Code #98 = Utf8 LineNumberTable #99 = Utf8 main #100 = Utf8 ([Ljava/lang/String;)V #101 = Utf8 StackMapTable #102 = Class #103 // "[Ljava/lang/String;" #103 = Utf8 [Ljava/lang/String; #104 = Utf8 lambda$main$0 #105 = Utf8 (Ljava/lang/String;Ljava/lang/Integer;)V #106 = Utf8 SourceFile #107 = Utf8 Application.java #108 = Utf8 BootstrapMethods #109 = MethodHandle 6:#110 // REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #110 = Methodref #111.#112 // java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #111 = Class #113 // java/lang/invoke/LambdaMetafactory #112 = NameAndType #114:#115 // metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #113 = Utf8 java/lang/invoke/LambdaMetafactory #114 = Utf8 metafactory #115 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; #116 = MethodType #117 // (Ljava/lang/Object;Ljava/lang/Object;)V #117 = Utf8 (Ljava/lang/Object;Ljava/lang/Object;)V #118 = MethodHandle 6:#119 // REF_invokeStatic Application.lambda$main$0:(Ljava/lang/String;Ljava/lang/Integer;)V #119 = Methodref #95.#120 // Application.lambda$main$0:(Ljava/lang/String;Ljava/lang/Integer;)V #120 = NameAndType #104:#105 // lambda$main$0:(Ljava/lang/String;Ljava/lang/Integer;)V #121 = MethodType #105 // (Ljava/lang/String;Ljava/lang/Integer;)V #122 = MethodHandle 6:#123 // REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; #123 = Methodref #124.#125 // java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; #124 = Class #126 // java/lang/invoke/StringConcatFactory #125 = NameAndType #93:#127 // makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; #126 = Utf8 java/lang/invoke/StringConcatFactory #127 = Utf8 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; #128 = String #129 // Product: \u0001, amount: \u0001 #129 = Utf8 Product: \u0001, amount: \u0001 #130 = Utf8 InnerClasses #131 = Class #132 // java/lang/invoke/MethodHandles$Lookup #132 = Utf8 java/lang/invoke/MethodHandles$Lookup #133 = Class #134 // java/lang/invoke/MethodHandles #134 = Utf8 java/lang/invoke/MethodHandles #135 = Utf8 Lookup { public Application(); descriptor: ()V flags: (0x0001) ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return LineNumberTable: line 7: 0 public static void main(java.lang.String[]); descriptor: ([Ljava/lang/String;)V flags: (0x0009) ACC_PUBLIC, ACC_STATIC Code: stack=7, locals=8, args_size=1 0: new #7 // class java/util/HashMap 3: dup 4: invokespecial #9 // Method java/util/HashMap."<init>":()V 7: astore_1 8: new #10 // class java/io/File 11: dup 12: ldc #12 // String goods.txt 14: invokespecial #14 // Method java/io/File."<init>":(Ljava/lang/String;)V 17: astore_2 18: new #17 // class java/util/Scanner 21: dup 22: aload_2 23: invokespecial #19 // Method java/util/Scanner."<init>":(Ljava/io/File;)V 26: astore_3 27: aload_3 28: invokevirtual #22 // Method java/util/Scanner.hasNext:()Z 31: ifeq 119 34: aload_3 35: invokevirtual #26 // Method java/util/Scanner.nextLine:()Ljava/lang/String; 38: astore 4 40: aload 4 42: ldc #30 // String : 44: invokevirtual #32 // Method java/lang/String.split:(Ljava/lang/String;)[Ljava/lang/String; 47: astore 5 49: aload 5 51: arraylength 52: iconst_2 53: if_icmpne 116 56: aload 5 58: iconst_0 59: aaload 60: invokevirtual #38 // Method java/lang/String.strip:()Ljava/lang/String; 63: astore 6 65: aload 5 67: iconst_1 68: aaload 69: invokevirtual #38 // Method java/lang/String.strip:()Ljava/lang/String; 72: invokestatic #41 // Method java/lang/Integer.parseInt:(Ljava/lang/String;)I 75: istore 7 77: aload_1 78: aload 6 80: iload 7 82: invokestatic #47 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer; 85: invokeinterface #51, 3 // InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; 90: pop 91: goto 116 94: astore 7 96: getstatic #59 // Field java/lang/System.out:Ljava/io/PrintStream; 99: ldc #65 // String %s cannot be parsed. Continue...%n 101: iconst_1 102: anewarray #2 // class java/lang/Object 105: dup 106: iconst_0 107: aload 5 109: iconst_1 110: aaload 111: aastore 112: invokevirtual #67 // Method java/io/PrintStream.printf:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; 115: pop 116: goto 27 119: aload_3 120: invokevirtual #73 // Method java/util/Scanner.close:()V 123: goto 135 126: astore_2 127: getstatic #59 // Field java/lang/System.out:Ljava/io/PrintStream; 130: ldc #78 // String goods.txt cannot be found on a disk 132: invokevirtual #80 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 135: aload_1 136: invokedynamic #83, 0 // InvokeDynamic #0:accept:()Ljava/util/function/BiConsumer; 141: invokeinterface #87, 2 // InterfaceMethod java/util/Map.forEach:(Ljava/util/function/BiConsumer;)V 146: return Exception table: from to target type 65 91 94 Class java/lang/NumberFormatException 8 123 126 Class java/io/FileNotFoundException LineNumberTable: line 10: 0 line 13: 8 line 14: 18 line 16: 27 line 17: 34 line 18: 40 line 20: 49 line 21: 56 line 24: 65 line 25: 77 line 28: 91 line 26: 94 line 27: 96 line 30: 116 line 32: 119 line 35: 123 line 33: 126 line 34: 127 line 37: 135 line 38: 146 StackMapTable: number_of_entries = 6 frame_type = 254 /* append */ offset_delta = 27 locals = [ class java/util/Map, class java/io/File, class java/util/Scanner ] frame_type = 255 /* full_frame */ offset_delta = 66 locals = [ class "[Ljava/lang/String;", class java/util/Map, class java/io/File, class java/util/Scanner, class java/lang/String, class "[Ljava/lang/String;", class java/lang/String ] stack = [ class java/lang/NumberFormatException ] frame_type = 248 /* chop */ offset_delta = 21 frame_type = 2 /* same */ frame_type = 255 /* full_frame */ offset_delta = 6 locals = [ class "[Ljava/lang/String;", class java/util/Map ] stack = [ class java/io/FileNotFoundException ] frame_type = 8 /* same */ } SourceFile: "Application.java" BootstrapMethods: 0: #109 REF_invokeStatic java/lang/invoke/LambdaMetafactory.metafactory:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; Method arguments: #116 (Ljava/lang/Object;Ljava/lang/Object;)V #118 REF_invokeStatic Application.lambda$main$0:(Ljava/lang/String;Ljava/lang/Integer;)V #121 (Ljava/lang/String;Ljava/lang/Integer;)V 1: #122 REF_invokeStatic java/lang/invoke/StringConcatFactory.makeConcatWithConstants:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/invoke/CallSite; Method arguments: #128 Product: \u0001, amount: \u0001 InnerClasses: public static final #135= #131 of #133; // Lookup=class java/lang/invoke/MethodHandles$Lookup of class java/lang/invoke/MethodHandles
Этот код понятен лишь виртуальной машине java (JVM).
Выполнение
Байт-код у нас есть. Теперь этот код можно выполнить, но есть один очень важный момент: в дополнении к JVM еще идут java-библиотеки. В этих библиотеках находится реализация java-коллекций для работы с данными, классы для работы с потоками ввода/вывода и еще много чего полезного и необходимого для работы.
Так вот JVM + библиотеки = JRE (Java Runtime Environment).

JRE - это среда выполнения java. Для того чтобы запустить java-программу нам нужна именно JRE. Это минимальный набор для запуска и работы любой java-программы.
Но как быть, если вам нужно заниматься разработкой на java? Здесь уже не обойтись без JDK (Java Development Kit).
JDK - это полноценный набор для разработчика на java. В составе JDK ты найдешь:
- компилятор - чтобы получить байт-код из исходного кода своей программы;
- отладчик - чтобы находить причины ошибок в своем коде;
- инструмент для чтения байт-кода (если тебе это будет для чего-то нужно);
- генератор документации для твоих классов и их методов;
- и еще много чего полезного и интересного.

И в самом конце я представляю вашему вниманию полную обзорную картину, показывающую взаимосвязь между JVM, JRE и JDK:

Вместо заключения
Java - это:
- и язык программирования;
- и название платформы (по аналогии с .NET для C#).
В этой статье мы поговорили о платформе Java и о взаимосвязи между ее компонентами, такими как JVM, JRE, JDK. Напомню, что платформа Java - это программное обеспечение, дающее нам возможность разрабатывать и затем запускать java-программы.
Если говорить про языки программирования, то ты можешь писать не только на Java, но и на Scala, Kotlin, Groovy, Clojure. Это языки программирования, которые тоже совместимы с платформой Java. Совместимы - это значит, что они тоже компилируются в байт-код, который может выполнять JVM.