java jpcp_javac -cp java-cp 看这篇就够了!

一、背景:

平时我们用javac 或者 java执行程序可能比较少,入门时候用到的也是简单的类,没有package或者没有依赖关系或者没有用其他.jar包的,所以执行起来没啥问题。在Algorithems Froth Edition中,经常要用命令行模式来Test 算法性能。

二、问题

在排序算法-初级排序算法这一章,执行java SortCompare Insertion Selection 1000 100就遇到问题:找不到外部.jar包或者找不到引用的类。网上答案大体表达清楚了意思,但是不够简洁,思路不够清晰。这里就用这个例子梳理一下。

先看下我的SortCompare包结构:└── com

└── chm

├── algorithms

│ ├── Example.java

│ ├── Insertion.java

│ ├── Selection.java

│ └── SortCompare.java

12345678

我们目的是,流畅的执行以下命令- javac SortCompare.java

- java SotrCompare Insertion Selection 1000 100

-

12345

介绍下类之间依赖关系,SortCompare是关键。

SortCompare.java的头部信息是这样的package com.chm.algorithms;

import edu.princeton.cs.algs4.StdOut;

import edu.princeton.cs.algs4.StdRandom;

import edu.princeton.cs.algs4.Stopwatch;

12345

这表明SortCompare这个类用到了外部jar包(算法提供的基础包algs4.jar);同时该类直接调用了Insertion.sort()、Selection.sort()方法,Insertion.sort()和Selection.sort()调用了Example中封装好的方法。

一言以蔽之,他们都在com.chm.algorithms这个package下(最核心部分)

最终结果:3288 0.9993866420331129 0.9998753497357498

For 1000 random Doubles

Insertion is 1.0 times faster than Selection

123

如果你对javac cp 或者 java -cp 理解不透,那么过程自然不顺利,这里我们先结论先行:

javac 编译.java文件,需要被编译的.java类是否有package,这个package表示该类所“认识”(默认)的当前目录,即java javac需要在package所在层级执行;(1) javac -cp 或者java -cp 都表明需要手动指定外部.jar包,cp也意味着会重新指定需要编译的类的目录,即包下面相互依赖的类所在的目录;用了cp编译器就不会默认在"当前路径"去找类了,而是都需要你自己去显式指定路径(2) 同一个包下的类依赖,只用顶层调用类,编译时,它所依赖的类自然会被编译。而不用像网上说的,先编译它所依赖的,再编译它。(不觉得累嘛?)(3)

知道这2点就够了,这2点不是凭空而来,执行 man javac 后的cp介绍很清楚,后文在回头细说。

没有package的类自然不用说,就在当前目录执行javac java即可;过程像小溪一样顺利;

我们这里的例子是比较复杂的:

我们应该在com这个级别执行javac 或者执行java,而不是跑到SortCompare.java所在的目录.这点最核心的,知道这点+结论中的(2)+(3),你的一切疑问都会烟消云散。

在这个目录执行命令,一会介绍为什么:/Users/myIdeaTest/my2020/202002/src/test/java

1

第一步:执行javac命令:Mac下:

javac -cp ~/Downloads/algs4.jar: com/chm/algorithms/SortCompare.java

Windows下:

javac -cp ~/Downloads/algs4.jar; com/chm/algorithms/SortCompare.java(未亲尝试)

注意:

1)algs4.jar包就是SortCompare.java用到的外部.jar包,放在了家目录下;

2)指定多个路径时,Mac和Window区别是:

1、多个.jar包或者目录Mac用:分开,Wind用;分开;

2、表达当前目录的方式,Mac用空格或者./;Winddow下大家知道这里不一样即可。

比如我这里的命令

javac -cp ~/Downloads/algs4.jar: com/chm/algorithms/SortCompare.java

或者

javac -cp ~/Downloads/algs4.jar:./ com/chm/algorithms/SortCompare.java

在Mac下都是可以的。网上CSDN部分不介绍清楚上下文,导致用;总是出问题。

12345678910111213141516171819202122

你会发现与SortCompare相关的类自动都被编译了,因为它们的包相同。需要提前先编译好Example.class Insertion.class Selection.class嘛?NO!

javac后的包结构:.

└── com

└── chm

├── algorithms

│ ├── Example.class

│ ├── Example.java

│ ├── Insertion.class

│ ├── Insertion.java

│ ├── Selection.class

│ ├── Selection.java

│ ├── SortCompare.class

│ └── SortCompare.java

12345678910111213

第二步:执行java命令Mac下:

java -cp ~/Downloads/algs4.jar: com/chm/algorithms/SortCompare Insertion Selection 1000 100

123

搞定!

现在详细解释下结论1)2)3)。如果你想知道我是怎么得出结论的,请耐心往下看:

1)这里的SortCompare有package,它用到的类(Example.java Insertion.java Selection.java)和它在一个包下,所以不用import;外部的.jar包自然需要import。执行javac编译它的时候,它所依赖的自然要能找到。javac怎么知道去哪里找呢?当然是当前目录。这个当前目录就是指的package。也就是SortCompare.java这个类,人家头部已经标明,我在这个包下面。如果我们跑到com/chm/algorithms这个目录去javac SortCompare.java,会提示找不到外部包,类似这样:[@MacBook-Air:algorithms (develop)]$ pwd

/Users/myIdeaTest/my2020/202002/src/test/java/com/chm/algorithms

[@deMacBook-Air:algorithms (develop)]$ ls

Example.java Insertion.java Selection.java SortCompare.java

[@deMacBook-Air:algorithms (develop)]$ javac SortCompare.java

SortCompare.java:3: 错误: 程序包edu.princeton.cs.algs4不存在

import edu.princeton.cs.algs4.StdOut;

^

SortCompare.java:4: 错误: 程序包edu.princeton.cs.algs4不存在

import edu.princeton.cs.algs4.StdRandom;

^

SortCompare.java:5: 错误: 程序包edu.princeton.cs.algs4不存在

import edu.princeton.cs.algs4.Stopwatch;

^

SortCompare.java:12: 错误: 找不到符号

Stopwatch timer = new Stopwatch();

^

符号: 类 Stopwatch

位置: 类 SortCompare

123456789101112131415161718192021

好,找不到外部包还不简单,加上就可以了javac -cp ~/Downloads/algs4.jar SortCompare.java

SortCompare.java:14: 错误: 找不到符号

Insertion.sort(a);

^

符号: 变量 Insertion

位置: 类 SortCompare

SortCompare.java:17: 错误: 找不到符号

Selection.sort(a);

^

符号: 变量 Selection

位置: 类 SortCompare

2 个错误

123456789101112

这里提示找不到Insertion 和Selection,他们不是和SortCompare在一个包下嘛?怎么会找不到?让我们再次回头大声朗读边结论(1),还是不大懂吧?没关系。我们在这个目录下执行javac的时候,编译器发现SortCompare.java所依赖的类在com.chm.algorithm包下面,所以就从SortCompare.java所在的目录往下寻找com.chm.algorithm.Insertion.java,这个目录往下哪里还有这个包呢?恍然大悟了吧?

因此,这就是SortCompare.java所"认识"的包的真实含义。所以我们需要到com包所在的这个层级执行,也就是在package的层级执行javac 或者java.

好的,那我们就回到package所在的目录去执行上面命令:[@deMacBook-Air:java (develop)]$ pwd

/Users/myIdeaTest/my2020/202002/src/test/java

[@deMacBook-Air:java (develop)]$ ls

com

[@deMacBook-Air:java (develop)]$ tree

.

└── com

└── chm

├── algorithms

│ ├── Example.java

│ ├── Insertion.java

│ ├── Selection.java

│ └── SortCompare.java

6 directories, 11 files

[@dzjdeMacBook-Air:java (develop)]$ javac ~/Downloads/algs4.jar com/chm/algorithms/SortCompare.java

javac: 无效的标记: /Users/Downloads/algs4.jar

用法: javac

-help 用于列出可能的选项 //这里没报错了

[@deMacBook-Air:java (develop)]$ tree

.

└── com

└── chm

├── algorithms

│ ├── Example.java

│ ├── Insertion.java

│ ├── Selection.java

│ └── SortCompare.java

123456789101112131415161718192021222324252627282930

没报错了,但是没编译成功!没有.class文件。为什么?

这就涉及到结论(2)了,请返回结论,大声朗读几遍结论(2)

使用-cp 意味着指定了java 或者javac去哪里找所编译的类依赖的.jar包,同时也意味着需要指定所编译的类所以来的类的路径。看一下这个-cp path or -classpath path

Specifies where to find user class files, and (optionally) annotation processors

and source files. This class path overrides the user class path in the CLASSPATH

environment variable. If neither CLASSPATH, -cp nor -classpath is specified, then

the user class path is the current directory. See Setting the Class Path.

1234567

这里的class files表明去哪里找.java文件;

这里的source files表明去哪里找.jar文件

所以

javac -cp ~/Downloads/algs4.jar SortCompare.java

是不够的,还需要显式的指定被编译的类所在的包路径。因为-cp 表明你要手动指定所有目录,而不是让编译命令自动用”当前“的路径。

好了。介绍结束了,过程有点啰嗦,结论很简洁。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值