I think most of the time I use an IDE for Java programming. Even when you start learning Java programming, it is often required from the preparation of the IDE. However, when beginners start learning from Java programming in the IDE, even if they can write code on the IDE, they cannot deeply understand the parts that the IDE supports, or they can only work depending on the IDE. I can't grow from the state. This article is for beginners to deepen their understanding by executing simple Java programs with CLI without using IDE. It does not mention the detailed reading or writing of the program. Difficult words and concepts may appear for beginners on the way, but it is not necessary to understand them immediately, so please read them and gradually understand them.
It will be the OS to work on this time and the version of Java to be used. In this article, I'm working on CentOS, but if you can't install vagrant, you can work on Mac, and if you replace UNIX commands, you can work on Windows command prompt (not verified). ..
OS
Use this BOX to start a VM with vagrant on VirtualBox and work in it.
$ 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
Install This OpenJDK with yum and use it.
$ 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
Java programs are usually compiled with the javac tool from .java
to .class
bytecode (also called intermediate code) before execution. Then, when the program is executed, the bytecode is executed on the JVM in an interpreted manner, or it is recompiled into machine code by the JIT compiler and executed. The JIT compiler is one of the components of JRE (Java Runtime Environment), and is a mechanism to optimize the machine code of program methods and improve performance.
From here, you will actually compile and execute Java programs and create archives with the CLI.
First, write a program that outputs Hello world.
and execute it. The program file to be executed is as follows, so prepare it with vi etc.
App.java
class App {
public static void main(String[] args) {
System.out.println("Hello world.");
}
}
Compile this with javac.
$ ls
App.java
$ javac App.java
$ ls
App.class App.java
You can see that the .class
file has been generated. Then run it in java. Note that the argument is the class name, not the file name.
$ java App
Hello world.
It was easy, but I compiled and ran the program. There is no problem so far.
Try passing arguments when running the program. Make the following modifications to the previous program file.
App.java
class App {
public static void main(String[] args) {
for (String arg: args) {
System.out.println(String.format("Hello %s.", arg));
}
}
}
Compile and run. Unlike before, let's pass arguments at runtime.
$ java App Alice Bob Carol
Hello Alice.
Hello Bob.
Hello Carol.
You can see that it has received the arguments.
Try accessing other classes in your program. First, create a Human class that represents humans as another class in another file.
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));
}
}
Instantiate the Human class in the main method of the App class.
App.java
class App {
public static void main(String[] args) {
for (String arg: args) {
Human human = new Human(arg);
human.introduceMyself();
}
}
}
Let's compile it.
$ ls
App.java Human.java
$ javac App.java
$ ls
App.class App.java Human.class Human.java
You can see that Human was compiled with the compilation of the app.
$ java App Alice Bob Carol
My name is Alice.
My name is Bob.
My name is Carol.
I created as many Human instances as the number of arguments and confirmed that the method was executed.
Give it a package name and compile it as a program in a separate package. First, give the Human class a package name. Also, since this class is accessed from another package, I gave each qualifier correctly.
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));
}
}
Next, for the App class, give the package name and also describe import to access the Human class.
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();
}
}
}
The package name has been assigned, but it cannot be compiled as it is. In Java, it is necessary to arrange the files in the same directory structure as the package name. So create a directory as below and move the files.
$ tree
.
└── jp
└── co
└── sample
├── App.java
└── lib
└── Human.java
4 directories, 2 files
After moving the file, compile and run it.
$ 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.
It was confirmed that the .class
file was created in the same hierarchy as each .java
file and the program could be executed.
Combine the created .class
files into .jar
and create an archive. The .java
file is not included in .jar
, so separate it as a src directory.
$ tree
.
└── src
└── jp
└── co
└── sample
├── App.java
└── lib
└── Human.java
5 directories, 2 files
Compile and output the .class
file to the classes directory. If you want to run in a location other than the package origin src directory, you need to specify the package origin with the -sourcepath
option.
$ 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
You can see that the classes directory is created and the .class
files are generated under it with the same directory structure as the package.
By the way, if you want to execute at a location other than the package origin at runtime, you need to specify the package origin with the -classpath
option.
$ java -classpath classes jp.co.sample.App Alice Bob Carol
My name is Alice.
My name is Bob.
My name is Carol.
Next, the MANIFEST file is required to create .jar
, so create the following file. The class name that has the main method is described here including the package name. Don't forget that if you don't put a blank line in the last line, it will not be recognized as a MANIFEST file.
manifest.mf
Main-Class: jp.co.sample.App
After preparing the MANIFEST file, create a .jar
file with jar.
$ jar cvfm sample.jar manifest.mf -C classes .
Manifest added
jp/Is being added(Enter=0)(Out=0)(0%Stored)
jp/co/Is being added(Enter=0)(Out=0)(0%Stored)
jp/co/sample/Is being added(Enter=0)(Out=0)(0%Stored)
jp/co/sample/App.class is being added(Enter=469)(Out=343)(26%Shrinked)
jp/co/sample/lib/Is being added(Enter=0)(Out=0)(0%Stored)
jp/co/sample/lib/Human.class is being added(Enter=595)(Out=382)(35%Shrinked)
$ 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
You can see that the .jar
file contains the MANIFEST file and the .class
file.
Finally, let's run the .jar
file.
$ java -jar sample.jar Alice Bob Carol
My name is Alice.
My name is Bob.
My name is Carol.
In this article, I wrote a program, compiled it, and then created and executed a .jar
file. You may have felt that the work content is very different between working in the IDE and typing commands in the CLI to compile and execute. While you can work intuitively with an IDE that has a UI, you need to understand and execute commands one by one when working with the CLI. I think that understanding the contents of this article will also help you understand the work in IDE.
OpenJDK includes a tool that can disassemble the compiled .class
file, and you can follow the detailed instructions of the program, so if you can afford it, you should take a look.
$ 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