Как запустить программу java? Как запустить java-приложение из командной строки.

Как запустить программу java?

Ответ мастера:

Приложение, которое написанно на языке java, является jar-архивом или набором файлов *.java и *.class, в том случае, если составляющие данной программы не скомпилированы в исполняемый jar-архив. Для того, чтобы запустить подобное приложение, вам понадобиться установить программу Java Runtime Environment.

Для этого необходимо зайти на страничку официального сайта разработчиков java, которая находится по адресу http://java.sun.com/javaee/sdk/, после чего выполнить загрузку последней версии java-машины. Далее нужно будет установить программу на винчестер своего персонального компьютера и указать ОС путь к установленным вами файлам, для чего необходимо добавить в параметр path переменных среды (вкладка называется «Дополнительно», находится в окне свойств компьютера) путь к месту, куда установлена программа.

Воспользовавшись главным меню или введя команду cmd, в поле «Выполнить», необходимо запустить командную строку. В командной строке зайдите в директорию java-программы, которую нужно запустить. После выполнения данной процедуры, введите команду java -cp [имя файла].jar [имя основного класса программы] и нажмите на клавишу Enter, это запустит выполнение файла.

Для того, чтобы скомпилировать java-файлы, нужно ввести команду javac[название основного файла].java, а после нее java -cp [имя файла]. Получив из командной строки информацию о параметрах запуска java-файлов, нужно ввести оператор java -help и нажать на клавишу Enter.

На экране высветится полный список доступных команд вместе с их опциями. Все команды необходимо вводите точно, потому как, введя ошибочную комбинацию, можно навредить всей операционной системе вашего персонального компьютера.

Если вы хотите запускать мини-игры на своем компьютере, которые написаны на языке java для мобильных устройств, то вам нужно будет загрузить программу MidpX. Это приложение позволит запускать jar-файлы без лишних сложностей. После того, как вы установите данное программное обеспечение, кликните правой клавишей мыши по одному из файлов jar и выберите пункт с названием «Свойства». В появившемся окне, необходимо будет нажать на кнопку «Изменить» и выбрать подходящую для открытия подобного типа файлов программу, то есть утилиту MidpX.

Сейчас уже никто не создает программы в консоли. Используя любимую IDE, разработчик чувствует себя неуютно за чужим компьютером, где её нет.
Решив разобраться в работе Ant и Maven, я поймал себя на том, что не смогу собрать приложение без них в консоли.
В данной статье я постарался уместить все этапы проектирования демонстрационного приложения, чтобы не искать справку по каждой команде на просторах Интернета.

От простого к...

Каждая программа обычно содержится в отдельном каталоге. Я придерживаюсь правила создавать в этом каталоге по крайней мере две папки: src и bin. В первой содержатся исходные коды, во второй - результат компиляции. В данных папках будет структура каталогов, зависящая от пакетов.

Один файл

Можно сделать и без лишних папок.
Берем сам файл HelloWorld.java. public class HelloWorld { public static void main(String args) { System.out.println("Hello World!"); } }
Переходим в каталог, где лежит данный файл, и выполняем команды.
javac HelloWorld.java В данной папке появится файл HelloWorld.class. Значит программа скомпилирована. Чтобы запустить
java -classpath . HelloWorld

Отделяем бинарные файлы от исходников

Теперь сделаем тоже самое, но с каталогами. Создадим каталог HelloWorld и в нем две папки src и bin.
Компилируем
javac -d bin src/HelloWorld.java Здесь мы указали, что бинарные файлы будут сохраняться в отдельную папку bin и не путаться с исходниками.

Запускаем
java -classpath ./bin HelloWorld

Используем пакеты

А то, вдруг, программа перестанет быть просто HelloWorld-ом. Пакетам лучше давать понятное и уникальное имя. Это позволит добавить данную программу в другой проект без конфликта имен. Прочитав некоторые статьи, можно подумать, что для имени пакета обязательно нужен домен. Это не так. Домены - это удобный способ добиться уникальности. Если своего домена нет, воспользуйтесь аккаунтом на сайте (например, ru.habrahabr.mylogin). Он будет уникальным. Учтите, что имена пакетов должны быть в нижнем регистре. И избегайте использования спецсимволов. Проблемы возникают из-за разных платформ и файловых систем.

Поместим наш класс в пакет с именем com.qwertovsky.helloworld. Для этого добавим в начало файла строчку
package com.qwertovsky.helloworld; В каталоге src создадим дополнительные каталоги, чтобы путь к файлу выглядел так: src/com/qwertovsky/helloworld/HelloWorld.java.
Компилируем
javac -d bin src/com/qwertovsky/helloworld/HelloWorld.java В каталоге bin автоматически создастся структура каталогов как и в src.
HelloWorld "---bin " "---com " "---qwertovsky " "---helloworld " "---HelloWorld.class "---src "---com "---qwertovsky "---helloworld "---HelloWorld.java
Запускаем
java -classpath ./bin com.qwertovsky.helloworld.HelloWorld

Если в программе несколько файлов

Изменим программу.
HelloWorld.java
package com.qwertovsky.helloworld; public class HelloWorld { public static void main(String args) { int a=2; int b=3; Calculator calc=new Calculator(); System.out.println("Hello World!"); System.out.println(a+"+"+b+"="+calc.sum(a,b)); } }
Calculator.java
package com.qwertovsky.helloworld; import com.qwertovsky.helloworld.operation.Adder; public class Calculator { public int sum(int... a) { Adder adder=new Adder(); for(int i:a) { adder.add(i); } return adder.getSum(); } }
Adder.java
package com.qwertovsky.helloworld.operation; public class Adder { private int sum; public Adder() { sum=0; } public Adder(int a) { this.sum=a; } public void add(int b) { sum+=b; } public int getSum() { return sum; } }
Компилируем
javac -d bin src/com/qwertovsky/helloworld/HelloWorld.java src\com\qwertovsky\helloworld\HelloWorld.java:9: cannot find symbol symbol: class Calculator location: class com.qwertovsky.helloworld.HelloWorld Calculator calc=new Calculator(); ^ src\com\qwertovsky\helloworld\HelloWorld.java:9: cannot find symbol symbol: class Calculator location: class com.qwertovsky.helloworld.HelloWorld Calculator calc=new Calculator(); ^ 2 errors
Ошибка возникла из-за того, что для компиляции нужны файлы с исходными кодами классов, которые используются (класс Calculator). Надо указать компилятору каталог с файлами с помощью ключа -sourcepath.
Компилируем
javac -sourcepath ./src -d bin src/com/qwertovsky/helloworld/HelloWorld.java
Запускаем
java -classpath ./bin com.qwertovsky.helloworld.HelloWorld Hello Word 2+3=5

Если удивляет результат

Есть возможность запустить отладчик. Для этого существует jdb.
Сначала компилируем с ключом -g, чтобы у отладчика была информация.
javac -g -sourcepath ./src -d bin src/com/qwertovsky/helloworld/HelloWorld.java
Запускаем отладчик
jdb -classpath bin -sourcepath src com.qwertovsky.helloworld.HelloWorld Initializing jdb ... >
Отладчик запускает свой внутренний терминал для ввода команд. Справку по последним можно вывести с помощью команды help.
Указываем точку прерывания на 9 строке в классе Calculator
> stop at com.qwertovsky.helloworld.Calculator:9 Deferring breakpoint com.qwertovsky.helloworld.Calculator:9. It will be set after the class is loaded.
Запускаем на выполнение.
> run run com.qwertovsky.helloworld.HelloWorld Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable > VM Started: Set deferred breakpoint com.qwertovsky.helloworld.Calculator:9 Hello World! Breakpoint hit: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=9 bci=0 9 Adder adder=new Adder();
Чтобы соориентироваться можно вывести кусок исходного кода, где в данный момент находится курссор.
main list 5 public class Calculator 6 { 7 public int sum(int... a) 8 { 9 => Adder adder=new Adder(); 10 for(int i:a) 11 { 12 adder.add(i); 13 } 14 return adder.getSum();
Узнаем, что из себя представляет переменная а.
main print a a = instance of int (id=340) main dump a a = { 2, 3 } main stop at com.qwertovsky.helloworld.operation.Adder:19 Deferring breakpoint com.qwertovsky.helloworld.operation.Adder:19. It will be set after the class is loaded.
Продолжим исполнение.
main cont > Set deferred breakpoint com.qwertovsky.helloworld.operation.Adder:19 Breakpoint hit: "thread=main", com.qwertovsky.helloworld.operation.Adder.add(), line=19 bci=0 19 sum+=b; main list 15 } 16 17 public void add(int b) 18 { 19 => sum+=b; 20 } 21 22 public int getSum() 23 { 24 return sum; main print sum sum = 0 main print b b = 2
Выполним код в текущей строке и увидим, что sum стала равняться 2.
main step > Step completed: "thread=main", com.qwertovsky.helloworld.operation.Adder.add(), line=20 bci=10 20 } main print sum sum = 2
Поднимемся из класса Adder в вызвавший его класс Calculator.
main step up > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=10 bci=36 10 for(int i:a)
Удаляем точку прерывания
main clear com.qwertovsky.helloworld.operation.Adder:19 Removed: breakpoint com.qwertovsky.helloworld.operation.Adder:19 main step > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=12 bci=30 12 adder.add(i);
Можно избежать захода в методы, используя команду next.
main next > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=10 bci=36 10 for(int i:a) main next > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=14 bci=42 14 return adder.getSum();
Проверяем значение выражения и завершаем выполнение.
main eval adder.getSum() adder.getSum() = 5 main cont > 2+3=5 The application exited

Хорошо бы протестировать

Используем JUnit.
package com.qwertovsky.helloworld; import static org.junit.Assert.*; import java.util.Arrays; import java.util.Collection; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized.Parameters; @RunWith(value=org.junit.runners.Parameterized.class) public class TestCalculator { int expected; int arg; @Parameters public static Collection parameters() { return Arrays.asList(new int{ {{4}, {2, 2}} ,{{-1},{4, -5}} ,{{0},{0,0,0}} ,{{0},{}} }); } public TestCalculator(int expected, int arg) { this.expected=expected; this.arg=arg; } @Test public void testSum() { Calculator c=new Calculator(); assertEquals(expected,c.sum(arg)); } }
Компилируем
mkdir test_bin javac -classpath lib/path/junit-4.8.2.jar -sourcepath ./src -d test_bin test/com/qwertovsky/helloworld/TestCalculator.java
Запускаем. В качестве разделителя нескольких путей в classpath в Windows используется ";", в Linux - ":". В консоли Cygwin не работают оба разделителя. Возможно, должен работать ";", но он воспринимается как разделитель команд.
java -classpath lib/path/junit-4.8.2.jar:./test_bin org.junit.runner.JUnitCore com.qwertovsky.helloworld.TestCalculator JUnit version 4.8.2 .... Time: 0,031 OK (4 tests)

Создадим библиотеку

Класс Calculator оказался полезным и может быть использован во многих проектах. Перенесем всё, что касается класса Calculator в отдельный проект.
HelloWorld "---bin "---src "---com "---qwertovsky "---helloworld "---HelloWorld.java Сalculator "---bin "---src " "---com " "---qwertovsky " "---calculator " "---Calculator.java " "---operation " "---Adder.java "---test "---com "---qwertovsky "---calculator "---TestCalculator.java
Измените также назавания пакетов в исходных текстах. В HelloWorld.java нужно будет добавить строку
import com.qwertovsky.calculator.Calculator;
Компилируем.
cd Calculator javac -sourcepath src -d bin src/com/qwertovsky/calculator/Calculator.java
Делаем архив jar
jar cvf calculator.jar -C bin . added manifest adding: com/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/calculator/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/calculator/Calculator.class(in = 497) (out= 373)(deflated 24%) adding: com/qwertovsky/calculator/operation/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/calculator/operation/Adder.class(in = 441) (out= 299)(deflated 32%)
С помощью ключа -C мы запустили программу в каталоге bin.

Надо узнать, что у библиотеки внутри

Можно распаковать архив zip-распаковщиком и посмотреть, какие классы есть в библиотеке.
Информацию о любом классе можно получить с помощью дизассемблера javap.
javap -c -classpath calculator.jar com.qwertovsky.calculator.Calculator Compiled from "Calculator.java" public class com.qwertovsky.calculator.Calculator extends java.lang.Object{ public com.qwertovsky.calculator.Calculator(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public int sum(int); Code: 0: new #2; //class com/qwertovsky/calculator/operation/Adder 3: dup 4: invokespecial #3; //Method com/qwertovsky/calculator/operation/Adder."":()V 7: astore_2 8: aload_1 9: astore_3 10: aload_3 11: arraylength 12: istore 4 14: iconst_0 15: istore 5 17: iload 5 19: iload 4 21: if_icmpge 42 24: aload_3 25: iload 5 27: iaload 28: istore 6 30: aload_2 31: iload 6 33: invokevirtual #4; //Method com/qwertovsky/calculator/operation/Adder.add:(I)V 36: iinc 5, 1 39: goto 17 42: aload_2 43: invokevirtual #5; //Method com/qwertovsky/calculator/operation/Adder.getSum:()I 46: ireturn }
Из результата видно, что класс содержит кроме пустого конструктора, ещё один метод sum, внутри которого в цикле вызывается метод add класса Adder. По завершении метода sum, вызывается Adder.getSum().
Без ключа -c программа выдаст только список переменных и методов (если использовать -private, то всех).
javap -private -classpath calculator.jar com.qwertovsky.calculator.operation.Adder Compiled from "Adder.java" public class com.qwertovsky.calculator.operation.Adder extends java.lang.Object{ private int sum; public com.qwertovsky.calculator.operation.Adder(); public com.qwertovsky.calculator.operation.Adder(int); public void add(int); public int getSum(); }

Лучше снабдить библиотеку документацией

Изменим для этого класс калькулятора.
package com.qwertovsky.calculator; import com.qwertovsky.calculator.operation.Adder; /** * Калькулятор, который умеет складывать * @author Qwertovsky * */ public class Calculator { /** * Определение суммы слагаемых * @param a массив слагаемых * @return сумма */ public int sum(int... a) { Adder adder=new Adder(); for(int i:a) { adder.add(i); } return adder.getSum(); } }
Документацию можно создать следующей командой. При ошибке программа выдаст список возможных опций.
mkdir doc javadoc -d doc -charset utf-8 -sourcepath src -author -subpackages com.qwertovsky.calculator
В результате получиться следующее

Можно подписать jar-архив

Если требуется подписать свою библиотеку цифровой подписью, на помощь придут keytool и jarsigner.
Генерируем подпись.
keytool -genkey -keyalg rsa -keysize 2048 -alias qwertokey -keystore path/to/qwerto.keystore Enter keystore password: Re-enter new password: What is your first and last name? : Valery Qwertovsky What is the name of your organizational unit? : Qwertovsky What is the name of your organization? : Qwertovsky What is the name of your City or Locality? : Tver What is the name of your State or Province? : Tverskaya obl. What is the two-letter country code for this unit? : RU Is CN=Valery Qwertovsky, OU=Qwertovsky, O=Qwertovsky, L=Tver, ST=Tverskaya obl., C=RU correct? : y Enter key password for (RETURN if same as keystore password): Re-enter new password:
Генерируем Certificate Signing Request (CSR)
keytool -certreq -file path/to/qwertokey.crt -alias qwertokey -keystore path/to/qwerto.keystore
Содержимое полученного файла отправляем в центр сертификации. От центра сертификации получаем сертификат. Сохраняем его в файле (например, qwertokey.cer) и импортируем в хранилище
keytool -import -trustcacerts -keystore path/to/qwert.keystore -alias qwertokey -file path/to/qwertokey.cer
Подписываем jar-архив
jarsigner -keystore path/to/qwerto.keystore calculator.jar qwertokey
Файл qwertokey.cer отправляем всем, кто хочет проверить архив. Проверяется он так
jarsigner -verify -verbose -certs -keystore path/to/qwerto.keystore calculator.jar

Использование библиотеки

Есть программа HelloWorld, которая использует библиотечный класс Calculator. Чтобы скомпилировать и запустить программу, нужно присоединить библиотеку.
Компилируем
cd HelloWorld javac -sourcepath src -d bin -classpath path/to/calculator.jar src/com/qwertovsky/helloworld/HelloWorld.java
Запускаем
java -classpath bin:path/to/calculator.jar com.qwertovsky.helloworld.HelloWorld

Собираем программу

Это можно сделать по-разному.

Первый способ

cd HelloWorld echo main-class: com.qwertovsky.helloworld.HelloWorld>manifest.mf echo class-path: lib/calculator.jar >>manifest.mf mkdir lib cp path/to/calculator.jar lib/calculator.jar jar -cmf manifest.mf helloworld.jar -C bin .
Здесь есть тонкости.
В строке
main-class: com.qwertovsky.helloworld.HelloWorld
не должно быть пробелов в конце.
Вторая тонкость описана в : в этой же строке должен стоять перенос на следующую строку. Это если манифест помещается в архив сторонним архиватором.
Программа jar не включит в манифест последнюю строку из манифеста, если в конце не стоит перенос строки.
Ещё момент: в манифесте не должно быть пустых строк между строками. Будет выдана ошибка «java.io.IOException: invalid manifest format».

При использовании команды echo надо следить только за пробелом в конце строки с main-class.

Второй способ

cd HelloWorld echo class-path: lib/calculator.jar >manifest.mf mkdir lib cp path/to/calculator.jar lib/calculator.jar jar -cmef manifest.mf com.qwertovsky.helloworld.HelloWorld helloworld.jar -C bin .
В данном способе избегаем ошибки с пробелом в main-class.

Третий способ

cd HelloWorld mkdir lib cd lib jar -xvf path/to/calculator.jar com/ created: com/ created: com/qwertovsky/ created: com/qwertovsky/calculator/ inflated: com/qwertovsky/calculator/Calculator.class created: com/qwertovsky/calculator/operation/ inflated: com/qwertovsky/calculator/operation/Adder.class cd .. cp -r bin/* lib/ jar -cef com.qwertovsky.helloworld.HelloWorld helloworld.jar -C lib . rm -r lib
Включили код нужной библиотеки в исполняемый файл.

Запуск исполняемого jar-файла

Файл calculator.jar исполняемым не является. А вот helloworld.jar можно запустить.
Если архив был создан первыми двумя способами, то рядом с ним в одном каталоге должна находится папка lib с файлом calculator.jar. Такие ограничения из-за того, что в манифесте в class-path указан путь относительно исполняемого файла.
cd Calculator ls ../HelloWorld/lib calculator.jar java -jar ../HelloWorld/helloworld.jar
При использовании третьего способа нужные библиотеки включаются в исполняемый файл. Держать рядом нужные библиотеки не требуется. Запускается аналогично.
java -jar ../HelloWorld/helloworld.jar

Как быть с приложениями JavaEE

Аналогично. Только библиотеки для компиляции нужно брать у сервера приложений, который используется. Если я использую JBoss, то для компиляции сервлета мне нужно будет выполнить примерно следующее
javac -classpath path/to/jboss/common/lib/jboss-servlet*.jar -d ./classes src/com/qwertovsky/app/servlets/MenuSt.java
Структура архива JavaEE-приложения должна соответствовать определенному формату. Например
my.ear `---META-INF | `---manifest.mf `---lib | `---mylib.jar `---my.war | `---META-INF | | `---manifest.mf | `---WEB-INF | | `---lib | | | `---myweblib.jar | | `---classes | | | `---com | | | `---... | | `---web.xml | `---index.html | `---<остальное веб-содержимое (страницы, изображения)> `---myejb.jar
Способы запуска приложения на самом сервере с помощью командной строки для каждого сервера различны.

Надеюсь, данная статья станет для кого-нибудь шпаргалкой для работы с Java в командной строке. Данные навыки помогут понять содержание и смысл Ant-скриптов и ответить на собеседовании на более каверзные вопросы, чем «Какая IDE Вам больше нравится?».

Задача: Запуск приложения java из командной строки.

Для примера я наваял небольшую програмку, которая должна вычислять площадь круга по заданному радиусу. Программа содержит два класса: GeometryWF (главный) и Circle. Предполагается создать консольное приложение. Запуск приложения java должен производиться из командной строки .

package geometrywf;
public class GeometryWF {
public static void main(String args) {
try {
if (args.equals("circle")) {
Circle c = new Circle(Double.parseDouble(args));
System.out.println("Circle perimetre: "+c.perimeter());
System.out.println("Circle aria: "+c.area());
}
}
catch(ArrayIndexOutOfBoundsException e) {
System.out.println("Ошибочные входные параметры!");
}
}
}

package geometrywf;
public class Circle {
public double r = 0;
public Circle(double r) {
this.r = r;
}
public double area() {
return(Math.PI*r*r);
}
public double perimeter() {
return(2*Math.PI*r);
}
}

Далее нужно собрать проект. Для разработки я использую NetBeans IDE. Соответственно сборку осуществляю нажатем сочетания "Shift+F11" ("Очистить и собрать проект"). На выходе получаю готовый jar-файл
(C:\Users\Иван\Documents\NetBeansProjects\GeometryWF\dist\GeometryWF.jar).

Запуск из командной строки.

Прежде, чем запускать командную строку, кликаем правой кнопкой мыши по значку "Мой компьютер" и открываем "Свойства". Переходим в "Дополнительные параметы системы"->"Переменные среды". В разделе "Системные переменные" необходимо создать новую переменную "JAVA_HOME" со значением "" (у меня это "C:\glassfish3\jdk\bin"). Этот же путь нужно прописать в уе существующую переменную Path после точки с запятой. Все сохраняем и запускаем командную строку.

Меняем директорию на папку с jar-файлом при помощи команды CHDIR:

C:\Users\Иван> CHDIR C:\Users\Иван\Documents\NetBeansProjects\GeometryWF\dist\

Выполняем запуск приложения java из командной строки при помощи команды "java -jar .

C:\Users\Иван\Documents\NetBeansProjects\GeometryWF\dist> java -jar GeometryWF.jar circle 9

На выходе получаем:

Circle perimetre: 56.548667764616276
Circle square: 254.46900494077323

Сейчас уже никто не создает программы в консоли. Используя любимую IDE, разработчик чувствует себя неуютно за чужим компьютером, где её нет.
Решив разобраться в работе Ant и Maven, я поймал себя на том, что не смогу собрать приложение без них в консоли.
В данной статье я постарался уместить все этапы проектирования демонстрационного приложения, чтобы не искать справку по каждой команде на просторах Интернета.

От простого к...

Каждая программа обычно содержится в отдельном каталоге. Я придерживаюсь правила создавать в этом каталоге по крайней мере две папки: src и bin. В первой содержатся исходные коды, во второй - результат компиляции. В данных папках будет структура каталогов, зависящая от пакетов.

Один файл

Можно сделать и без лишних папок.
Берем сам файл HelloWorld.java. public class HelloWorld { public static void main(String args) { System.out.println("Hello World!"); } }
Переходим в каталог, где лежит данный файл, и выполняем команды.
javac HelloWorld.java В данной папке появится файл HelloWorld.class. Значит программа скомпилирована. Чтобы запустить
java -classpath . HelloWorld

Отделяем бинарные файлы от исходников

Теперь сделаем тоже самое, но с каталогами. Создадим каталог HelloWorld и в нем две папки src и bin.
Компилируем
javac -d bin src/HelloWorld.java Здесь мы указали, что бинарные файлы будут сохраняться в отдельную папку bin и не путаться с исходниками.

Запускаем
java -classpath ./bin HelloWorld

Используем пакеты

А то, вдруг, программа перестанет быть просто HelloWorld-ом. Пакетам лучше давать понятное и уникальное имя. Это позволит добавить данную программу в другой проект без конфликта имен. Прочитав некоторые статьи, можно подумать, что для имени пакета обязательно нужен домен. Это не так. Домены - это удобный способ добиться уникальности. Если своего домена нет, воспользуйтесь аккаунтом на сайте (например, ru.habrahabr.mylogin). Он будет уникальным. Учтите, что имена пакетов должны быть в нижнем регистре. И избегайте использования спецсимволов. Проблемы возникают из-за разных платформ и файловых систем.

Поместим наш класс в пакет с именем com.qwertovsky.helloworld. Для этого добавим в начало файла строчку
package com.qwertovsky.helloworld; В каталоге src создадим дополнительные каталоги, чтобы путь к файлу выглядел так: src/com/qwertovsky/helloworld/HelloWorld.java.
Компилируем
javac -d bin src/com/qwertovsky/helloworld/HelloWorld.java В каталоге bin автоматически создастся структура каталогов как и в src.
HelloWorld "---bin " "---com " "---qwertovsky " "---helloworld " "---HelloWorld.class "---src "---com "---qwertovsky "---helloworld "---HelloWorld.java
Запускаем
java -classpath ./bin com.qwertovsky.helloworld.HelloWorld

Если в программе несколько файлов

Изменим программу.
HelloWorld.java
package com.qwertovsky.helloworld; public class HelloWorld { public static void main(String args) { int a=2; int b=3; Calculator calc=new Calculator(); System.out.println("Hello World!"); System.out.println(a+"+"+b+"="+calc.sum(a,b)); } }
Calculator.java
package com.qwertovsky.helloworld; import com.qwertovsky.helloworld.operation.Adder; public class Calculator { public int sum(int... a) { Adder adder=new Adder(); for(int i:a) { adder.add(i); } return adder.getSum(); } }
Adder.java
package com.qwertovsky.helloworld.operation; public class Adder { private int sum; public Adder() { sum=0; } public Adder(int a) { this.sum=a; } public void add(int b) { sum+=b; } public int getSum() { return sum; } }
Компилируем
javac -d bin src/com/qwertovsky/helloworld/HelloWorld.java src\com\qwertovsky\helloworld\HelloWorld.java:9: cannot find symbol symbol: class Calculator location: class com.qwertovsky.helloworld.HelloWorld Calculator calc=new Calculator(); ^ src\com\qwertovsky\helloworld\HelloWorld.java:9: cannot find symbol symbol: class Calculator location: class com.qwertovsky.helloworld.HelloWorld Calculator calc=new Calculator(); ^ 2 errors
Ошибка возникла из-за того, что для компиляции нужны файлы с исходными кодами классов, которые используются (класс Calculator). Надо указать компилятору каталог с файлами с помощью ключа -sourcepath.
Компилируем
javac -sourcepath ./src -d bin src/com/qwertovsky/helloworld/HelloWorld.java
Запускаем
java -classpath ./bin com.qwertovsky.helloworld.HelloWorld Hello Word 2+3=5

Если удивляет результат

Есть возможность запустить отладчик. Для этого существует jdb.
Сначала компилируем с ключом -g, чтобы у отладчика была информация.
javac -g -sourcepath ./src -d bin src/com/qwertovsky/helloworld/HelloWorld.java
Запускаем отладчик
jdb -classpath bin -sourcepath src com.qwertovsky.helloworld.HelloWorld Initializing jdb ... >
Отладчик запускает свой внутренний терминал для ввода команд. Справку по последним можно вывести с помощью команды help.
Указываем точку прерывания на 9 строке в классе Calculator
> stop at com.qwertovsky.helloworld.Calculator:9 Deferring breakpoint com.qwertovsky.helloworld.Calculator:9. It will be set after the class is loaded.
Запускаем на выполнение.
> run run com.qwertovsky.helloworld.HelloWorld Set uncaught java.lang.Throwable Set deferred uncaught java.lang.Throwable > VM Started: Set deferred breakpoint com.qwertovsky.helloworld.Calculator:9 Hello World! Breakpoint hit: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=9 bci=0 9 Adder adder=new Adder();
Чтобы соориентироваться можно вывести кусок исходного кода, где в данный момент находится курссор.
main list 5 public class Calculator 6 { 7 public int sum(int... a) 8 { 9 => Adder adder=new Adder(); 10 for(int i:a) 11 { 12 adder.add(i); 13 } 14 return adder.getSum();
Узнаем, что из себя представляет переменная а.
main print a a = instance of int (id=340) main dump a a = { 2, 3 } main stop at com.qwertovsky.helloworld.operation.Adder:19 Deferring breakpoint com.qwertovsky.helloworld.operation.Adder:19. It will be set after the class is loaded.
Продолжим исполнение.
main cont > Set deferred breakpoint com.qwertovsky.helloworld.operation.Adder:19 Breakpoint hit: "thread=main", com.qwertovsky.helloworld.operation.Adder.add(), line=19 bci=0 19 sum+=b; main list 15 } 16 17 public void add(int b) 18 { 19 => sum+=b; 20 } 21 22 public int getSum() 23 { 24 return sum; main print sum sum = 0 main print b b = 2
Выполним код в текущей строке и увидим, что sum стала равняться 2.
main step > Step completed: "thread=main", com.qwertovsky.helloworld.operation.Adder.add(), line=20 bci=10 20 } main print sum sum = 2
Поднимемся из класса Adder в вызвавший его класс Calculator.
main step up > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=10 bci=36 10 for(int i:a)
Удаляем точку прерывания
main clear com.qwertovsky.helloworld.operation.Adder:19 Removed: breakpoint com.qwertovsky.helloworld.operation.Adder:19 main step > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=12 bci=30 12 adder.add(i);
Можно избежать захода в методы, используя команду next.
main next > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=10 bci=36 10 for(int i:a) main next > Step completed: "thread=main", com.qwertovsky.helloworld.Calculator.sum(), line=14 bci=42 14 return adder.getSum();
Проверяем значение выражения и завершаем выполнение.
main eval adder.getSum() adder.getSum() = 5 main cont > 2+3=5 The application exited

Хорошо бы протестировать

Используем JUnit.
package com.qwertovsky.helloworld; import static org.junit.Assert.*; import java.util.Arrays; import java.util.Collection; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized.Parameters; @RunWith(value=org.junit.runners.Parameterized.class) public class TestCalculator { int expected; int arg; @Parameters public static Collection parameters() { return Arrays.asList(new int{ {{4}, {2, 2}} ,{{-1},{4, -5}} ,{{0},{0,0,0}} ,{{0},{}} }); } public TestCalculator(int expected, int arg) { this.expected=expected; this.arg=arg; } @Test public void testSum() { Calculator c=new Calculator(); assertEquals(expected,c.sum(arg)); } }
Компилируем
mkdir test_bin javac -classpath lib/path/junit-4.8.2.jar -sourcepath ./src -d test_bin test/com/qwertovsky/helloworld/TestCalculator.java
Запускаем. В качестве разделителя нескольких путей в classpath в Windows используется ";", в Linux - ":". В консоли Cygwin не работают оба разделителя. Возможно, должен работать ";", но он воспринимается как разделитель команд.
java -classpath lib/path/junit-4.8.2.jar:./test_bin org.junit.runner.JUnitCore com.qwertovsky.helloworld.TestCalculator JUnit version 4.8.2 .... Time: 0,031 OK (4 tests)

Создадим библиотеку

Класс Calculator оказался полезным и может быть использован во многих проектах. Перенесем всё, что касается класса Calculator в отдельный проект.
HelloWorld "---bin "---src "---com "---qwertovsky "---helloworld "---HelloWorld.java Сalculator "---bin "---src " "---com " "---qwertovsky " "---calculator " "---Calculator.java " "---operation " "---Adder.java "---test "---com "---qwertovsky "---calculator "---TestCalculator.java
Измените также назавания пакетов в исходных текстах. В HelloWorld.java нужно будет добавить строку
import com.qwertovsky.calculator.Calculator;
Компилируем.
cd Calculator javac -sourcepath src -d bin src/com/qwertovsky/calculator/Calculator.java
Делаем архив jar
jar cvf calculator.jar -C bin . added manifest adding: com/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/calculator/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/calculator/Calculator.class(in = 497) (out= 373)(deflated 24%) adding: com/qwertovsky/calculator/operation/(in = 0) (out= 0)(stored 0%) adding: com/qwertovsky/calculator/operation/Adder.class(in = 441) (out= 299)(deflated 32%)
С помощью ключа -C мы запустили программу в каталоге bin.

Надо узнать, что у библиотеки внутри

Можно распаковать архив zip-распаковщиком и посмотреть, какие классы есть в библиотеке.
Информацию о любом классе можно получить с помощью дизассемблера javap.
javap -c -classpath calculator.jar com.qwertovsky.calculator.Calculator Compiled from "Calculator.java" public class com.qwertovsky.calculator.Calculator extends java.lang.Object{ public com.qwertovsky.calculator.Calculator(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: return public int sum(int); Code: 0: new #2; //class com/qwertovsky/calculator/operation/Adder 3: dup 4: invokespecial #3; //Method com/qwertovsky/calculator/operation/Adder."":()V 7: astore_2 8: aload_1 9: astore_3 10: aload_3 11: arraylength 12: istore 4 14: iconst_0 15: istore 5 17: iload 5 19: iload 4 21: if_icmpge 42 24: aload_3 25: iload 5 27: iaload 28: istore 6 30: aload_2 31: iload 6 33: invokevirtual #4; //Method com/qwertovsky/calculator/operation/Adder.add:(I)V 36: iinc 5, 1 39: goto 17 42: aload_2 43: invokevirtual #5; //Method com/qwertovsky/calculator/operation/Adder.getSum:()I 46: ireturn }
Из результата видно, что класс содержит кроме пустого конструктора, ещё один метод sum, внутри которого в цикле вызывается метод add класса Adder. По завершении метода sum, вызывается Adder.getSum().
Без ключа -c программа выдаст только список переменных и методов (если использовать -private, то всех).
javap -private -classpath calculator.jar com.qwertovsky.calculator.operation.Adder Compiled from "Adder.java" public class com.qwertovsky.calculator.operation.Adder extends java.lang.Object{ private int sum; public com.qwertovsky.calculator.operation.Adder(); public com.qwertovsky.calculator.operation.Adder(int); public void add(int); public int getSum(); }

Лучше снабдить библиотеку документацией

Изменим для этого класс калькулятора.
package com.qwertovsky.calculator; import com.qwertovsky.calculator.operation.Adder; /** * Калькулятор, который умеет складывать * @author Qwertovsky * */ public class Calculator { /** * Определение суммы слагаемых * @param a массив слагаемых * @return сумма */ public int sum(int... a) { Adder adder=new Adder(); for(int i:a) { adder.add(i); } return adder.getSum(); } }
Документацию можно создать следующей командой. При ошибке программа выдаст список возможных опций.
mkdir doc javadoc -d doc -charset utf-8 -sourcepath src -author -subpackages com.qwertovsky.calculator
В результате получиться следующее

Можно подписать jar-архив

Если требуется подписать свою библиотеку цифровой подписью, на помощь придут keytool и jarsigner.
Генерируем подпись.
keytool -genkey -keyalg rsa -keysize 2048 -alias qwertokey -keystore path/to/qwerto.keystore Enter keystore password: Re-enter new password: What is your first and last name? : Valery Qwertovsky What is the name of your organizational unit? : Qwertovsky What is the name of your organization? : Qwertovsky What is the name of your City or Locality? : Tver What is the name of your State or Province? : Tverskaya obl. What is the two-letter country code for this unit? : RU Is CN=Valery Qwertovsky, OU=Qwertovsky, O=Qwertovsky, L=Tver, ST=Tverskaya obl., C=RU correct? : y Enter key password for (RETURN if same as keystore password): Re-enter new password:
Генерируем Certificate Signing Request (CSR)
keytool -certreq -file path/to/qwertokey.crt -alias qwertokey -keystore path/to/qwerto.keystore
Содержимое полученного файла отправляем в центр сертификации. От центра сертификации получаем сертификат. Сохраняем его в файле (например, qwertokey.cer) и импортируем в хранилище
keytool -import -trustcacerts -keystore path/to/qwert.keystore -alias qwertokey -file path/to/qwertokey.cer
Подписываем jar-архив
jarsigner -keystore path/to/qwerto.keystore calculator.jar qwertokey
Файл qwertokey.cer отправляем всем, кто хочет проверить архив. Проверяется он так
jarsigner -verify -verbose -certs -keystore path/to/qwerto.keystore calculator.jar

Использование библиотеки

Есть программа HelloWorld, которая использует библиотечный класс Calculator. Чтобы скомпилировать и запустить программу, нужно присоединить библиотеку.
Компилируем
cd HelloWorld javac -sourcepath src -d bin -classpath path/to/calculator.jar src/com/qwertovsky/helloworld/HelloWorld.java
Запускаем
java -classpath bin:path/to/calculator.jar com.qwertovsky.helloworld.HelloWorld

Собираем программу

Это можно сделать по-разному.

Первый способ

cd HelloWorld echo main-class: com.qwertovsky.helloworld.HelloWorld>manifest.mf echo class-path: lib/calculator.jar >>manifest.mf mkdir lib cp path/to/calculator.jar lib/calculator.jar jar -cmf manifest.mf helloworld.jar -C bin .
Здесь есть тонкости.
В строке
main-class: com.qwertovsky.helloworld.HelloWorld
не должно быть пробелов в конце.
Вторая тонкость описана в : в этой же строке должен стоять перенос на следующую строку. Это если манифест помещается в архив сторонним архиватором.
Программа jar не включит в манифест последнюю строку из манифеста, если в конце не стоит перенос строки.
Ещё момент: в манифесте не должно быть пустых строк между строками. Будет выдана ошибка «java.io.IOException: invalid manifest format».

При использовании команды echo надо следить только за пробелом в конце строки с main-class.

Второй способ

cd HelloWorld echo class-path: lib/calculator.jar >manifest.mf mkdir lib cp path/to/calculator.jar lib/calculator.jar jar -cmef manifest.mf com.qwertovsky.helloworld.HelloWorld helloworld.jar -C bin .
В данном способе избегаем ошибки с пробелом в main-class.

Третий способ

cd HelloWorld mkdir lib cd lib jar -xvf path/to/calculator.jar com/ created: com/ created: com/qwertovsky/ created: com/qwertovsky/calculator/ inflated: com/qwertovsky/calculator/Calculator.class created: com/qwertovsky/calculator/operation/ inflated: com/qwertovsky/calculator/operation/Adder.class cd .. cp -r bin/* lib/ jar -cef com.qwertovsky.helloworld.HelloWorld helloworld.jar -C lib . rm -r lib
Включили код нужной библиотеки в исполняемый файл.

Запуск исполняемого jar-файла

Файл calculator.jar исполняемым не является. А вот helloworld.jar можно запустить.
Если архив был создан первыми двумя способами, то рядом с ним в одном каталоге должна находится папка lib с файлом calculator.jar. Такие ограничения из-за того, что в манифесте в class-path указан путь относительно исполняемого файла.
cd Calculator ls ../HelloWorld/lib calculator.jar java -jar ../HelloWorld/helloworld.jar
При использовании третьего способа нужные библиотеки включаются в исполняемый файл. Держать рядом нужные библиотеки не требуется. Запускается аналогично.
java -jar ../HelloWorld/helloworld.jar

Как быть с приложениями JavaEE

Аналогично. Только библиотеки для компиляции нужно брать у сервера приложений, который используется. Если я использую JBoss, то для компиляции сервлета мне нужно будет выполнить примерно следующее
javac -classpath path/to/jboss/common/lib/jboss-servlet*.jar -d ./classes src/com/qwertovsky/app/servlets/MenuSt.java
Структура архива JavaEE-приложения должна соответствовать определенному формату. Например
my.ear `---META-INF | `---manifest.mf `---lib | `---mylib.jar `---my.war | `---META-INF | | `---manifest.mf | `---WEB-INF | | `---lib | | | `---myweblib.jar | | `---classes | | | `---com | | | `---... | | `---web.xml | `---index.html | `---<остальное веб-содержимое (страницы, изображения)> `---myejb.jar
Способы запуска приложения на самом сервере с помощью командной строки для каждого сервера различны.

Надеюсь, данная статья станет для кого-нибудь шпаргалкой для работы с Java в командной строке. Данные навыки помогут понять содержание и смысл Ant-скриптов и ответить на собеседовании на более каверзные вопросы, чем «Какая IDE Вам больше нравится?».



 

Пожалуйста, поделитесь этим материалом в социальных сетях, если он оказался полезен!