资讯·论坛·笑话大全·QQ表情·设为首页
发新话题
打印

[java] 提高代码质量及字节码如何防止内存错误

提高代码质量及字节码如何防止内存错误

大多Java程序员知道他们的程序通常不会被编译为本机代码而是被编译为由java虚拟机(JVM)执行的字节码格式。然而,很少有java程序员曾经看过字节码因为他们的工具不鼓励他们去看。大多Java 调试工具不允许单步执行字节码,它们要么显示源代码行,要么什么也不显示。
% Z2 t8 s2 g8 y/ I: z我爱电脑技术社区--打造最好的电脑技术自学交流平台
) G, Q! v! J& Y/ d, |8 J2 Wwww.520diannao.com幸运的是JDK提供了javap,一个命令行工具,它使得查看字节码很容易。让我们看一个范例: www.520diannao.com: j6 x. d7 l! N5 p4 k/ |3 ?( A

+ n# v  w& {1 E& Cwww.520diannao.com
% q$ G5 P0 E9 g7 K0 V打造最好的电脑自学交流论坛public class ByteCodeDemo {
' l, q9 F3 ]+ ^& p1 j* c' ^8 P电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
( J' k6 v& w6 E9 C我爱电脑技术论坛public static void main(String[] args) {
& }& G7 l4 e6 S我爱电脑技术论坛
, p$ G2 I- }9 s# u. r, G5 H我爱电脑技术论坛System.out.println("Hello world"); www.520diannao.com5 p" s. L9 g/ N7 y$ W
我爱电脑技术论坛, ]  C6 e! l5 q; m4 w3 H. r
}
9 G& o0 @! K8 S5 [. o4 s. K$ ^& {2 y, j8 X. o( E! @
} www.520diannao.com0 p. B2 ^6 m% c2 G3 t
电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站$ l2 |' L, d' F( j

/ \* o# u& h: Pwww.520diannao.com在编译这个类后,你可以用十六进制编辑器打开.class文件然后参照虚拟机规范翻译字节码。幸运的是有更简单的方法。JDK包含一个命令行的反汇编器:javap,它可以转换字节码为一种可读的助记符形式,可以像下面这样通过传递'-c'参数给javap得到字节码列表:
5 c) \; F9 [- P) P6 r打造最好的电脑自学交流论坛我爱电脑技术论坛) ?6 A8 H) g$ s" j: W

2 k' ~) b; S  b* {/ U5 F+ |& O/ W电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站javap -c ByteCodeDemo www.520diannao.com0 J  D( H0 j; z* @- U1 V

$ E9 j/ P6 E! I) r, ^5 d我爱电脑技术论坛
- y7 u7 F( @" L' ^$ q* c; c电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站你应该会看到输出类似这样:
1 y( H& r! m- gwww.520diannao.com我爱电脑技术论坛6 r8 y# U* b. Q' S0 n8 o$ w" F

3 {: X6 l7 c# J% p- w# }( K! p打造最好的电脑自学交流论坛public class ByteCodeDemo extends java.lang.Object {
3 Y% t+ h( l" u. z9 Hwww.520diannao.com
0 x' z; L1 v1 `电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站public ByteCodeDemo();
4 G9 {% Y3 r6 t. i2 p" M: q% bwww.520diannao.com电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站. S  ^- B# l8 b& o4 t; t5 J
public static void main(java.lang.String[]); 打造最好的电脑自学交流论坛6 g0 z2 `$ @, ?

2 y% L, Z1 X3 ?& O" J( Z- s打造最好的电脑自学交流论坛} www.520diannao.com! r& ~8 c1 @% @  a5 S  `
www.520diannao.com) @, V& J6 l# h' [4 V2 N2 N2 x
Method ByteCodeDemo() 3 t, p& d4 i5 z" V! o
电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站6 S" F! {" Y; I. c0 _
0 aload_0
; c4 t* \) I4 {1 y我爱电脑技术论坛我爱电脑技术社区--打造最好的电脑技术自学交流平台9 X3 ~4 x) r! i5 R
1 invokespecial #1 我爱电脑技术社区--打造最好的电脑技术自学交流平台# p5 f" @/ R) \* b; a

1 @7 ^& s& T' i3 m) f, ~: f打造最好的电脑自学交流论坛4 return
# c! t' j  C1 K2 @4 {) w  k- H% I" G! \+ I8 t( W1 l
Method void main(java.lang.String[]) 我爱电脑技术论坛; K0 n: H5 d' o" Z5 b: N
电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站  U3 ^  s9 J6 I- A( H
0 getstatic #2
# {; p& N) \  v# G/ ]: x& n  y2 M9 ^) w) I打造最好的电脑自学交流论坛
* I+ E" Y2 Y: swww.520diannao.com3 ldc #3 % A$ }9 j% Z0 U

0 n6 t3 r# y; ^2 o8 g# b我爱电脑技术社区--打造最好的电脑技术自学交流平台5 invokevirtual #4 我爱电脑技术社区--打造最好的电脑技术自学交流平台( \+ v5 t  P5 Q
www.520diannao.com* W2 z2 I0 r: L. t  Z/ `
8 return
. T% M) t, u! G+ W( }打造最好的电脑自学交流论坛
9 L: J7 s; n/ x; }- b4 y' y7 I打造最好的电脑自学交流论坛我爱电脑技术社区--打造最好的电脑技术自学交流平台" M; Q8 S. o: @
仅仅从这个短小的列表你可以学到很多字节码的知识。从main方法的第一个指令开始: 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站2 J5 C" {& i8 `$ e; B
我爱电脑技术论坛6 ^) b0 l9 a& E2 R& F# Y5 N
我爱电脑技术论坛* r. k3 @* D. q6 R* y, o
0 getstatic #2
+ g9 i' N8 u$ K我爱电脑技术论坛
- W" s3 C: L, ~' c6 F6 N; E9 u; ?* rwww.520diannao.com
) x4 ~, @- f. X, k( t. D8 w开始的整数是方法中的指令的偏移值,因此第一个指令以0开始。紧随偏移量是指令的助记符(mnemonic)。在这个范例中,'getstatic' 指令将一个静态成员压入一个称为操作数堆栈的数据结构,后续的指令可以引用这个数据结构中的成员。getstatic 指令后是要压入的成员。在这个例子中,要压入的成员是"#2 " 。如果你直接检查字节码,你会看到成员信息没有直接嵌入指令而是像所有由java类使用的常量那样存储在一个共享池中。将成员信息存储在一个常量池中可以减小字节码指令的大小,因为指令只需要存储常量池中的一个索引而不是整个常量。在这个例子中,成员信息位于常量池中的#2处。常量池中的项目的顺序是和编译器相关的,因此在你的环境中看到的可能不是'#2' 。
8 m( Q3 g- x7 A* a) _- M+ T电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站. D. E( l4 [! U- h. Q4 b

# m7 [+ B! i& [9 _我爱电脑技术社区--打造最好的电脑技术自学交流平台分析完第一个指令后很容易猜到其它指令的意思。'ldc' (load constant) 指令将常量"Hello, World."压入操作数栈。'invokevirtual'指令调用println方法,它从操作数栈弹出它的两个参数。不要忘记一个像println这样的实例方法有两个参数:上面的字符串,加上隐含的'this'引用。
; H4 D6 ~2 m- ~$ K3 J我爱电脑技术社区--打造最好的电脑技术自学交流平台. x4 x& c3 X) P! z" ^* d
打造最好的电脑自学交流论坛/ {9 ~+ {$ U: S( x- e5 Y
字节码如何预防内存错误 我爱电脑技术社区--打造最好的电脑技术自学交流平台# n8 @  F" Q9 O2 d7 G

7 @1 B1 E1 N7 o4 o: {* z7 ]9 I我爱电脑技术社区--打造最好的电脑技术自学交流平台, a- I3 _6 Z6 b! J; {2 d* N
Java语言经常被吹捧为开发互联网软件的"安全的"语言。表面上和c++如此相似的代码如何体现安全呢?它引入的一个重要的安全概念是防止内存相关的错误。计算机罪犯利用内存错误在其它情况下安全的程序中插入自己的恶意的代码。Java字节码是第一个可以预防这种攻击的,像下面的范例展示的: 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站. _! a& U  ]  W- S- h5 ~1 k
电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站: F+ a$ C2 o; t, r( F7 \
4 M* b  U! x8 o
public float add(float f, int n) { 1 t6 t2 z$ @- t6 b7 w, R7 w
www.520diannao.com& I% U4 \# s; V" p% |& U
return f + n; www.520diannao.com5 Z! q& F0 Y; I# D3 K
电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站9 T5 u; }' m! |1 X0 J! |, h
}
( ]2 B; T. p) m5 x& G我爱电脑技术社区--打造最好的电脑技术自学交流平台打造最好的电脑自学交流论坛" Q6 p1 M5 J; U9 E0 `3 h
www.520diannao.com5 w# E+ z5 D5 J7 t
如果你将这个方法加入上面的范例中,重新编译它,然后运行javap,你将看到的字节码类似这个: / ~7 u( e' k2 }1 g. J- }

" I6 |% B. G. r2 w. p0 W& awww.520diannao.com电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站+ t4 d4 z3 ~- s
Method float add(float, int)
4 i) `. i3 S0 x. W. S+ S我爱电脑技术社区--打造最好的电脑技术自学交流平台
/ L% |% `1 Y7 t& o/ v) [) ~0 fload_1 打造最好的电脑自学交流论坛6 l+ q6 o& z/ h4 G1 C9 B
电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站4 I# E3 H& \# M' S; A' _  K
1 iload_2 www.520diannao.com% c% u$ n, H; `* ?
我爱电脑技术社区--打造最好的电脑技术自学交流平台( q" P" p9 j9 D+ V' [
2 i2f
; Y/ a! b+ x; u% ?' p电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
- M4 X; T. q" `* K1 |. L3 fadd
. C2 t% |# F* t2 Q. u& v我爱电脑技术社区--打造最好的电脑技术自学交流平台我爱电脑技术论坛1 j; x; Z5 e9 N8 C" |" w
4 freturn 我爱电脑技术社区--打造最好的电脑技术自学交流平台2 w* {, |! e: o& ?3 K, O% O

( d8 g4 m2 R: K电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站) Z  d0 t! z" N1 K: I
在方法的开始,虚拟机将方法的参数放入一个称为局部变量表的数据结构中。将像名字暗示的那样,局部变量表也包含了你声明的任何局部变量。在这个例子中,方法以三个局部变量表的项开始,这些都是add方法的参数,位置0保存this引用,而位置1和2分别保存float和int参数。
+ k- m' ~, C, s, `0 s1 v6 m打造最好的电脑自学交流论坛
# |0 ^3 w: Z% X# G! D电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站www.520diannao.com" r# @/ E& B6 G7 q
为了实际的操作这些变量,它们必须被加载(压入)到操作数栈。第一个指令fload_1将位置1处的float压入操作数栈,第二个指令iload_2将位置2处的int压入操作数栈。这些指令的一个引起注意的事情是指令中的'i'和'f'前缀,这说明Java字节码指令是强类型的。如果参数的类型和字节码的类型不匹配,VM将该字节码作为不安全的而加以拒绝。更好的是,字节码被设计为只需在类被加载时执行一次这样的类型安全检查。
5 G3 _: i+ ^3 Fwww.520diannao.com
9 A3 @% W& n* x8 m电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站打造最好的电脑自学交流论坛( `# u" h/ T6 u2 F* a
这个类型安全是如何加强安全的?如果一个攻击者能够欺骗虚拟机将一个int作为一个float或者相反,它就可以很容易的以一个预期的的方法破坏计算。如果这些计算涉及银行结余,那么隐含的安全性是很明显的。更危险的是欺骗VM将一个int作为一个Object引用。在大多情况下,这将导致VM崩溃,但是攻击者只需要找到一个漏洞。不要忘记攻击者不会手工搜索这个漏洞--写出一个程序产生数以亿计的错误字节码的排列是相当容易的,这些排列试图找到危害VM的幸运的那个。

TOP

字节码的另一个内存安全防护是数组操作。'aastore' 和 'aaload' 字节码操作Java数组并且它们总是检查数组边界。如果调用程序越过了数组尾,这些字节码将抛出一个ArrayIndexOutOfBoundsException。也许所有最重要的检查都使用分支指令,例如,以if开始的字节码。在字节码中,分支指令只能转移到同一方法中的其它指令。在方法外可以传递的唯一控制是使它返回:抛出一个异常或者执行一个'invoke'指令。这不仅关闭了很多攻击,同时也防止由于摇荡引用(dangling reference)或者堆栈冲突而引发的令人厌恶的错误。如果你曾经使用系统调试器打开你的程序并定位到代码中的一个随机的位置,那么你会很熟悉这些错误。 我爱电脑技术社区--打造最好的电脑技术自学交流平台* @, p$ ^7 q( N' B7 u! h$ y# \5 N
1 Z, x* B& J- j! L

( w4 S. `8 H/ r! O& \# i: ]$ _所有这些检查中需要记住的重要的一点是它们是由虚拟机在字节码级进行的而不是仅仅由编译器在源代码级进行的。一个例如c++这样的语言的编译器可能在编译时预防上面讨论的某些内存错误,但是这些保护只是在源代码级应用。操作系统将很乐意加载执行任何机器码,无论这些代码是由精细的c++编译器产生的还是心怀恶意的攻击者产生的。简单的讲,C++仅仅是在源代码级上面向对象而Java的面向对象的特性扩展到编译过的代码级。
( @' _+ u5 c- D# \  ~www.520diannao.com
" p; u# Z- i" D8 O3 T我爱电脑技术社区--打造最好的电脑技术自学交流平台我爱电脑技术社区--打造最好的电脑技术自学交流平台# B& w' ?; d8 j$ f: I/ B& \8 d
分析字节码提升代码质量
+ I( h- h; V$ X6 `6 O$ B& \* C电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
( \7 f7 p$ {( ^+ H8 I我爱电脑技术社区--打造最好的电脑技术自学交流平台
* M1 e8 `4 O9 ^  u) d我爱电脑技术论坛Java字节码的内存和安全保护无论我们是否注意都是存在地,那么我们为什么还费心查看字节码呢?在很多情况下,知道编译器如何将你的代码转换为字节码可以帮助你写出更高效的代码,而且在某些情况下可以防止不易发觉的错误。考虑下面的例子:
7 z3 p9 O! @; c9 n8 ]5 v  {打造最好的电脑自学交流论坛
& d; ]& M7 d, `( G( y8 p我爱电脑技术社区--打造最好的电脑技术自学交流平台
! s6 N" s$ f) [) p! _; {7 V. Y# }我爱电脑技术论坛//返回 str1+str2 的串连 我爱电脑技术社区--打造最好的电脑技术自学交流平台6 S$ e9 t" u3 J) l( e2 e1 L
我爱电脑技术社区--打造最好的电脑技术自学交流平台; @3 f9 |" U9 ~2 z/ A' S
String concat(String str1, String str2) { 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站5 g$ L7 t: H; ~) f* U* f
" k+ B* w% Z1 z7 `( l7 Y& O6 a
return str1 + str2; 打造最好的电脑自学交流论坛% K) n4 z. w' {2 x$ S( f& P

+ c& @; B6 K. {4 [# A8 j2 swww.520diannao.com} 6 W9 S+ p) |+ I& P2 D% y' m5 X6 e$ o

% V7 O8 T0 L8 }; }
- N- l9 d9 Z3 }, t4 K8 d, j" Jwww.520diannao.com//将 str2 附加到 str1
; q3 J. b7 C/ [0 a0 lwww.520diannao.com打造最好的电脑自学交流论坛% L7 H: e- l4 w: w! i  d( [
void concat(StringBuffer str1, String str2) { 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站$ \  E0 I$ w: x$ \9 h
打造最好的电脑自学交流论坛: a3 n7 l: O, e. w
str1.append(str2);
6 n7 R* V" k; y" [+ A0 _( t# Swww.520diannao.com
4 X9 D# z1 B" q6 |} 打造最好的电脑自学交流论坛% y9 c) P1 \8 ^0 W. N* q9 K! R
+ a: X# K, \8 r3 E
我爱电脑技术社区--打造最好的电脑技术自学交流平台6 {/ V6 S! ^2 J/ y6 F  x
猜猜每个方法需要多少个方法调用。现在编译这些方法并且运行javap,你会得到类似下面的输出: 我爱电脑技术社区--打造最好的电脑技术自学交流平台7 P% F; o. V) P: }, E
我爱电脑技术社区--打造最好的电脑技术自学交流平台6 B4 K7 g& y5 E. h) [5 a( Z2 v

+ e! d' h+ _* o* C; x' a打造最好的电脑自学交流论坛Method java.lang.String concat1(java.lang.String, java.lang.String)
/ N1 `' z4 D- N% w; L7 b电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
7 D2 I* k9 R/ M3 F: p* `www.520diannao.com0 new #5 www.520diannao.com2 P6 K% C" p  v, N+ J$ D7 U
0 U" ?" ?5 w! n/ G: E" J
3 dup
  _: N" f: [7 _打造最好的电脑自学交流论坛
/ m$ x* B0 U: [/ }1 V" h- R7 U& h# q我爱电脑技术论坛4 invokespecial #6
. `8 z, I' l1 T6 E我爱电脑技术论坛
  c8 J6 y. g7 t/ {- q电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站7 aload_1
, m- E* n6 h4 R% W* w4 q我爱电脑技术社区--打造最好的电脑技术自学交流平台
+ d% f$ R2 @# ^- P) E  n我爱电脑技术论坛8 invokevirtual #7 www.520diannao.com" N6 ?- k  w. J, p" _8 \9 F
打造最好的电脑自学交流论坛" u# |# A( d9 [# B" K% S1 B8 I
11 aload_2
; i6 K. D/ v% L我爱电脑技术论坛, f5 N6 j! E4 j, v3 g% [# `+ L
12 invokevirtual #7
( E2 H! d; E- w5 l8 K电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
* ]9 U9 w7 G% q3 ~3 a8 N% D我爱电脑技术论坛15 invokevirtual #8
8 ?5 G9 l4 k  _6 n: d0 c) z5 \+ w. _打造最好的电脑自学交流论坛
, \# S& g. k: w: j0 K5 H' y; U/ F电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站18 areturn 我爱电脑技术论坛: M: ~& Y; I& v0 D% }+ g

0 k+ ]1 V  `) r7 ^' U, j% y# M, |0 _我爱电脑技术社区--打造最好的电脑技术自学交流平台Method void concat2(java.lang.StringBuffer, java.lang.String)
8 F+ S/ m/ w9 z$ E6 z9 l0 ]
% m7 }( v8 b- b% c" X我爱电脑技术论坛0 aload_1
  j! t5 m2 T+ G  C. ?0 n我爱电脑技术论坛
; V- P( `' f; t* X( Iwww.520diannao.com1 aload_2
2 ^/ W( X# e8 y. g  t5 ?我爱电脑技术论坛
) m/ C, a# n) [6 ~' A电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站2 invokevirtual #7
- k! o4 T; _! ?9 E我爱电脑技术论坛. a$ u3 k; D- o! N. F2 F. e
5 pop
! i5 d: G& Q& O$ {- p6 C/ Awww.520diannao.com
1 C& l7 x" f5 m8 p2 l  V, X, e6 J电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站6 return
4 A% ?/ A  E  W! |1 X$ R打造最好的电脑自学交流论坛
- s! p5 r- `; b3 T1 q( \  Q我爱电脑技术社区--打造最好的电脑技术自学交流平台) q) B# a7 r/ z4 R9 g3 b
concat1方法执行了5个方法调用s: new, invokespecial和三个invokevirtuals,这比concat2方法执行了更多的工作,后者只执行了一个invokevirtual调用。大多Java程序员已经得到过警告,因为String是不可变的,而使用StringBuffer进行字符串连接效率更高。使用javap分析这个使得这点变得很生动。如果你不能肯定两个语言构造在性能上是否相等,你应该使用javap分析字节码。然而,对just-in-time (JIT)编译器要小心,因为JIT编译器将字节码重新编译为本机代码而能执行一些javap不能揭示的附加优化。除非你有你的虚拟机的源代码,否则你应该补充你的字节码的基准性能分析。 打造最好的电脑自学交流论坛2 B+ Y! _0 t3 l4 t  ?
我爱电脑技术社区--打造最好的电脑技术自学交流平台  s6 r, o) k* ?2 Z
, f7 e/ i+ I9 Y5 P0 ^
最后的一个范例展示了检查字节码如何帮助防止程序中的错误。像下面那样创建两个类,确保它们在独立的文件中。 我爱电脑技术社区--打造最好的电脑技术自学交流平台( U6 |% p7 g) y+ ?- Z6 P- \
电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站" Z5 K& C' |: E

( E+ @  M! k' e, L' l打造最好的电脑自学交流论坛public class ChangeALot {
. J) S1 c& I$ Q* a1 o0 lwww.520diannao.com我爱电脑技术社区--打造最好的电脑技术自学交流平台( P7 ^; v2 o6 _- w  l& S, V3 w
public static final boolean debug=false; 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站6 h' K! Q! O  y$ A( g% k
我爱电脑技术社区--打造最好的电脑技术自学交流平台4 q, j! F) f, n' A+ i1 I
public static boolean log=false;
8 S  W% c" l. t+ {# t; g* |我爱电脑技术社区--打造最好的电脑技术自学交流平台电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站$ R0 W$ ~, \! s+ {6 c* h
} 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站4 C4 P$ u' r/ ~' W( @$ [

7 a; [7 x3 v7 D1 k9 E. c我爱电脑技术论坛5 W4 G1 O* R: T( z7 K$ Z* X( q
public class EternallyConstant { 打造最好的电脑自学交流论坛8 k' G1 C: j7 p8 g% [5 ?& e

- U2 y" Z; ?& }; I! ~) E& E( N电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站public static void main(String [] args) { 我爱电脑技术社区--打造最好的电脑技术自学交流平台0 x* g/ c+ O* A% v
打造最好的电脑自学交流论坛( F3 B$ S/ a5 ~/ s+ t/ a+ s4 l4 C
System.out.println("EternallyConstant beginning execution"); 我爱电脑技术论坛, W1 |* C# a5 c# g1 Z% I/ j

. ~# K# g+ D, ~9 g+ e  `2 k8 t我爱电脑技术社区--打造最好的电脑技术自学交流平台if (ChangeALot.debug)
4 H) G7 W2 ^: w: X1 c5 |' a5 p+ W我爱电脑技术论坛
% g' z( f- O7 W" g& j% i/ g" u4 U6 g打造最好的电脑自学交流论坛System.out.println("Debug mode is on");
/ k$ m) i6 G( `0 ~( e5 t0 b我爱电脑技术论坛我爱电脑技术社区--打造最好的电脑技术自学交流平台; ?/ X2 L* `4 `0 b, o
if (ChangeALot.log) 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站+ G9 y) m: t9 M) Z0 _- O
$ x: m3 T4 m  z6 q, N
System.out.println("Logging mode is on"); www.520diannao.com% C: @5 P9 ^+ t! w2 `

6 G# _% z& m$ g} 电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站+ G% u$ q! x" S2 C8 Y. ^3 S; V
我爱电脑技术社区--打造最好的电脑技术自学交流平台% p5 b" h3 l, ]* B* Y: ^5 \
} 我爱电脑技术社区--打造最好的电脑技术自学交流平台" O# Q  H1 K" z2 w1 ~# b! e. t

; ~, Q2 u- ], x( o+ W" b; J我爱电脑技术论坛电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站& h( w2 C' Q: G: p* O$ w" w! J, ?, D
如果你运行EternallyConstant,你会得到信息:
6 {2 y+ ^' Z* x# Rwww.520diannao.com# `3 b6 x7 c: m8 @0 l  H* N% i9 V

8 _& [8 A( N) ~7 Y. j& k$ _打造最好的电脑自学交流论坛EternallyConstant beginning execution.
! l" q& L" G- B7 b# fwww.520diannao.com
( \% ]# z1 n! P1 B  z! A9 Mwww.520diannao.com打造最好的电脑自学交流论坛  x5 U3 k. V( k2 g
现在试着编辑ChangeALot,修改debug和log变量的值为true(两个都为true)。只重新编译ChangeALot。再次运行EternallyConstant,你将看到下面的输出: 我爱电脑技术论坛7 ?+ {/ @  s$ o. D
我爱电脑技术社区--打造最好的电脑技术自学交流平台7 v5 _! w) ?! q& a2 g( R- v
6 N. \) D" `' W, C! I+ }5 n
EternallyConstant beginning execution www.520diannao.com; D  w& R- S- r  f  v9 B/ H

& t% o# `- M% J7 c我爱电脑技术论坛Logging mode is on 我爱电脑技术社区--打造最好的电脑技术自学交流平台  s# W9 u- L/ F8 o- M
我爱电脑技术社区--打造最好的电脑技术自学交流平台, G+ z, \6 A6 r4 c  i+ X
我爱电脑技术社区--打造最好的电脑技术自学交流平台" j2 P" Y2 \0 R" |) m1 D" S) y
debug变量怎么了?即使你将debug设置为true,信息"Debug mode is on"并没有出现。答案在字节码中。对 EternallyConstant运行javap你会看到:
3 j9 d6 w  C9 `. u. m: R* g  s: _我爱电脑技术社区--打造最好的电脑技术自学交流平台
% [; H* J  ^5 {: z+ |" n& a# j电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站
) P9 B& w9 i% `* U4 C. mMethod void main(java.lang.String[])
, {& A$ }1 M0 swww.520diannao.com
& t- X4 D% |3 i. y% [; F- rwww.520diannao.com0 getstatic #2 我爱电脑技术社区--打造最好的电脑技术自学交流平台: t% K$ K! t  E0 L& O9 @
我爱电脑技术社区--打造最好的电脑技术自学交流平台  o; y6 W1 d5 g4 V2 U, Z% x
3 ldc #3
5 c; x7 o1 y% V+ Z( twww.520diannao.com
; x( ]" _# X4 P) i5 ?我爱电脑技术社区--打造最好的电脑技术自学交流平台5 invokevirtual #4
. k7 L) W; |( t3 p# w7 A我爱电脑技术社区--打造最好的电脑技术自学交流平台5 G7 G( o/ S: n9 [/ m* u$ S* A& @& h
8 getstatic #5
- l- i& R" Q9 @: s6 J! `: g; i/ @0 |我爱电脑技术论坛
' \8 q) Z7 t6 P# W4 S我爱电脑技术论坛11 ifeq 22 www.520diannao.com4 J2 c! U$ ~5 [

+ `2 f( Z9 d" c2 E$ n. ]" kwww.520diannao.com14 getstatic #2 打造最好的电脑自学交流论坛; d1 _) j+ ~+ o  O' s3 B' e

; v1 R1 O: h* o' y0 u: \我爱电脑技术论坛17 ldc #6 , h3 w6 m7 h5 e8 x  q
打造最好的电脑自学交流论坛5 s* j5 F# m9 n/ J# H
19 invokevirtual #4
; @) B& J9 J% w. x$ Gwww.520diannao.com打造最好的电脑自学交流论坛& }$ A8 p# s1 F& Z0 u! I$ f
22 return 打造最好的电脑自学交流论坛- `0 N1 i" m7 b4 R) T
www.520diannao.com" j& l3 N# ~) S" U7 b9 e+ ?
我爱电脑技术社区--打造最好的电脑技术自学交流平台  K8 d( s7 S3 ]4 N- l$ M5 `
惊奇吧!在log成员上有一个'ifeq'检查,而代码根本没有检查debug成员。因为debug成员被标记为final类型,编译器知道debug成员在运行时永远不会改变,因此它通过移除'if'声明进行优化。这确实是一个非常有用的优化,因为它允许你在程序中嵌入调试代码而在将它设置为false时不用付出运行时的代价。不幸的是这个优化能够导致主要的编译时混乱。如果你改变一个final成员,你必须记住重新编译任何可能引用该成员的类。这是因为这个'reference'可能已经经过优化了。Java开发环境不能总是发现这个微妙的相关性,一些能导致非常奇怪的错误。因此,古老的C++格言对于java环境仍然有效:"When in doubt, rebuild all."(有疑问,重新编译所有的代码)。
0 G' I8 Z/ A$ w5 l" x; r电脑,技术,IT,学习,交流,网络安全,QQ,硬件,软件,编程,教程,建站我爱电脑技术社区--打造最好的电脑技术自学交流平台1 b1 N( o% U) r8 t7 j: }3 M) n/ ?

) R2 j. Z) A4 t2 `1 m9 m) S我爱电脑技术论坛知道一些字节码的知识对于使用java编程的程序员都是有价值的。javap工具使得查看字节码很容易。有时候,使用javap检查你的代码以期提高性能和捕获特殊的不易察觉的错误时是没有用的。

TOP

发新话题