美文网首页
java 知识合集

java 知识合集

作者: lucode | 来源:发表于2019-02-15 09:33 被阅读1次

    String、StringBufer、StringBuilder

    String 它是典型的Immutable(不可改变)类,被声明成为fnal class,所有属性也都是fnal的。也由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的String对象。在循环场景下不建议使用这些功能。

    StringBufer是为解决上面提到拼接产生太多中间对象的问题而提供的一个类,可以用append或者add方法,把字符串添加到已有序列的末尾或者指定位置。StringBufer本质是一个线程安全的可修改字符序列,它保证了线程安全(简单粗暴各种修改数据的方法都加上synchronized关键字实现的),也随之带来了额外的性能开销,所以除非有线程安全的需要,不然还是推荐使用它的后继者,也就是StringBuilder。

    StringBuilder 在能力上和StringBufer没有本质区别,但是它去掉了线程安全的部分,有效减小了开销,是绝大部分情况下进行字符串拼接的首选。从 builder 命名来看这个类专门就是为创建而生。

    • Immutable对象在拷贝时不需要额外复制数据。

    字符串的内部数组

    • 为了实现修改字符序列的目的,StringBufer和StringBuilder底层都是利用可修改的char数组(JDK 9以后是byte),都继承了AbstractStringBuilder。

    • 这个内部数组应该创建成多大的呢?如果太小,拼接的时候可能要重新创建足够大的数组;如果太大,又会浪费空间。目前的实现是,构建时初始字符串长度加16(这意味着,如果没有构建对象时输入最初的字符串,那么初始值就是16)。我们如果确定拼接会发生非常多次,而且大概是可预计的,那么就可以指定合适的大小,避免很多次扩容的开销。扩容会产生多重开销,因为要抛弃原有数组,创建新的(可以简单认为是倍数)数组,还要进行arraycopy。

    字符串拼接

    • 如果在代码拼接说 String 拼接效率低下,但是在 jdk8即使你使用 String 拼接编译器还是会把你优化成 StringBuilder,jdk9优化成StringConcatFactory(暂时没用了解过)

    字符串缓存、内存

    • String在jdk6以后提供了intern()方法,目的是提示JVM把相应字符串缓存起来,以备重复使用。但是不建议使用。

    • jdk6被缓存的字符串是存在所谓PermGen里的,也就是臭名昭著的“永久代”,这个空间是很有限的,也基本不会被FullGC之外的垃圾收集照顾到。所以,如果使用不当,OOM就会光顾。

    • jdk7存放在堆中。

    • jdk8出现了MetaSpace(元数据区),就存在元空间中。

    • intern是一种显式地排重机制,但是它也有一定的副作用,因为需要开发者写代码时明确调用,一是不方便,每一个都显式调用是非常麻烦的;另外就是我们很难保证效率,应用开发阶段很难清楚地预计字符串的重复情况,有人认为这是一种污染代码的实践。
      幸好在Oracle JDK 8u20之后,推出了一个新的特性,也就是G1 GC下的字符串排重。它是通过将相同数据的字符串指向同一份数据来做到的,是JVM底层的改变,并不需要Java类库做什么修改。
      开启 G1 GC 后可加入这个参数开启-XX:+UseStringDeduplication

    动态代理

    深入理解RPC之动态代理篇这篇文章针对集中动态代理有比较详细的分析
    动态代理的应用场景比如:RPC、安全、日志、事务

    静态代理

    事先写好代理类,可以手工编写,也可以用工具生成。缺点是每个业务类都要对应一个代理类,非常不灵活。

    动态代理

    运行时自动生成代理对象。缺点是生成代理代理对象和调用代理方法都要额外花费时间。

    JDK动态代理:基于Java反射机制实现,必须要实现了接口的业务类才能用这种办法生成代理对象。新版本也开始结合ASM机制。

    cglib动态代理:基于ASM机制实现,通过生成业务类的子类作为代理类。

    基本数据类型和引用数据类型

    缓存机制

    缓存机制并不是只有Integer才有,同样存在于其他的一些包装类,比如:

    • Boolean,缓存了true/ false对应实例,确切说,只会返回两个常量实例Boolean.TRUE/ FALSE。
    • Short,同样是缓存了-128到127之间的数值。
    • Byte,数值有限,所以全部都被缓存。
    • Character,缓存范围'\ u0000' 到 '\ u007F'。
      继续深挖缓存,I nteger的缓存范围虽然默认是-128到127,但是在特别的应用场景,比如我们明确知道应用会频繁使用更大的数值,这时候应该怎么办呢?
    -XX:AutoBoxCacheMax=N
    

    缓存上限值实际是可以根据需要调整的,JVM提供了参数设置:

    自动拆装箱的注意点

    建议避免无意中的装箱、拆箱行为,尤其是在性能敏感的场合,创建10万个Java对象和10万个整数的开销可不是一个数量级的,不管是内存使用还是处理速度,光是对象头的空间占用就已经是数量级的差距了。

    Integer 内存结构组成

    1. Mark Word: 标记位 4字节,类似轻量级锁标记位,偏向锁标记位等。
    2. Class对象指针: 4字节,指向对象对应class对象的内存地址。
    3. 对象实际数据:对象所有成员变量。
    4. 对齐:对齐填充字节,按照8个字节填充。
      Integer占用内存大小,4+ 4+ 4+ 4= 16字节。

    集合

    狭义的集合框架

    Map

    Map

    LinkedHashMap

    LinkedHashMap通常提供的是遍历顺序符合插入顺序,它的实现是通过为条目(键值对)维护一个双向链表。注意,通过特定构造函数,我们可以创建反映访问顺序的实例,所谓的put、get、compute等,都算作“访问”。

    
    

    相关文章

      网友评论

          本文标题:java 知识合集

          本文链接:https://www.haomeiwen.com/subject/xdczsqtx.html