javac 概述
javac 是jdk bin目录下的一个脚本。 用于编译 java程序的源代码,但是 其实现的本质 是基于 jdk 标准类库中的 javac类库实现,所以java的编译器实质上是一个 java程序。
javac脚本 仅是一个便于启动以及传递参数的脚本文件,其内部依旧运行了 java程序。
javac 又被称作前端编译器,仅负责 源代码 与 字节码之间的转换,而在jvm内部 还存在 一个后置编译器,根据热点探测技术 可以将最有价值的 字节码转换为 机器码执行从而提升java程序的运行效率。
javac 的意义就在于 将源码编译为字节码,同时 做一些 词法,语法,语义上的检查,最后生成可供jvm运行的字节码文件。
javac 源码
在 lib 中的 tools jar 包中 sun.tools.javac; 包下管理者 java前端编译器 的class文件。 Main 类 中的 main 方法的执行 是javac程序的执行入口。
1 public static void main(String args[])
2 {
//将标准错误流获取
3 PrintStream printstream = System.err;
4 if (Boolean.getBoolean("javac.pipe.output"))
5 printstream = System.out;
//创建 编译器对象
6 Main main1 = new Main(printstream, "javac");
//调用编译器的 compile方法进行 编译 并接受 args 为参数,该参数就是 javac 后面携带的参数
7 System.exit(main1.compile(args) ? 0 : main1.exitStatus);
8 }
compile方法的 编译过程 概括性的分析:
1.解析与填充符号表
解析: 对java源代码的字节流进行读取解析,进行两个大致的步骤,词法解析以及语法解析
词法解析: 识别 java源码中存在的表达语义的逻辑单元,列如 关键字 变量名 参数名 每一个逻辑单元 称为 标量。
语法解析:将各个独立的 标量按照java语法规范形成 java语法数,语法树的每一个节点代表一个操作,运算,或者 方法调用。
填充符号表: 解析后的语法树最顶级的节点将被用来填充在符号表中,符号表存储着各个语法树的最顶级节点,填充后的符号表最终形成 待处理表。
符号表就是一个遵从java语法的结构规范,用于组织语法树的逻辑顺序。
2.插入式注解处理器
jdk1.5后引入注解功能,注解是一种应用字节码 属性中类的元数据进行操作的一种编程机制。
处理表形成后 会自动检测是否有注解器需要执行,若有则执行注解处理器。注解处理器实现了在可插入式的编译期改变编译过程的功能。
其本质就是 再次修改 处理表中的语法树。 一旦语法树被修改,则将再次进行 词法,语法分析并填充符号表的过程。
3.语义分析并生成字节码
语义分析: 再次对语法树中的节点进行校验。对数据类型以及控制逻辑进行检测。
标量检测: 检验关键字是否使用正确,类型转换是否正确等。
数据与控制流分析: 对控制流程的逻辑进行校验。
语法糖解析: 编程语言为了 增加代码的可读性,以及减少编程出错率,提供了一些并不影响程序运行期仅在编译期有效的编程机制。
java语言中语法糖 有 泛型,拆箱与装箱,foreach循环,可变参数,switch,枚举等,在编译期将转换为字节码遵守的规范形式。
泛型使用类型擦出,拆装箱调用了valueOf与xxValue方法,foreach是迭代器 可变参数是数组,switch本质是 if else 的嵌套。
字节码替换: 在生成类的字节码之时,编译器后做一些默认性质的操作,当没有显示声明的构造器,则会创建默认的无参构造器,构造器分为 实例构造器与类构造器
在字节码层面 类构造器 是指多个static代码块中的语句 收敛生成的<cinit>指令。而构造代码块与显示的构造器将收敛生成实例构造器。
同时还会将 String类型的 +与+= 操作,默认替换为 对 StringBuffer或 StrignBudiuer的操作。
最后生成字节码。
代码如下:
1 public synchronized boolean compile(String as[])
2 {
3 String s = null;
4 String s1 = null;
5 String s2 = null;
6 String s3 = null;
7 boolean flag = false;
8 String s4 = null;
9 short word0 = 45;
10 short word1 = 3;
11 File file = null;
12 File file1 = null;
13 String s5 = "-Xjcov";
14 String s6 = "-Xjcov:file=";
15 int i = 0x41004;
16 long l = System.currentTimeMillis();
17 Vector vector = new Vector();
18 boolean flag1 = false;
19 Object obj = null;
20 String s7 = null;
21 String s8 = null;
22 String s9 = null;
23 exitStatus = 0;
24 try
25 {
26 as = CommandLine.parse(as);
27 }
28 catch (FileNotFoundException filenotfoundexception)
29 {
30 error("javac.err.cant.read", filenotfoundexception.getMessage());
31 System.exit(1);
32 }
33 catch (IOException ioexception)
34 {
35 ioexception.printStackTrace();
36 System.exit(1);
37 }
38 label0:
39 for (int j = 0; j < as.length; j++)
40 {
41 if (as[j].equals("-g"))
42 {
43 if (s8 != null && !s8.equals("-g"))
44 error("main.conflicting.options", s8, "-g");
45 s8 = "-g";
46 i |= 0x1000;
47 i |= 0x2000;
48 i |= 0x40000;
49 continue;
50 }
51 if (as[j].equals("-g:none"))
52 {
53 if (s8 != null && !s8.equals("-g:none"))
54 error("main.conflicting.options", s8, "-g:none");
55 s8 = "-g:none";
56 i &= 0xffffefff;
57 i &= 0xffffdfff;
58 i &= 0xfffbffff;
59 continue;
60 }
61 if (as[j].startsWith("-g:"))
62 {
63 if (s8 != null && !s8.equals(as[j]))
64 error("main.conflicting.options", s8, as[j]);
65 s8 = as[j];
66 String s10 = as[j].substring("-g:".length());
67 i &= 0xffffefff;
68 i &= 0xffffdfff;
69 i &= 0xfffbffff;
70 do
71 {
72 do
73 {
74 if (s10.startsWith("lines"))
75 {
76 i |= 0x1000;
77 s10 = s10.substring("lines".length());
78 } else
79 if (s10.startsWith("vars"))
80 {
81 i |= 0x2000;
82 s10 = s10.substring("vars".length());
83 } else
84 if (s10.startsWith("source"))
85 {
86 i |= 0x40000;
87 s10 = s10.substring("source".length());
88 } else
89 {
90 error("main.bad.debug.option", as[j]);
91 usage_error();
92 return false;
93 }
94 if (s10.length() == 0)
95 continue label0;
96 } while (!s10.startsWith(","));
97 s10 = s10.substring(",".length());
98 } while (true);
99 }
100 if (as[j].equals("-O"))
101 {
102 if (s9 != null && !s9.equals("-O"))
103 error("main.conflicting.options", s9, "-O");
104 s9 = "-O";
105 continue;
106 }
107 if (as[j].equals("-nowarn"))
108 {
109 i &= -5;
110 continue;
111 }
112 if (as[j].equals("-deprecation"))
113 {
114 i |= 0x200;
115 continue;
116 }
117 if (as[j].equals("-verbose"))
118 {
119 i |= 1;
120 continue;
121 }
122 if (as[j].equals("-nowrite"))
123 {
124 flag1 = true;
125 continue;
126 }
127 if (as[j].equals("-classpath"))
128 {
129 if (j + 1 < as.length)
130 {
131 if (s1 != null)
132 error("main.option.already.seen", "-classpath");
133 s1 = as[++j];
134 } else
135 {
136 error("main.option.requires.argument", "-classpath");
137 usage_error();
138 return false;
139 }
140 continue;
141 }
142 if (as[j].equals("-sourcepath"))
143 {
144 if (j + 1 < as.length)
145 {
146 if (s != null)
147 error("main.option.already.seen", "-sourcepath");
148 s = as[++j];
149 } else
150 {
151 error("main.option.requires.argument", "-sourcepath");
152 usage_error();
153 return false;
154 }
155 continue;
156 }
157 if (as[j].equals("-sysclasspath"))
158 {
159 if (j + 1 < as.length)
160 {
161 if (s2 != null)
162 error("main.option.already.seen", "-sysclasspath");
163 s2 = as[++j];
164 } else
165 {
166 error("main.option.requires.argument", "-sysclasspath");
167 usage_error();
168 return false;
169 }
170 continue;
171 }
172 if (as[j].equals("-bootclasspath"))
173 {
174 if (j + 1 < as.length)
175 {
176 if (s2 != null)
177 error("main.option.already.seen", "-bootclasspath");
178 s2 = as[++j];
179 } else
180 {
181 error("main.option.requires.argument", "-bootclasspath");
182 usage_error();
183 return false;
184 }
185 continue;
186 }
187 if (as[j].equals("-extdirs"))
188 {
189 if (j + 1 < as.length)
190 {
191 if (s3 != null)
192 error("main.option.already.seen", "-extdirs");
193 s3 = as[++j];
194 } else
195 {
196 error("main.option.requires.argument", "-extdirs");
197 usage_error();
198 return false;
199 }
200 continue;
201 }
202 if (as[j].equals("-encoding"))
203 {
204 if (j + 1 < as.length)
205 {
206 if (s7 != null)
207 error("main.option.already.seen", "-encoding");
208 s7 = as[++j];
209 } else
210 {
211 error("main.option.requires.argument", "-encoding");
212 usage_error();
213 return false;
214 }
215 continue;
216 }
217 if (as[j].equals("-target"))
218 {
219 if (j + 1 < as.length)
220 {
221 if (s4 != null)
222 error("main.option.already.seen", "-target");
223 s4 = as[++j];
224 int k = 0;
225 do
226 {
227 if (k >= releases.length)
228 break;
229 if (releases[k].equals(s4))
230 {
231 word0 = majorVersions[k];
232 word1 = minorVersions[k];
233 break;
234 }
235 k++;
236 } while (true);
237 if (k == releases.length)
238 {
239 error("main.unknown.release", s4);
240 usage_error();
241 return false;
242 }
243 } else
244 {
245 error("main.option.requires.argument", "-target");
246 usage_error();
247 return false;
248 }
249 continue;
250 }
251 if (as[j].equals("-d"))
252 {
253 if (j + 1 < as.length)
254 {
255 if (file != null)
256 error("main.option.already.seen", "-d");
257 file = new File(as[++j]);
258 if (!file.exists())
259 {
260 error("main.no.such.directory", file.getPath());
261 usage_error();
262 return false;
263 }
264 } else
265 {
266 error("main.option.requires.argument", "-d");
267 usage_error();
268 return false;
269 }
270 continue;
271 }
272 if (as[j].equals(s5))
273 {
274 i |= 0x40;
275 i &= 0xffffbfff;
276 i &= 0xffff7fff;
277 continue;
278 }
279 if (as[j].startsWith(s6) && as[j].length() > s6.length())
280 {
281 file1 = new File(as[j].substring(s6.length()));
282 i &= 0xffffbfff;
283 i &= 0xffff7fff;
284 i |= 0x40;
285 i |= 0x80;
286 continue;
287 }
288 if (as[j].equals("-XO"))
289 {
290 if (s9 != null && !s9.equals("-XO"))
291 error("main.conflicting.options", s9, "-XO");
292 s9 = "-XO";
293 i |= 0x4000;
294 continue;
295 }
296 if (as[j].equals("-Xinterclass"))
297 {
298 if (s9 != null && !s9.equals("-Xinterclass"))
299 error("main.conflicting.options", s9, "-Xinterclass");
300 s9 = "-Xinterclass";
301 i |= 0x4000;
302 i |= 0x8000;
303 i |= 0x20;
304 continue;
305 }
306 if (as[j].equals("-Xdepend"))
307 {
308 i |= 0x20;
309 continue;
310 }
311 if (as[j].equals("-Xdebug"))
312 {
313 i |= 2;
314 continue;
315 }
316 if (as[j].equals("-xdepend") || as[j].equals("-Xjws"))
317 {
318 i |= 0x400;
319 if (out == System.err)
320 out = System.out;
321 continue;
322 }
323 if (as[j].equals("-Xstrictdefault"))
324 {
325 i |= 0x20000;
326 continue;
327 }
328 if (as[j].equals("-Xverbosepath"))
329 {
330 flag = true;
331 continue;
332 }
333 if (as[j].equals("-Xstdout"))
334 {
335 out = System.out;
336 continue;
337 }
338 if (as[j].equals("-X"))
339 {
340 error("main.unsupported.usage");
341 return false;
342 }
343 if (as[j].equals("-Xversion1.2"))
344 {
345 i |= 0x800;
346 continue;
347 }
348 if (as[j].endsWith(".java"))
349 {
350 vector.addElement(as[j]);
351 } else
352 {
353 error("main.no.such.option", as[j]);
354 usage_error();
355 return false;
356 }
357 }
358
359 if (vector.size() == 0 || exitStatus == 2)
360 {
361 usage_error();
362 return false;
363 }
364 BatchEnvironment batchenvironment = BatchEnvironment.create(out, s, s1, s2, s3);
365 if (flag)
366 output(getText("main.path.msg", batchenvironment.sourcePath.toString(), batchenvironment.binaryPath.toString()));
367 batchenvironment.flags |= i;
368 batchenvironment.majorVersion = word0;
369 batchenvironment.minorVersion = word1;
370 batchenvironment.covFile = file1;
371 batchenvironment.setCharacterEncoding(s7);
372 String s11 = getText("main.no.memory");
373 String s12 = getText("main.stack.overflow");
374 batchenvironment.error(0L, "warn.class.is.deprecated", "sun.tools.javac.Main");
375 try
376 {
377 for (Enumeration enumeration = vector.elements(); enumeration.hasMoreElements();)
378 {
379 File file2 = new File((String)enumeration.nextElement());
380 try
381 {
382 batchenvironment.parseFile(new ClassFile(file2));
383 }
384 catch (FileNotFoundException filenotfoundexception1)
385 {
386 batchenvironment.error(0L, "cant.read", file2.getPath());
387 exitStatus = 2;
388 }
389 }
390
391 Object obj1 = batchenvironment.getClasses();
392 do
393 {
394 if (!((Enumeration) (obj1)).hasMoreElements())
395 break;
396 ClassDeclaration classdeclaration = (ClassDeclaration)((Enumeration) (obj1)).nextElement();
397 if (classdeclaration.getStatus() == 4 && !classdeclaration.getClassDefinition().isLocal())
398 try
399 {
400 classdeclaration.getClassDefinition(batchenvironment);
401 }
402 catch (ClassNotFound classnotfound) { }
403 } while (true);
404 obj1 = new ByteArrayOutputStream(4096);
405 boolean flag2;
406 do
407 {
408 flag2 = true;
409 batchenvironment.flushErrors();
410 Enumeration enumeration1 = batchenvironment.getClasses();
411 do
412 {
413 if (!enumeration1.hasMoreElements())
414 break;
415 ClassDeclaration classdeclaration1 = (ClassDeclaration)enumeration1.nextElement();
416 switch (classdeclaration1.getStatus())
417 {
418 case 1: // '\001'
419 case 2: // '\002'
420 default:
421 break;
422
423 case 0: // '\0'
424 if (!batchenvironment.dependencies())
425 continue;
426 // fall through
427
428 case 3: // '\003'
429 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (SOURCE): loading, ").append(classdeclaration1).toString());
430 flag2 = false;
431 batchenvironment.loadDefinition(classdeclaration1);
432 if (classdeclaration1.getStatus() != 4)
433 {
434 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (SOURCE): not parsed, ").append(classdeclaration1).toString());
435 continue;
436 }
437 // fall through
438
439 case 4: // '\004'
440 if (classdeclaration1.getClassDefinition().isInsideLocal())
441 {
442 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (PARSED): skipping local class, ").append(classdeclaration1).toString());
443 continue;
444 }
445 flag2 = false;
446 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (PARSED): checking, ").append(classdeclaration1).toString());
447 SourceClass sourceclass = (SourceClass)classdeclaration1.getClassDefinition(batchenvironment);
448 sourceclass.check(batchenvironment);
449 classdeclaration1.setDefinition(sourceclass, 5);
450 // fall through
451
452 case 5: // '\005'
453 SourceClass sourceclass1 = (SourceClass)classdeclaration1.getClassDefinition(batchenvironment);
454 if (sourceclass1.getError())
455 {
456 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (CHECKED): bailing out on error, ").append(classdeclaration1).toString());
457 classdeclaration1.setDefinition(sourceclass1, 6);
458 continue;
459 }
460 flag2 = false;
461 ((ByteArrayOutputStream) (obj1)).reset();
462 batchenvironment.dtEvent((new StringBuilder()).append("Main.compile (CHECKED): compiling, ").append(classdeclaration1).toString());
463 sourceclass1.compile(((OutputStream) (obj1)));
464 classdeclaration1.setDefinition(sourceclass1, 6);
465 sourceclass1.cleanup(batchenvironment);
466 if (sourceclass1.getNestError() || flag1)
467 continue;
468 String s14 = classdeclaration1.getName().getQualifier().toString().replace('.', File.separatorChar);
469 String s15 = (new StringBuilder()).append(classdeclaration1.getName().getFlatName().toString().replace('.', '$')).append(".class").toString();
470 File file3;
471 if (file != null)
472 {
473 if (s14.length() > 0)
474 {
475 file3 = new File(file, s14);
476 if (!file3.exists())
477 file3.mkdirs();
478 file3 = new File(file3, s15);
479 } else
480 {
481 file3 = new File(file, s15);
482 }
483 } else
484 {
485 ClassFile classfile = (ClassFile)sourceclass1.getSource();
486 if (classfile.isZipped())
487 {
488 batchenvironment.error(0L, "cant.write", classfile.getPath());
489 exitStatus = 2;
490 continue;
491 }
492 file3 = new File(classfile.getPath());
493 file3 = new File(file3.getParent(), s15);
494 }
495 try
496 {
497 FileOutputStream fileoutputstream = new FileOutputStream(file3.getPath());
498 ((ByteArrayOutputStream) (obj1)).writeTo(fileoutputstream);
499 fileoutputstream.close();
500 if (batchenvironment.verbose())
501 output(getText("main.wrote", file3.getPath()));
502 }
503 catch (IOException ioexception1)
504 {
505 batchenvironment.error(0L, "cant.write", file3.getPath());
506 exitStatus = 2;
507 }
508 if (batchenvironment.print_dependencies())
509 sourceclass1.printClassDependencies(batchenvironment);
510 break;
511 }
512 } while (true);
513 } while (!flag2);
514 }
515 catch (OutOfMemoryError outofmemoryerror)
516 {
517 batchenvironment.output(s11);
518 exitStatus = 3;
519 return false;
520 }
521 catch (StackOverflowError stackoverflowerror)
522 {
523 batchenvironment.output(s12);
524 exitStatus = 3;
525 return false;
526 }
527 catch (Error error1)
528 {
529 if (batchenvironment.nerrors == 0 || batchenvironment.dump())
530 {
531 error1.printStackTrace();
532 batchenvironment.error(0L, "fatal.error");
533 exitStatus = 4;
534 }
535 }
536 catch (Exception exception)
537 {
538 if (batchenvironment.nerrors == 0 || batchenvironment.dump())
539 {
540 exception.printStackTrace();
541 batchenvironment.error(0L, "fatal.exception");
542 exitStatus = 4;
543 }
544 }
545 int i1 = batchenvironment.deprecationFiles.size();
546 if (i1 > 0 && batchenvironment.warnings())
547 {
548 int j1 = batchenvironment.ndeprecations;
549 Object obj2 = batchenvironment.deprecationFiles.elementAt(0);
550 if (batchenvironment.deprecation())
551 {
552 if (i1 > 1)
553 batchenvironment.error(0L, "warn.note.deprecations", new Integer(i1), new Integer(j1));
554 else
555 batchenvironment.error(0L, "warn.note.1deprecation", obj2, new Integer(j1));
556 } else
557 if (i1 > 1)
558 batchenvironment.error(0L, "warn.note.deprecations.silent", new Integer(i1), new Integer(j1));
559 else
560 batchenvironment.error(0L, "warn.note.1deprecation.silent", obj2, new Integer(j1));
561 }
562 batchenvironment.flushErrors();
563 batchenvironment.shutdown();
564 boolean flag3 = true;
565 if (batchenvironment.nerrors > 0)
566 {
567 String s13 = "";
568 if (batchenvironment.nerrors > 1)
569 s13 = getText("main.errors", batchenvironment.nerrors);
570 else
571 s13 = getText("main.1error");
572 if (batchenvironment.nwarnings > 0)
573 if (batchenvironment.nwarnings > 1)
574 s13 = (new StringBuilder()).append(s13).append(", ").append(getText("main.warnings", batchenvironment.nwarnings)).toString();
575 else
576 s13 = (new StringBuilder()).append(s13).append(", ").append(getText("main.1warning")).toString();
577 output(s13);
578 if (exitStatus == 0)
579 exitStatus = 1;
580 flag3 = false;
581 } else
582 if (batchenvironment.nwarnings > 0)
583 if (batchenvironment.nwarnings > 1)
584 output(getText("main.warnings", batchenvironment.nwarnings));
585 else
586 output(getText("main.1warning"));
587 if (batchenvironment.covdata())
588 {
589 Assembler assembler = new Assembler();
590 assembler.GenJCov(batchenvironment);
591 }
592 if (batchenvironment.verbose())
593 {
594 l = System.currentTimeMillis() - l;
595 output(getText("main.done_in", Long.toString(l)));
596 }
597 return flag3;
598 }