Java基础
- 复用构造器:只能在构造函数第一行调用其他构造函数,且只能调用一个
- 接口适合用来实现mixin(将一个类变量完全复制到另一个类中)
- 类被load时,static初始化->内存申请->默认初始化->调用构造器
- Arrays类用来对数组进行操作,Collections对Collection
- Map中的key需要有equals方法,HashMap要有hashCode,TreeMap要实现Comparable
- RuntimeException不需声明就能抛出
- Input(Output)Stream是字节流,Reader/Writer是字符流
- 一旦出现Foo.class,classloader已经把Foo的二进制读到了内存中,可能会出现内存占用问题,所以框架多存className,然后用反射loadclass
- Java的泛型会根据赋值进行类型参数推断,但是返回结果被直接作为方法参数时不会进行类型参数推断。可以显示说明类型,形如:
bar(Class.<Type>foo())
,奇葩语法 - 泛型可以使用自限定类型,实现类的泛型参数就是自己
class Foo<T extends Foo<T>>
,此时,可以声明一些参数为T的函数,只接受与自己相同类型的参数,例如Compare时,即jdk5以后支持的参数协变 - ConcurrentHashMap只是给put与对象hash相同的对象链表加锁,速度会快,完全依赖会有问题
- Exception是函数声明的一部分,所以,Runnable是不能throw一般的Exception的,只能throw RuntimeException。对于Thread中的Exception,使用UncaughtExceptionHandler
- Exception在二进制里是用
Exception table:
from to target type
0 8 19 Class java/lang/Exception
0 8 39 any
19 28 39 any
来表示的。对于finally,是将finally中的代码(可能是因为测试代码很少,编译器做的优化)附加到每一个try/catch可能流程的末尾,然后由finally goto到return行。一个更复杂的分析
- 构造函数中非final变量的初始化可能被重排到构造函数结束后!!!
- synchronized块只保证A线程块内部的执行是在B线程进入块之前完成的,并不保证A线程块前的代码会被执行!!!
- 有几种方法能够做到等待所有子任务完成后继续:
- ExecutorService.awaitTermination,没什么坑
- CountDownLatch,专门做这个的多线程工具类,适用性广,非常赞
- Thread.join + for,这个有一个小点。for循环调用join的时候是顺序的,也就是说,join是按序等待结束的
- 类初始化是线程安全的,所以多线程可能会互锁,静态块会在这里执行,要小心
- BlockingQueue的take会block,但遍历不会,会用ReentrantLock来做锁(ArrayBlockingQueue)
- 混淆对代码的改动匪夷所思,一定要看一下
- Java对于重载参数的解析发生在编译时,所以,多态的重载并不支持。WTF!!!
- javac默认报错100个。。。神奇的设置。。。gradle里这样修改
afterEvaluate {
tasks.withType(JavaCompile) {
options.compilerArgs << "-Xmaxerrs" << "100000"
}
}
黑科技
- DCL式的Singleton在jdk1.5以前是有bug的,因为JMM规定的一致性协议是单线程的as if serial。除非使用volatile强制内存写通
- Proxy也很慢,平均下来比直接new对象要慢30倍左右(高通615 Android 4.4)
- 可以通过更改jni层class和method struct中的指针指向替换类和方法,大阿里的一个实现
- Proxy只能搞interface的实现,想用这个做类功能的替换是不行的
- LambdaMetafactory可以生成高速的反射调用,java8支持
- Annotation Processor生成java代码,一定要记得把writer#close掉,要不然后续的javac会忽略生成的类(惨痛教训,查了一个小时,太傻逼了)
- APT中,文件一旦创建(createResource)并openWriter,不论后续轮次的生成中是否close writer或者删除文件,再open都是会跪掉的,getResource出来的不能openWriter。所以,只要想支持多轮次的生成resource文件,必须使用Writer的成员变量,在finalize中释放(虽然很二)。
- 对于 @Repeatable 的 annotation,在 APT 的
roundEnv.getElementsAnnotatedWith
时,必须同时处理 @Foo 和 @Foos。对于重复的 @Foo,会被默默的转成 @Foos