[LINUX] Compilation et exécution Java comprises par CLI

Je pense que la plupart du temps, j'utilise IDE pour la programmation Java. Même lorsque vous commencez à apprendre la programmation Java, elle est souvent requise lors de la préparation de l'EDI. Cependant, lorsque les débutants commencent à apprendre de la programmation Java dans l'EDI, même s'ils peuvent écrire du code sur l'EDI, ils ne peuvent pas comprendre en profondeur les parties prises en charge par l'EDI, ou ils ne peuvent travailler qu'en fonction de l'IDE. Je ne peux pas grandir de l'état. Cet article est destiné aux débutants pour approfondir leur compréhension en exécutant des programmes Java simples avec CLI sans utiliser l'IDE. Il ne mentionne pas la lecture ou l'écriture détaillée du programme. Des mots et des concepts difficiles peuvent apparaître pour les débutants en cours de route, mais il n'est pas nécessaire de les comprendre immédiatement, alors veuillez les lire et les comprendre progressivement.

environnement

Ce sera le système d'exploitation sur lequel vous travaillez cette fois et la version de Java que vous utiliserez. Dans cet article, je travaille sur CentOS, mais si vous ne pouvez pas installer vagrant, vous pouvez travailler sur Mac, et si vous remplacez la commande UNIX, vous pouvez travailler sur l'invite de commande Windows (je ne l'ai pas vérifiée). ..

OS

Utilisez cette BOITE pour démarrer une VM avec vagrant sur une VirtualBox et y travailler.

$ cat /etc/os-release
NAME="CentOS Linux"
VERSION="7 (Core)"
ID="centos"
ID_LIKE="rhel fedora"
VERSION_ID="7"
PRETTY_NAME="CentOS Linux 7 (Core)"
ANSI_COLOR="0;31"
CPE_NAME="cpe:/o:centos:centos:7"
HOME_URL="https://www.centos.org/"
BUG_REPORT_URL="https://bugs.centos.org/"

CENTOS_MANTISBT_PROJECT="CentOS-7"
CENTOS_MANTISBT_PROJECT_VERSION="7"
REDHAT_SUPPORT_PRODUCT="centos"
REDHAT_SUPPORT_PRODUCT_VERSION="7"

Java

Installez This OpenJDK avec yum et utilisez-le.

$ java -version
java 10.0.2 2018-07-17
Java(TM) SE Runtime Environment 18.3 (build 10.0.2+13)
Java HotSpot(TM) 64-Bit Server VM 18.3 (build 10.0.2+13, mixed mode)

$ javac -version
javac 10.0.2

Programme Java

Les programmes Java sont généralement compilés avec un outil javac du code d'octet .java à .class (également appelé code intermédiaire) avant l'exécution. Ensuite, lorsque le programme est exécuté, le code d'octet est exécuté sur la JVM à la manière d'un interpréteur, ou le compilateur JIT le recompile en code machine et l'exécute. Le compilateur JIT est l'un des composants de JRE (Java runtime environment), et est un mécanisme pour optimiser le code machine des méthodes de programme et améliorer les performances.

À partir de là, vous allez compiler et exécuter des programmes Java et créer des archives avec la CLI.

Compilation et exécution de base

Tout d'abord, écrivez un programme qui affiche «Hello world» et exécutez-le. Le fichier programme à exécuter est le suivant, préparez-le donc avec vi etc.

App.java


class App {
    public static void main(String[] args) {
        System.out.println("Hello world.");
    }
}

Compilez-le avec javac.

$ ls
App.java

$ javac App.java

$ ls
App.class  App.java

Vous pouvez voir que le fichier .class a été généré. Ensuite, exécutez-le en java. Notez que l'argument est le nom de la classe, pas le nom du fichier.


$ java App 
Hello world.

C'était facile, mais j'ai compilé et exécuté le programme. Il n'y a pas de problème pour l'instant.

Exécution avec arguments

Essayez de passer des arguments lors de l'exécution du programme. Apportez les modifications suivantes au fichier programme précédent.

App.java


class App {
    public static void main(String[] args) {
        for (String arg: args) {
            System.out.println(String.format("Hello %s.", arg));
        }
    }
}

Compilez et exécutez. Contrairement à la précédente, passons un argument à l'exécution.

$ java App Alice Bob Carol
Hello Alice.
Hello Bob.
Hello Carol.

Vous pouvez voir que l'argument a été reçu.

Utilisation d'autres classes

Essayez d'accéder à d'autres classes de votre programme. Tout d'abord, créez une classe humaine qui représente les humains comme une autre classe dans un autre fichier.

Human.java


class Human {
    String name;
    Human(String name) {
            this.name = name;
    }
    void introduceMyself() {
            System.out.println(String.format("My name is %s.", this.name));
    }
}

Instanciez la classe Human dans la méthode principale de la classe App.

App.java


class App {
    public static void main(String[] args) {
        for (String arg: args) {
            Human human = new Human(arg);
            human.introduceMyself();
        }
    }
}

Compilons-le.

$ ls
App.java  Human.java

$ javac App.java

$ ls
App.class  App.java  Human.class  Human.java

Vous pouvez voir que Human a été compilé avec la compilation de l'application.

$ java App Alice Bob Carol
My name is Alice.
My name is Bob.
My name is Carol.

J'ai créé autant d'instances Humaines que le nombre d'arguments et j'ai confirmé que la méthode était exécutée.

Gestion des packages

Donnez-lui un nom de package et essayez de le compiler en tant que programme dans un package séparé. Tout d'abord, donnez à la classe Human un nom de package. De plus, comme cette classe est accessible à partir d'un autre package, j'ai ajouté correctement chaque modificateur.

Human.java


package jp.co.sample.lib;

public class Human {
    private String name;
    public Human(String name) {
        this.name = name;
    }
    public void introduceMyself() {
        System.out.println(String.format("My name is %s.", this.name));
    }
}

Ensuite, pour la classe App, donnez le nom du package et décrivez également l'importation pour accéder à la classe Human.

App.java


package jp.co.sample;

import jp.co.sample.lib.Human;

class App {
    public static void main(String[] args) {
        for (String arg: args) {
            Human human = new Human(arg);
            human.introduceMyself();
        }
    }
}

Le nom du package a été attribué, mais il ne peut pas être compilé tel quel. En Java, il est nécessaire d'organiser les fichiers dans la même structure de répertoires que le nom du package. Créez donc un répertoire comme indiqué ci-dessous et déplacez les fichiers.

$ tree
.
└── jp
    └── co
        └── sample
            ├── App.java
            └── lib
                └── Human.java

4 directories, 2 files

Après avoir déplacé le fichier, compilez-le et exécutez-le.

$ javac jp/co/sample/App.java

$ tree
.
└── jp
    └── co
        └── sample
            ├── App.class
            ├── App.java
            └── lib
                ├── Human.class
                └── Human.java

4 directories, 4 files

$ java jp.co.sample.App Alice Bob Carol
My name is Alice.
My name is Bob.
My name is Carol.

Il a été confirmé que le fichier .class a été créé au même niveau que chaque fichier .java et que le programme peut être exécuté.

Créer un fichier JAR

Combinez les fichiers .class créés dans .jar et créez une archive. Le fichier .java n'est pas inclus dans .jar, donc séparez-le comme un répertoire src.

$ tree
.
└── src
    └── jp
        └── co
            └── sample
                ├── App.java
                └── lib
                    └── Human.java

5 directories, 2 files

Compilez et sortez le fichier .class dans le répertoire classes. Si vous souhaitez exécuter dans un emplacement autre que le répertoire src d'origine du package, vous devez spécifier l'origine du package avec l'option -sourcepath.

$ javac -sourcepath src -d classes src/jp/co/sample/App.java 

$ tree
.
├── classes
│   └── jp
│       └── co
│           └── sample
│               ├── App.class
│               └── lib
│                   └── Human.class
└── src
    └── jp
        └── co
            └── sample
                ├── App.java
                └── lib
                    └── Human.java

10 directories, 4 files

Vous pouvez voir que le répertoire classes est créé et que les fichiers .class sont générés en dessous avec la même structure de répertoires que le package. Au fait, si vous voulez exécuter à un endroit autre que l'origine du package au moment de l'exécution, vous devez spécifier l'origine du package avec l'option -classpath.

$ java -classpath classes jp.co.sample.App Alice Bob Carol
My name is Alice.
My name is Bob.
My name is Carol.

Ensuite, le fichier MANIFEST est requis pour créer .jar, alors créez le fichier suivant. Le nom de la classe qui a la méthode main est décrit ici, y compris le nom du package. N'oubliez pas que si vous ne mettez pas de ligne vide dans la dernière ligne, il ne sera pas reconnu comme un fichier MANIFEST.

manifest.mf


Main-Class: jp.co.sample.App

Après avoir préparé le fichier MANIFEST, créez un fichier .jar avec jar.

$ jar cvfm sample.jar manifest.mf -C classes .
Manifeste ajouté
jp/Est ajouté(Entrer=0)(En dehors=0)(0%Stockée)
jp/co/Est ajouté(Entrer=0)(En dehors=0)(0%Stockée)
jp/co/sample/Est ajouté(Entrer=0)(En dehors=0)(0%Stockée)
jp/co/sample/App.la classe est ajoutée(Entrer=469)(En dehors=343)(26%Rétréci)
jp/co/sample/lib/Est ajouté(Entrer=0)(En dehors=0)(0%Stockée)
jp/co/sample/lib/Human.la classe est ajoutée(Entrer=595)(En dehors=382)(35%Rétréci)

$ ls
classes  manifest.mf  sample.jar  src

$ jar -tf sample.jar 
META-INF/
META-INF/MANIFEST.MF
jp/
jp/co/
jp/co/sample/
jp/co/sample/App.class
jp/co/sample/lib/
jp/co/sample/lib/Human.class

Vous pouvez voir que le fichier .jar contient le fichier MANIFEST et le fichier .class. Enfin, exécutons le fichier .jar.

$ java -jar sample.jar Alice Bob Carol
My name is Alice.
My name is Bob.
My name is Carol.

Résumé

Dans cet article, j'ai écrit un programme, je l'ai compilé, puis créé et exécuté un fichier .jar. Vous avez peut-être senti que le contenu du travail est très différent entre le travail dans l'EDI et les commandes de la CLI pour compiler et exécuter. Bien que vous puissiez travailler de manière intuitive dans un IDE avec une interface utilisateur, vous devez comprendre et exécuter chaque commande dans la CLI. Je pense que comprendre le contenu de cet article vous aidera également à comprendre le travail dans IDE.

prime

OpenJDK inclut un outil qui peut réassembler le fichier compilé .class, et vous pouvez suivre la déclaration détaillée du programme, donc si vous pouvez vous le permettre, vous devriez y jeter un coup d'œil.

$ javap -v -classpath classes jp.co.sample.App
Classfile /home/vagrant/java_test/classes/jp/co/sample/App.class
  Last modified 2019/04/30; size 469 bytes
  MD5 checksum 7ad6f96dd09200ac12a4c48cadb71ea8
  Compiled from "App.java"
class jp.co.sample.App
  minor version: 0
  major version: 54
  flags: (0x0020) ACC_SUPER
  this_class: #5                          // jp/co/sample/App
  super_class: #6                         // java/lang/Object
  interfaces: 0, fields: 0, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #6.#17         // java/lang/Object."<init>":()V
   #2 = Class              #18            // jp/co/sample/lib/Human
   #3 = Methodref          #2.#19         // jp/co/sample/lib/Human."<init>":(Ljava/lang/String;)V
   #4 = Methodref          #2.#20         // jp/co/sample/lib/Human.introduceMyself:()V
   #5 = Class              #21            // jp/co/sample/App
   #6 = Class              #22            // java/lang/Object
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               ([Ljava/lang/String;)V
  #13 = Utf8               StackMapTable
  #14 = Class              #23            // "[Ljava/lang/String;"
  #15 = Utf8               SourceFile
  #16 = Utf8               App.java
  #17 = NameAndType        #7:#8          // "<init>":()V
  #18 = Utf8               jp/co/sample/lib/Human
  #19 = NameAndType        #7:#24         // "<init>":(Ljava/lang/String;)V
  #20 = NameAndType        #25:#8         // introduceMyself:()V
  #21 = Utf8               jp/co/sample/App
  #22 = Utf8               java/lang/Object
  #23 = Utf8               [Ljava/lang/String;
  #24 = Utf8               (Ljava/lang/String;)V
  #25 = Utf8               introduceMyself
{
  jp.co.sample.App();
    descriptor: ()V
    flags: (0x0000)
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 5: 0

  public static void main(java.lang.String[]); 
    descriptor: ([Ljava/lang/String;)V
    flags: (0x0009) ACC_PUBLIC, ACC_STATIC
    Code:
      stack=3, locals=6, args_size=1
         0: aload_0
         1: astore_1
         2: aload_1
         3: arraylength
         4: istore_2
         5: iconst_0
         6: istore_3
         7: iload_3
         8: iload_2
         9: if_icmpge     39
        12: aload_1
        13: iload_3
        14: aaload
        15: astore        4
        17: new           #2                  // class jp/co/sample/lib/Human
        20: dup
        21: aload         4
        23: invokespecial #3                  // Method jp/co/sample/lib/Human."<init>":(Ljava/lang/String;)V
        26: astore        5
        28: aload         5
        30: invokevirtual #4                  // Method jp/co/sample/lib/Human.introduceMyself:()V
        33: iinc          3, 1
        36: goto          7
        39: return
      LineNumberTable:
        line 7: 0
        line 8: 17
        line 9: 28
        line 7: 33
        line 11: 39
      StackMapTable: number_of_entries = 2
        frame_type = 254 /* append */
          offset_delta = 7
          locals = [ class "[Ljava/lang/String;", int, int ]
        frame_type = 248 /* chop */
          offset_delta = 31
}
SourceFile: "App.java"

Recommended Posts

Compilation et exécution Java comprises par CLI
Exécution par sous-shell (et mise à jour des variables)
Notifier l'erreur et la fin de l'exécution par LINE [Python]
exécution et erreur de pytube
Comprendre le modèle Decorator en comparant le code JavaScript et Java
Comprendre le modèle d'état en comparant le code JavaScript et Java
Comprendre le modèle composite en comparant le code JavaScript et Java
Différence entre le processus de premier plan et le processus d'arrière-plan compris par principe