前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用命令行编译、运行Java程序

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

作者头像
全栈程序员站长
发布2022-09-08 12:56:18
1.8K0
发布2022-09-08 12:56:18
举报
文章被收录于专栏:全栈程序员必看

大家好,又见面了,我是你们的朋友全栈君。

我们一般都是通过IDE(如Eclipse、Intellij Idea,STS等)来开发,调试java项目。

在不借助IDE的情况下,如何编译、运行Java程序。

使用javac 命令,可以通过只敲击javac 看到各种命令参数。

必学参数 -d -cp,这俩下面会讲到

如果javac命令不能用,看一下环境变量是否没配对。

我们从简单到复杂来看java编译、运行命令

单独类如何编译

我们可以用ide(eclipse、idea,甚至高级点的文本编辑工具Emeditor、Notepad++、UE)准备java文件,然后拷贝到硬盘,比如D盘。javac命令需要带.java后缀名,执行java文件不需要带后缀名。

一、不带包名的类如何编译

1、没有中文的java文件。

准备代码

代码语言:javascript
复制
public class A {

    public static void main(String[] args) {

        System.out.println("abc");

    }

}

命令:

javac A.java

java A

输出结果

2、假设输出的是中文,会怎么样?

修改代码与输出结果,两种情况与两种结果

a)

代码语言:javascript
复制
public class A {

    public static void main(String[] args) {

        System.out.println("你好吗");

    }

}

错误:编码GBK的不可映射字符

b)

代码语言:javascript
复制
public class A {

    public static void main(String[] args) {

        System.out.println("你好");

    }

}

能编译成功,但是输出乱码

原因分析:

我们需要了解javac和java命令是什么样的过程。

javac是java compiler的命令,是将.java文件编译成.class文件的过程。我们需要先将文件读入内存,才能进行编译。

读入内存需要知道文件的编码格式,才能正确的将文件读取。我们查看一下java源文件的编码,发现是UTF-8。而java编译器默认的字符集可以通过如下代码查看。

代码语言:javascript
复制
System.out.println(Charset.defaultCharset());

会发现输出GBK。

也就是java编译器认为文件采用GBK编码,而实际上文件是采用UTF-8编码。然后“你好吗”三个字的UTF-8码值,转换成GBK就是”浣犲ソ鍚�”,这个问号“�”就是一个GBK不可映射的字符。可以用下面的代码试一下:

代码语言:javascript
复制
String s = "你好吗";

String s1 = new String(s.getBytes("utf-8"), "gbk");

System.out.println(s1);

而如果是”你好”两个字的UTF-8码值转换成GBK是这三个字符”浣犲ソ”。

代码语言:javascript
复制
String s = "你好";

String s1 = new String(s.getBytes("utf-8"), "gbk");

System.out.println(s1);

编译器使用了UTF-8的二进制值来尝试转换成GBK,第一次认识到了一个不认识的字符,因为UTF-8的范围很大,这个码值在GBK中没有,就报了这个错。

而第二次编译通过,是因为“你好”这两个字的UTF-8编码,恰好能转换成GBK编码,所以能编译通过。但是编译通过并不保证内容就是正确的,输出的时候仍然是乱码。

问题:

为什么我们通过IDE就能编译通过。

通过IDE,不可能分开java文件编码和java compiler的编码格式的,文件设置成什么编码,编译器都会知道,就会用什么编码来解析。原生的javac不会这样,它只会按照默认的系统编码来编,这个时候如果文件编码不同,就出现这个问题了。

知道了原因,怎么解决,两种解决方案,最终目的是为了文件编码和解码字符集相同

1)如果文件是UTF-8编码的,我们使用-encoding UTF-8 来显式指定为UTF-8的编码格式。

2)将文件改为GBK编码,如果使用windows自带的记事本,保存为ANSI,中国区域会使用GBK编码。如果使用其它高级文本编辑工具,如:notepad++、Emeditor、UE这样的,另存为指定格式。

然后再编译运行就可以了。

这里的GB2312(936)就是GBK,不是GB2312那个阉割版。

二、带包名的类如何编译

准备代码,我们已经讨论过中文乱码问题了,为了简单起见,下面都用英文示范其它的情况。

代码语言:javascript
复制
package mypack;



public class A {

    public static void main(String[] args) {

        System.out.println("abc");

    }

}

编译运行:

我们会发现编译成功,A.class被编译到了D盘根目录下。运行报错“错误:找不到或无法加载主类A”

原因分析:

这里地方有点绕人,我们先分析为什么现在的命令不行。

java A

有包的java程序,需要用完整包名来执行

由于我们没有指定classpath,jvm准备在当前路径下查找A.class来装载,找了一圈没找到(确实有个A类,但是A类的完整路径是mypack.A,所以不是这个),报错找不到或无法加载主类。

java mypack.A

有包的java程序,文件路径中必须包含包名,并以包名结尾

jvm看了一下有包,于是将包转换为路径,也就是期望在D:/mypack文件夹下,找到A.class文件进行装载。也没找到。

如果有包,java命令必须在包的上层目录执行完整路径名(完全限定名),上例中A.class的完全限定名是mypack.A。如果在D盘下,有一个A.java,包路径为aaa.bbb.ccc,必须在D盘下,执行java aaa.bbb.ccc.A才行,此处的“在D盘下”,暂时可以看做直接在D盘下,也可以通过-cp指定到D盘下,这个后面还会说。

解决办法

我们可以使用-d . 来让编译器以当前路径为基准,自动创建包路径,这个-d .放在前面,放在后面都可以

这个-d 可以将文件编译到指定目录下。

假设我们在D盘下创建一个aa的目录,然后执行javac -d aa A.java,效果如下。

使用-classpath指定包的上级目录

使用-classpath(或者 -cp,简写,意思相同)指定.class的目录,使用相对路径,绝对路径都可以,这个目录直接通到mypack的上级即可。

我们可以通过-classpath指定.class在哪个根目录下,然后从这个目录拼接上包路径来构成完整路径。

javac的自由性

javac命令使用了可指定编译路径的可选项(option),可以指定不指定,不指定将在当前目录生成.class文件;可以指定为-d . ,将会在当前目录下创建包的全路径。可以指定位-d xx/xxx/xxxx 具体的目录,将会在具体目录下创建包的全路径。

这几种命令产生的.class文件本身完全相同。

等于并不限定.class文件产生的位置,因为javac只是创建。可能java文件本身可能就不放在目标位置。也可能创建的.class文件通过网路传输到别的地方再执行,所以决定了由使用者自己来决定放到什么地方。

三、引入其它自定义类

1、引入非自定义类

假设我们编辑如下的代码:

代码语言:javascript
复制
import java.nio.charset.Charset;



public class A {

    public static void main(String[] args) {

        System.out.println(Charset.defaultCharset());

    }

}

这个先放这边,我们举另外一个例子

2、引入自定义类

准备一个非默认的包,java目前版本不允许引入未命名包的类。让A引用B。

代码语言:javascript
复制
package pack;



public class B {

    private String name;



    public String getName() {

        return name;

    }



    public void setName(String name) {

        this.name = name;

    }



    public void showMyName(){

        System.out.println("my name is " + this.getName());

    }

}
代码语言:javascript
复制
package mypack;



import pack.B;



public class A {

    public static void main(String[] args) {

        B b = new B();

        b.setName("abc");

        b.showMyName();

    }

}

然后将A和B都放入D盘根目录,使用javac -d . 编译A.java

解决方案一:

我们可以用比较无脑的方式

甚至,可以javac -d . *.java,但是我认为.* 不妥,这样把不必要的类也编译了。

解决方案二:

首先,java程序会将被引用的类也打包的。

然后,如果类是相互引用并且不同包的,一定要按照包的路径放好,保持包定义和文件结构同步。

我们新建mypack和pack目录,将A.java丢到mypack目录下,将B.java丢到pack下。

如果B.java在其它路径:

上面的例子隐含了一种情况,A.java和B.java的包都在敲击命令目录的下级目录,包路径和隐含的classpath(也就是当前路径)构成了完整的路径。假设B在其它路径怎么办?

我们将B.java丢到E盘下的aa目录。这个时候只需要使用-cp指定B.java的上级路径即可。

我们打开E:\aa文件夹查看,会发现B.class并不在这里,因为B.java只是一个source路径而已。最终的.class文件仍然是相对当前敲击命令的位置安放。

如果B.class在其它路径。

我们将B.class也移动到E:\aa目录试试

好熟悉的报错。哈哈

这个时候需要使用-cp,但是看以第一条命令,使用-cp只指定了一个目录,会认为mypack.A也在这个路径下,要分开指定,使用”.”代表当前路径,使用分号隔开多个class路径。

总结一下:

1、如果有中文乱码,考虑是文件的编码方式和javac的编码方式不同。

javac的编码方式默认是ANSI的,也就是不同区域不同编码,中国区是GBK。可以使用Charset.defaultCharset()来查看。

将java文件编码和javac解码字符集统一。

a)修改java文件编码。

b)使用-encoding指定javac编译时候使用的编码。

2、对于有包的java程序,执行的时候要在包路径的上级路径,使用带有包路径的全限定名来执行。

包路径包含于实际文件路径,并且是实际文件路径的后面部分,当然特殊情况可以和文件路径相同。使用classpath指定包的上级目录,来执行不在当前路径下的java文件。

3、javac 有个可选参数 -d,如果不填会将.class文件放到当前目录,并且不带包名;如果填了会将.class文件放到指定目录,并且会创建包路径,可以用-d . 会在当前目录创建包路径。

4、javac和java都可以使用-cp/-classpath来操作执行路径下的文件。classpath可以有多个值,使用分号隔开,如果是.,表示当前目录。jvm会扫描classpath的所有目录,从中查找源文件和可执行文件。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/156701.html原文链接:https://javaforall.cn

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、不带包名的类如何编译
    • 1、没有中文的java文件。
      • 2、假设输出的是中文,会怎么样?
        • a)
        • b)
        • 原因分析:
      • 原因分析:
        • 解决办法
          • javac的自由性
          • 三、引入其它自定义类
            • 1、引入非自定义类
              • 2、引入自定义类
                • 如果B.java在其它路径:
                  • 如果B.class在其它路径。
                  • 总结一下:
                  领券
                  问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档