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 voidmain(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代码块中的语句 收敛生成的指令。而构造代码块与显示的构造器将收敛生成实例构造器。

同时还会将 String类型的 +与+= 操作,默认替换为 对 StringBuffer或 StrignBudiuer的操作。

最后生成字节码。

代码如下:

1 public synchronized booleancompile(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 = newVector();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 continuelabel0;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 
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 
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 
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 
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 
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 
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 
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 
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 = newFile(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 = newFile((String)enumeration.nextElement());380 try
381 {382 batchenvironment.parseFile(newClassFile(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 booleanflag2;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 = newFile(file, s14);476 if (!file3.exists())477 file3.mkdirs();478 file3 = newFile(file3, s15);479 } else
480 {481 file3 = newFile(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 = newFile(classfile.getPath());493 file3 = newFile(file3.getParent(), s15);494 }495 try
496 {497 FileOutputStream fileoutputstream = newFileOutputStream(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), newInteger(j1));554 else
555 batchenvironment.error(0L, "warn.note.1deprecation", obj2, newInteger(j1));556 } else
557 if (i1 > 1)558 batchenvironment.error(0L, "warn.note.deprecations.silent", new Integer(i1), newInteger(j1));559 else
560 batchenvironment.error(0L, "warn.note.1deprecation.silent", obj2, newInteger(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 = newAssembler();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 returnflag3;598 }