Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 739fe6d

Browse files
committed
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

File tree

2 files changed

+94
-109
lines changed

2 files changed

+94
-109
lines changed
Lines changed: 38 additions & 0 deletions
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`中。
Lines changed: 56 additions & 109 deletions
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)

AltStyle によって変換されたページ (->オリジナル) /