Skip to content

Commit 739fe6d

Browse files
committedSep 14, 2019
Merge branch 'smj' of https://github.com/AutumnLight/stackoverflow-java-top-qa into AutumnLight-smj
# Conflicts: # contents/how-can-i-generate-an-md5-hash.md # contents/why-is-printing-b-dramatically-slower-than-printing.md
1 parent ba475c8 commit 739fe6d

2 files changed

+94
-109
lines changed
 
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
##如何在classpath中设置多个jar包?
2+
3+
###问题
4+
是否有一个方法可以在classpath选项中包含一个文件夹(目录)下的所有jar包?
5+
我尝试运行`java -classpath lib/*.jar:. my.package.Program`,但是无法找到相应的类文件,可是这些类文件确实存在于命令中的jar包中。我是否需要在classpath中分别指定所有的jar包?
6+
7+
###回答
8+
在使用Java6或者以上版本时,classpath选项可以支持通配符(wildcards)。使用方法如下:
9+
* 使用直接引用(`"`)
10+
* 使用 `*` 而不是 `*.jar`
11+
12+
**Windows平台**
13+
14+
`java -cp "Test.jar;lib/*" my.package.MainClass`
15+
16+
**Unix平台**
17+
18+
`java -cp "Test.jar:lib/*" my.package.MainClass`
19+
20+
Unix平台与Windows平台基本一样,除了使用冒号 `:` 替代分号 `;` 之外。如果你不能使用通配符,也可以使用`bash`完成上述功能,命令如下(其中lib是一个包含所有jar包的目录):
21+
`java -cp $(echo lib/*.jar | tr ' ' ':')`
22+
23+
注意事项:classpath选项与-jar选项并不能兼容。可以查看:[Execute jar file with multiple classpath libraries from command prompt](http://stackoverflow.com/questions/13018100/execute-jar-file-with-multiple-classpath-libraries-from-command-prompt)
24+
25+
**对于通配符的理解**
26+
来自[Classpath](http://java.sun.com/javase/6/docs/technotes/tools/windows/classpath.html)文档:
27+
28+
类路径可以包含一个基本文件名通配符`*`,其等价于指定一个特定目录下的所有以.jar或.JAR为后缀的文件的列表。例如,一个类路径的条目为`foo/*`,其指定了foo目录下的所有jar文件。一个仅仅包含`*`的classpath条目(entry)指定了当前目录下的所有jar包。
29+
30+
一个包含了`*`的classpath条目不能匹配特定目录下的class文件。为了既能匹配foo目录下的类文件,也能匹配jar包,可以使用`foo;foo/*``foo/*;foo`。对于前者而言,类文件和资源选择的顺序先是foo目录下的类文件和资源,之后才是jar包;而后者则正好相反。
31+
32+
通配符并不能递归地搜索子目录下的jar包。例如,`foo/*`只找`foo`目录下的jar包,而不会寻找`foo/bar``foo/baz`等目录下的jar包。
33+
34+
一个目录中的jar包枚举顺序并不固定,这不仅和平台有关,甚至可能会在同一个机器上因为时间不同而表现不同。一个结构良好(well-constructed)的应用不应该依赖于某个特定的顺序。如果特定顺序是不可避免的时候,就需要在classpath中显示枚举所有的jar包了。
35+
36+
在类加载进程中,通配符的扩展在早期完成,优先于程序main函数的调用,而不是在其后。每个包含通配符的类路径都被替换为所在目录下所有jar包的序列。例如,如果目录`foo`包含`a.jar``b.jar`以及`c.jar`,因此类路径`foo/*`被扩展为`foo/a.jar;foo/b.jar;foo/c.jar`,并且以上字符串被作为系统属性`java.class.path`的值。
37+
38+
环境变量`CLASSPATH`与命令行选项-classpath或者-cp并没有什么不同。也就是说,通配符既可以应用于命令行`-classpath/-cp`选项中,也可以应用于环境变量`CLASSPATH`中。
Original file line numberDiff line numberDiff line change
@@ -1,114 +1,61 @@
1-
# 为什么打印“B”会明显的比打印“#”慢
2-
3-
## 问题
4-
5-
我生成了两个`1000`x`1000`的矩阵:
6-
7-
第一个矩阵:`O``#`
8-
第二个矩阵:`O``B`
9-
10-
使用如下的代码,生成第一个矩阵需要8.52秒:
11-
12-
Random r = new Random();
13-
for (int i = 0; i < 1000; i++) {
14-
for (int j = 0; j < 1000; j++) {
15-
if(r.nextInt(4) == 0) {
16-
System.out.print("O");
17-
} else {
18-
System.out.print("#");
19-
}
20-
}
21-
22-
System.out.println("");
23-
}
24-
25-
26-
而使用这段代码,生成第二个矩阵花费了259.152秒:
27-
28-
Random r = new Random();
29-
for (int i = 0; i < 1000; i++) {
30-
for (int j = 0; j < 1000; j++) {
31-
if(r.nextInt(4) == 0) {
32-
System.out.print("O");
33-
} else {
34-
System.out.print("B"); //only line changed
35-
}
1+
##为什么打印B要比打印#慢很多?
2+
3+
###问题
4+
我生成了两个大小为 1000 * 1000 的矩阵
5+
第一个矩阵:O和#
6+
第二个矩阵:O和B
7+
使用以下代码,第一个矩阵仅用时8.25s就完成了:
8+
```java
9+
Random r = new Random();
10+
for (int i = 0; i < 1000; i++) {
11+
for (int j = 0; j < 1000; j++) {
12+
if(r.nextInt(4) == 0) {
13+
System.out.print("O");
14+
} else {
15+
System.out.print("#");
3616
}
37-
38-
System.out.println("");
3917
}
4018

41-
如此大的运行时间差异的背后究竟是什么原因呢?
42-
43-
---
44-
45-
正如评论中所建议的,只打印`System.out.print("#");`用时7.8871秒,而`System.out.print("B");`则给出`still printing...`
46-
47-
另外有人指出这段代码对他们来说是正常的, 我使用了[Ideone.com](http://ideone.com),这两段代码的执行速度是相同的。
48-
49-
测试条件:
50-
51-
- 我在Netbeans 7.2中运行测试,由控制台显示输出
52-
- 我使用了`System.nanoTime()`来计算时间
53-
54-
## 解答一
55-
56-
*纯粹的推测*是因为你使用的终端尝试使用[单词换行][1]而不是字符换行,并且它认为`B`是一个单词而`#`却不是。所以当它到达行尾并且寻找一个换行的地方的时候,如果是`#`就可以马上换行;而如果是`B`,它则需要花更长时间搜索,因为可能会有更多的内容才能换行(在某些终端会非常费时,比如说它会先输出退格再输出空格去覆盖被换行的那部分字符)。
57-
58-
但这都只是纯粹的推测。
59-
60-
61-
[1]: http://en.wikipedia.org/wiki/Word_wrap
62-
63-
64-
##解答二
65-
66-
我用Eclipse和Netbeans 8.0.2做了测试,他们的Java版本都是1.8;我用了`System.nanoTime()`来计时。
67-
68-
##Eclipse:
69-
70-
我得到了**用时相同的结果** - 大约**1.564秒**
71-
72-
##Netbeans:
73-
74-
* 使用"#": **1.536秒**
75-
* 使用"B": **44.164秒**
76-
77-
所以看起来像是Netbeans输出到控制台的性能问题。
78-
79-
在做了更多研究以后我发现问题所在是Netbeans [换行][1] 的最大缓存(这并不限于`System.out.println`命令),参见以下代码:
80-
81-
for (int i = 0; i < 1000; i++) {
82-
long t1 = System.nanoTime();
83-
System.out.print("BBB......BBB"); \\<-contain 1000 "B"
84-
long t2 = System.nanoTime();
85-
System.out.println(t2-t1);
86-
System.out.println("");
19+
System.out.println("");
20+
}
21+
````
22+
而使用相同的代码时,第二个矩阵却执行了259.152s
23+
````java
24+
Random r = new Random();
25+
for (int i = 0; i < 1000; i++) {
26+
for (int j = 0; j < 1000; j++) {
27+
if(r.nextInt(4) == 0) {
28+
System.out.print("O");
29+
} else {
30+
System.out.print("B");
31+
}
8732
}
8833

89-
每一个循环所花费的时间都不到1毫秒,除了 **每第五个循环**会花掉大约225毫秒。像这样(单位是毫秒):
90-
91-
BBB...31744
92-
BBB...31744
93-
BBB...31744
94-
BBB...31744
95-
BBB...226365807
96-
BBB...31744
97-
BBB...31744
98-
BBB...31744
99-
BBB...31744
100-
BBB...226365807
101-
.
102-
.
103-
.
104-
105-
以此类推。
106-
107-
##总结:
108-
109-
1. 使用Eclipse打印“B”完全没有问题
110-
1. Netbeans有换行的问题但是可以被解决(因为在Eclipse并没有这个问题)(而不用在B后面添加空格(“B ”))。
111-
112-
[1]: http://en.wikipedia.org/wiki/Line_wrap_and_word_wrap
113-
114-
stackoverflow原址:http://stackoverflow.com/questions/21947452/why-is-printing-b-dramatically-slower-than-printing
34+
System.out.println("");
35+
}
36+
````
37+
为什么两者的执行时间会有如此巨大的差距?
38+
- - -
39+
评论中一些人建议仅执行`System.out.print("#");`以及`System.out.print("B");`前者用时7.8871s,而后者仍然在打印(即花费时间过多--译者注)
40+
另外有些人指出在他们那里工作正常(即两者花费时间差不错--译者注),我在[Ideone.com](http://ideone.com/)环境中运行两段代码,执行时间也差不多。
41+
42+
测试条件:
43+
- Netbeans 7.2,结果输出在IDE的控制台
44+
- 使用`System.nanoTime()`度量时间
45+
46+
###回答
47+
纯推测:你正在使用的终端试图进行[“自动换行”(word-wrapping)](http://en.wikipedia.org/wiki/Word_wrap),而不是“字符换行”(character-wrapping),并且将'B'视为一个单词字符(word character),而'#'视为一个非单词字符(non-word character)。因此当输出到达行尾时,控制台搜索一个位置用来换行,当遇到'#'时可以立即执行换行;然而遇到'B'时,控制台必须继续搜索,并且可能有更多的字符需要换行(这个操作在一些控制台上可能花销很大,例如,输出退格,然后输出空白字符来覆盖那些需要被换行的字符)。
48+
但是,这仅仅是理论推测。
49+
50+
**译者注:**
51+
对于"word-wrapping""character-wrapping",我的理解是,它们的区别在于换行时是否在一个单词内部分割,例如在 charac-ter 中的-处换行,"word-wrapping"会将character全部移到下一行,而"character-wrapping"则将ter移到下一行,而charac依旧在原来的位置。
52+
**word-wrapping**
53+
```
54+
*******
55+
character
56+
```
57+
**character-wrapping**
58+
```
59+
*******charac
60+
ter
61+
```

0 commit comments

Comments
 (0)
Please sign in to comment.