从计算机程序出现的第一天起,对效率的追求就是程序天生的坚定信仰,这个过程犹如一场没有终点,永不停歇的F1方程式竞赛,程序员试车手,技术平台则是在赛道上飞驰的赛车。

有时候想想自己也挺势力的。昨天没有更新文章。因为我是一个面向工作的程序员。昨天《深入理解JVM虚拟机》讲到的知识点是“虚拟机字节码执行引擎”和“类加载和执行子系统的案例与实践”。习惯于背各种面试题,哪怕不熟悉的知识,起码书面知识点要背下来的填鸭式学习的我看过大大小小的面试总结,所以感觉以上两章不在面试的考点上而且对于一个中级开发(我对自己目前的定位)来说过于深奥,而且大量的测试代码不好总结,所以就没有在此记笔记。然后大概看了这本书的后半部分。不出意外应该还有四章就整理完了(我已经把书看完了,就差整理到简书上)。除了这个早期优化,还有晚期优化,java内存模型与线程,线程安全与锁优化。
这本书,读起来不可谓不用心,毕竟大部分一个字一个字看的,深知其中一大半内容又用键盘打出来的。但是感觉理解上并不十分透彻,可能因为知道这是面试前的啃书,就跟考试前的通宵一样。用心也努力,但是为了的只是成绩而不是学习知识的乐趣。
可能今天下雨,莫名有点小小的遗憾。又是一个周日。希望下周一切顺利。然后有机会的话,可以用一种闲暇舒适的态度重温此书。话不多说,开始整理笔记。
概述
首先java的编译期其实是“不确定”的过程。我们常用的javac,Eclipse JDT都是前端编译器。还有书中提到的JIT,AOT等等(后两种我也不知道其实)。然后这本书中提到的编译期和编译器都是第一类,也就是前端编译器。
据说java中相当多新生的java语法特性,都是靠编译器的“语法糖”来实现的,而不是以来虚拟机的底层改进。可以说,java中即时编译器在运行期的优化过程对于程序运行来说更重要。而前端编译器在编译期的优化过程对于程序编码来说关系更加密切。
Java语法糖
语法糖:语法糖也称糖衣语法。指在计算机语言中添加的某种语法,这种语法对语言的功能并没有影响。但是更方便程序员使用。通常来讲,使用语法糖能够增加程序的可读性,从而减少程序代码出错的机会。
java中最常用的语法糖:泛型,变长参数,自动装箱/拆箱等。
泛型与类型擦除:泛型是jdk1.5出的(虽然现在又12了,但是我一般都用jdk1.8)。它的本质是参数化类型的应用。也就是说所操作的数据类型被指定为一个参数。这种参数类型可以用在类,接口和方法的创建中,分别成为泛型类,泛型接口和泛型方法。
打个比方,1.5以前在哈希表中存取,因为没有泛型,都是Object结合类型强转两个特点实现泛化的(现在想想能理解,但是麻烦死了。感谢我活在直接就有泛型的时代)。这样做又麻烦又不安全(容易类型转化错误)。
然后有了泛型。java中的泛型只在程序源码中存在,在编译后的字节码文件中就自动替换为原来的原生类型。并且在相应的地方插入了强转的代码。因为其实这个泛型只是让我们编译的时候更加方便和安全而已,这个就是语法糖。也被别的语言称为伪泛型。
自动装箱,拆箱与遍历循环
从纯技术上讲,自动装箱,自动拆箱与遍历循环这些语法糖无论是实现上还是思想上都不能和泛型相比。专门拿出来讲的原因是因为他们是java语言里使用最多的语法糖。
自动装箱,拆箱在编译之后被转化成了对应的包装和还原方法。遍历循环则是把代码还原成了迭代器的实现。这也是为什么遍历循环需要被遍历的类实现Iterable接口的原因。最后说变长参数,它在调用的时候变成了一个数组类型的参数。
这些语法糖都很简单。但是也有一些需要注意的问题。比如包装类的”==“运算在不遇到算术运算的情况下不会自动拆箱。以及他们的equals()方法不处理数据转型的关系。
条件编译
java语言条件编译的语法就是使用条件为常量的if语句。(简单解释下,就是if(true)这种,ture是常量。书中例子就是这样的,估计if(false)也可以应该)。这样的条件语句在编译阶段就会被运行。假如:
package demo;
public class demo {
public static void main(String[] args) {
if(true) {
System.out.println("I");
}else {
System.out.println("2");
}
}
}
上面的代码在编译后,直接会变成:
public static void main(String[] args) {
System.out.println("I");
}
除了这几个介绍了的语法糖,java里还有很多,比如内部类,枚举类,断言语句,对枚举和字符串的switch支持,try语句中定义和关闭资源等。书里没介绍我也没额外查找资料。所以这里就不说了。
编译器
这里其实书中是一个实战。但是我觉得全都敲下来没意义。主要讲一下内容吧。
首先如果你试图了解过javac编译器的源码,就会知道编译器在把java程序源码编译为字节码的时候,会对java程序源码做各方面的检查校验。但是这些校验都是以程序“写的对不对”为出发点。虽然有的会有警告,但是总体来讲还是不在意“写的好不好”。针对这种情况也有一些针对程序“写的好不好”的校验工具,例如CheckStyle,FindBug等等。有兴趣的自己去看吧。也算给自己留个坑。如果以后什么时候有空了我也去看看。这有一个实战做个简单校验工具的demo。我就说下思路和大概,具体的逻辑代码就不完善了。首先定义一个处理器这里两点:
- 继承AbstractProcessor类
- 重写初始化方法和检查方法(检查方法是必须重写的。初始化方法我看书上重写了我就也重写了)
底下的这个类,两个方法按需求重写就好了。
package demo;
import java.util.Set;
import javax.annotation.processing.AbstractProcessor;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.RoundEnvironment;
import javax.annotation.processing.SupportedAnnotationTypes;
import javax.annotation.processing.SupportedSourceVersion;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.TypeElement;
@SupportedAnnotationTypes("*")
@SupportedSourceVersion(value = SourceVersion.RELEASE_8)
public class NameChecker extends AbstractProcessor {
//这个是初始化检查插件的
@Override
public synchronized void init(ProcessingEnvironment processingEnv) {
// TODO Auto-generated method stub
super.init(processingEnv);
}
//这个是具体检查内容
@Override
public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
// 在这里写检查器的使用
return false;
}
}
再定义一个检查器。
这个就是具体业务逻辑了,所以我复制粘贴了。反正就是一个规则而已。然后规则里不符合要求的就报警告。然后这个实战不算深奥,有兴趣的同学自己去找demo或者私聊我我发你。
然后这一章差不多就这么多内容了。
全文手打不易。如果你觉得稍微帮到了你一点点,请点个喜欢点个关注。有不同意见或者问题的欢迎评论或者私信。祝大家工作生活都顺顺利利吧。
网友评论