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

使用命令行编译、运行Java程序我们一般都是通过IDE(如Eclipse、IntellijIdea,MyEclipse、STS可以归到Eclipse里)来开发,调试java项目。在不借助IDE的情况下,如何编译、运行Java程序。使用javac命令,可以通过只敲击javac看到各种命令参数。必学参数-d-cp,这俩下面会讲到如果javac命令不能用,看一下环境变量是否没配对。我们从简单到复杂来看ja…

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

我们一般都是通过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文件。

准备代码

public class A {

    public static void main(String[] args) {

        System.out.println("abc");

    }

}

命令:

javac A.java

java A

输出结果

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

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

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

a)

public class A {

    public static void main(String[] args) {

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

    }

}

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

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

b)

public class A {

    public static void main(String[] args) {

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

    }

}

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

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

原因分析:

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

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

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

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

会发现输出GBK。

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

String s = "你好吗";

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

System.out.println(s1);

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

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的编码格式。

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

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

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

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

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

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

二、带包名的类如何编译

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

package mypack;



public class A {

    public static void main(String[] args) {

        System.out.println("abc");

    }

}

编译运行:

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

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

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

原因分析:

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

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 .放在前面,放在后面都可以

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

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

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

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

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

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

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

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

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

javac的自由性

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

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

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

三、引入其它自定义类

1、引入非自定义类

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

import java.nio.charset.Charset;



public class A {

    public static void main(String[] args) {

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

    }

}

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

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

2、引入自定义类

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

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());

    }

}

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

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

解决方案一:

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

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

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

解决方案二:

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

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

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

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

如果B.java在其它路径:

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

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

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

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

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

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

如果B.class在其它路径。

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

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

好熟悉的报错。哈哈

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

这个时候需要使用-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的所有目录,从中查找源文件和可执行文件。

最后吐槽一下CSDN这个,,,我从有道云拷贝过来,图片要一个一个贴,不知道是哪边的锅,累死我了

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

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

(0)
上一篇 2022年7月9日 上午6:36
下一篇 2022年7月9日 上午6:36


相关推荐

  • jQuery Lightbox图片放大预览

    简介:jQueryLightbox图片放大预览代码是一款可以在用户点击页面中的小图片时,将该图片的高清版本以Lightbox的方式放大显示在页面的中间,提高用户的体验度。效果展示 http

    2021年12月28日
    39
  • 调用wsdl接口 使用xml格式为参数

    调用wsdl接口 使用xml格式为参数

    2020年11月9日
    303
  • POE交换机通用吗_工业级交换机

    POE交换机通用吗_工业级交换机目前PoE交换机需要量大,那一定有些人疑惑PoE交换机能够替代一般工业交换机应用吗?下面为大伙儿介绍下,一起来瞧瞧吧。一般状况下是还可以的,具备IEEE802.3af或是IEEE802.3at协议书的POE交换机,输出电压时会有一个小电流量侦测。假如另一方不是带PoE的设备,那么就不容易供以往48V的工作电压。可是PoE交换机虽具有交换机的作用,作为一般工业交换机应用时,沒有最大限度充分发挥它的使用价值,不足经济发展节省,是自然资源的消耗。假如不用对联接设备给予直流电,能够同时采用一般工业.

    2022年10月5日
    6
  • MySQL基础 — 常用命令

    MySQL基础 — 常用命令一、连接MySQL格式:mysql-h主机地址-u用户名-p用户密码1、连接到本机上的MySQL。        首先在打开cmd窗口,输入mysql-uroot-p,然后空格进入MySQL模式,MySQL的提示符是:mysql>。mysql-uroot-p#如果刚安装好MySQL,root是没有密码的2、连接到远程主机上的MySQL。        假设远程主机的IP…

    2022年6月15日
    29
  • 根据前序遍历和中序遍历创建二叉树

    根据前序遍历和中序遍历创建二叉树Contents 前言四种遍历树的方法简介简介两种快速获得遍历结果的方法根据前序遍历和后续遍历创建树代码实现四种遍历树的方法的代码前言昨天参加了两场笔试 都考了这个题 第一场是根据 pre

    2025年10月22日
    5
  • kubectl 命令_numactl命令

    kubectl 命令_numactl命令在清华大学出版社出版的<<Kubernetes零基础快速入门>>一书上看到了总结的Kubectl命令,觉得很不错,比较全,包括有命令的含义以及常见的资源对象,所以分享一下。常

    2022年8月17日
    15

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号