作为一个从PHP转Java的人,发现阿里巴巴的arthas很好用。通过arthas的redefine命令,和PHP一样,可以在不重新发布的情况下改变程序的行为(前提是类结构和方法签名没有改变)。但是用多了之后发现,很多时候,改了几行代码,有时甚至加一行日志,就无法重新定义。提示redefineerror!java.lang.UnsupportedOperationException:classredefinitionfailed:attemptedtoaddamethod提示我们添加新的方法,那我们看看有没有添加新的方法。通过javap查看定义的方法:Thisistheoldclass:Thisisnewclass:经过对比发现是新类,也就是本地编译的类,lambdas对应的方法名是lambda$getAllCity$0,最后一个数字从0开始。在老类中,也就是现在运行的类中,同一个lambda的方法名是lambda$getAllCity$121,最后一个数字是一个非常大的数字。仔细对比后发现是jdk版本问题,不同jdk版本的处理可能lamdba不一致。具体来说,网上编译的jdk版本是1.8.0_66-b17,而本地版本是1.8.0_222-b10,这两个版本的lambda对应的方法名是不一样的。首先,为了调试方便,写一个最新的小复用例子来看看://Compile.java//编译LamdbaTest1.java和LamdbaTest2.javaimportjavax.tools.*;importjava.io.File;publicclassCompile{publicstatic[voidmain(s)){Stringpath1="/path/to/LamdbaTest1.java";Stringpath2="/path/to/LamdbaTest2.java";JavaCompilerjavaCompiler=ToolProvider.getSystemJavaCompiler();DiagnosticCollectordiagnostics=newDiagnosticCollector();StandardJavaFileManagerfileManager=javaCompiler.getStandardFileManager(诊断,null,null);IterablecompilationUnits=fileManager.getJavaFileObjects(newFile(path1),newFile(path2));JavaCompiler.CompilationTasktask=javaCompiler.getTask(null,fileManager,diagnostics,null,null,compilationUnits);booleansuccess=task.call();System.out.println(success);}}//LamdbaTest1.javapublicclassLamdbaTest1{privatevoidtest(Runnablerunnable){runnable.run();}privatevoidmain()throwsThrowable{test(()->{System.out.println(11);});}}//LamdbaTest2.javapublicclassLamdbaTest2{privatevoidtest(Runnablerunnable){runnable.run();}privatevoidmain()throwsThrowable{test(()->{System.out.println(22);});}}使用1.8.0_222-b10(新版jdk)运行后发现LambdaTest2中的lambda方法为:privatestaticvoidlambda$main$0();更改版本1.8.0_66-b17(旧版本jdk)后,lambda方法变为:privatestaticvoidlambda$main$1();尝试同时编译几个文件,我们可以发现:对于老版本的javac,末尾的数字是全局递增的,50个类有100个lambda,最后一个lambda的个数是99;而新版本是每节课的重新统计与总课时数无关。确认问题后,接下来就是不断中断重试。后来发现javac不同版本的逻辑确实不一样。首先,通过查看jdk源码可以知道lambda的方法名是:lambda$
