logo头像

不破不立

使用命令行编译运行Java程序

本文于724天之前发表,文中内容可能已经过时。

对这个一直有很大的疑惑,总处于那种似懂非懂的感觉,相信很多人都在开始学Java的时候用了一小会command line来运行Java application,但是很少有人用这个来尝试多个class或者使用了external jar。昨晚开始想了一下,来试试这样操作的样子,然后一弄就是几个小时,搞不定,1.多了必须睡觉,想着明天还得上班。
  今天下了班,然后再开始尝试,网上找到了两篇博客,也是看的困惑,不知道是他写的比较乱还是什么,在自己的环境总是运行起来,百度一堆都是些垃圾,然后终于还是想着用几个关键字来Google一下,然后就把自己的问题给解决了。这里保留一份这个问题的记录。

一、使用命令行编译运行引用jar包的Java程序

  我建了一个项目(就是一个空文件夹),名字叫做message,然后在里面按照Java project 的structure来建了一个src的文件,接着里面弄了org.fire.entity和org.fire.test两个package,其实在文件浏览器里面都是文件夹形式。然后分别在entity里面建了一个Message class,在test里面建了一个Test class,整个structure图如下:
  

  两个Java class 的内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
package org.fire.entity;
/**
 * Message.java
 * Created by Pan on 2016/8/31.
 */
public class Message {
    public Message() {
    }
    public void saySomethingWithYou(String message) {
        System.out.println(message);
    }
}

1
2
3
4
5
6
7
8
9
package org.fire.test;
import org.fire.entity.Message;
public class Test {
    public static void main(String[] args) {
        // write your code here
        Message message = new Message();
        message.saySomethingWithYou("nice to meet you!");
    }
}

  然后用javac来compile这个项目,将命令行的path切换到src下面,使用javac开始编译
  javac org\fire\entity\Message.java org\fire\test\Test.java
  然后使用java来run Test 这个类的main方法,看看有没有达到相应的result。
  java org.fire.test.Test
  

  结果显示“nice to meet you!”
  正好是main中需要print的value。
  successful。
  注意,以上都没有指定生成的字节码文件.class放置在具体位置,因此会默认将每个.java对应的.class放置在.java同一个目录。
  我们可以使用
  -d bin
  来指定.class生成的位置,这里可以尝试一下:
  
  
  

  这里可能会注意到有
  -sourcepath src

  这是因为目前我已经不在src目录下了,而是在src上级目录下,所以指定src为源代码文件夹位置。

  整个过程还有可以优化的地方,就是在使用javac来compile的时候。
  think, 如果有多个java class 怎么办,一个一个write?It’s impossible。
  这里将一种方便的方法,不过方便可能也是针对Linux环境说的。
  新建一个txt放在src目录下吧,内容就按照如下方式写:
  

  result如下图:
  

  successful。
  上面所讲的source.txt在linux的环境下不需要手写了,使用命令:
  find -name "*.java" > source.txt
  即可生成。

二、使用命令行编译运行有引用外部jar的Java程序

(一)将项目打包成jar

  先将上面的项目打包成一个jar文件(jar中不包含源码,所以在上述javac操作后的bin目录下进行以下操作)
  在bin目录下新建一个名为“META-INF”文件夹,然后在里面建一个名为“MANIFEST.MF”文件,注意后缀为mf,然后在MANIFEST.MF中写入一下代码(根据自己实际情况编写)
  

  注意事项:第一行是固定格式,定义版本号,第二行就是指明主类的位置可以用空格分开多个声明,注意冒号之后要有一个空格;然后注意的就是后面需要空出2行。
  还要注意把bin下不用的文件删掉,即留下下图所示
  

  然后在bin目录下的command line运行:

  jar -cvfm message.jar META-INF\MANIFEST.MF .

  然后bin目录下多了一个文件,如图:
  

  可以将message解压看看内部内容,可以发现meta-inf下面的manifest.mf文件变成了这样,
  

  程序运行结果:
  

  successful。
  这里测试的只有一个主类,没有测试过多个主类,如果存在多个主类则需要在manifest.mf中定义多个,并且在运行的时候需要指定运行哪一个,假设这里有多个主类,我们需要运行org.fire.test.Test主类,则是在上面的基础上加上org.fire.test.Test即可,如图:
  

(二)新建项目来运行测试外部jar

  新建一个项目,然后弄个TestMessage class,结构如下:
  

  然后用javac compile,java run,result 如下:
  

  project 的structure如下:
  
  注意:
  在使用javac 来compile的时候,linux下分割jar采用冒号“:”,windows下采用分号“;”,在参考blog的第一篇文中有讲:

Task
  Lets say we have a fairly standard java project that consists of three top level folders:
    /bin - empty folder that will contain compiled .class files
    /lib - contains third party .jar files
    /src - contains .java source files  
  Our task would be to compile and launch the project from its root folder. We will use Windows OS as example (on Unix systems the only difference would be path separation symbol - “:” instead of “;”).

  在使用java 来run 的时候,指定了bin为当前程序运行的目录。在参考blog的第一篇文中有讲,如下段:

Some Notes About Classpath
  Lets say during Application.java compilation a compiler stumbles upon somecom.example.Util class. How to find it in the file system? According to Java file naming rules,Util class has to be located somewhere in Util.java file under /com/example/ folder, but where to start searching for this path? Here is where classpath comes into play which sets the starting folder for searching for classes. Classpath can be set in 3 different ways:
  1. If no –classpath parameter is passed, CLASSPATH environment variable is used
  2. If CLASSPATH environment variable is not found, current folder (“.”) is used by default
  3. If –classpath is explicitly set as a command line parameter, it overrides all other values
  The fact that classpath when set overrides default value (current folder) can cause some unexpected results.
  For example if we don’t use any third party libraries, only our own com.example.Util class, and try to compile Application.java from the src folder:
  javac com/example/Application.java
  this would work, but then if we decide to add a third party libarary to the classpath:
  javac -cp lib/lib1.jar com/example/Application.java
  it would cause an error:
  package com.example.Util does not exist
  This happens because when we set -cp lib/lib1.jar we override default value for the classpath - current folder. Now a compiler will be looking for all classes only inside that jar file. To fix this we need to explicitly add the current folder to the classpath:
  javac -cp .;lib/lib1.jar com/example/Application.java

  好了,到此,这篇blog也是差不多了,其实还有很多东西讲的都不清楚,大家可以互相讨论,下面留言即可,我的blog停了将近 一年了,也是自己的问题,现在开了,互动会很快的,不要觉得博主不会看评论,先试试回答,不会有错的。

  这里提醒大家,最好用Google来进行English search,即使Google搜索再好,天朝内部的程序员社区却已经不好了,所以你不论是用百度还是用Google搜到的很多都是一样的rubbish。

  Bear in mind : Google Search in English 。

  参考blog(order by quality):

  1. http://www.sergiy.ca/how-to-compile-and-launch-java-code-from-command-line/
  2. http://stackoverflow.com/questions/17140512/how-to-compile-multiple-java-files-when-there-are-java-files-in-other-packages
  3. http://www.cnblogs.com/freeweb/p/5251358.html
  4. http://stackoverflow.com/questions/13657849/run-java-application-from-command-line-with-external-jar-files
  5. http://www.cnblogs.com/freeweb/p/5251358.html
  6. http://www.importnew.com/11370.html
上一篇

评论系统未开启,无法评论!

如果有好的建议或疑问等可以发送邮件至:panhainan@yeah.net,或者添加QQ:1016593477,将你的建议或者疑问告诉作者,作者会对你的建议进行处理并补充到文章的尾部,谢谢大家的谅解!