那些年我踩过的坑——Java

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
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值