后端开发小复习

本文最后更新于:6 个月前

这里是🐰自己的快速复习,不全,随心记,🐰认为的重点或不熟的,可能很抽象昂!

Java复习

基础

Reference: JavaGuide

  • Java特点:

    • 面向对象(封装、继承、多态)
    • JVM, Write Once, Run Anywhere
  • JVM和字节码(.class)完成跨平台特性。

    • .Java -> Javac compile -> .class
      • -> Hot Code(Yes) -> JIT -> 机器码
      • -> Hot Code(No) -> 解释器 -> 机器码
    • 编译与解释并存,先编译,后解释。.class这种字节码必须由 Java 解释器来解释执行。
  • Java vs CPP

    • Java 不提供指针来直接访问内存,程序内存更加安全
    • Java 的类是单继承的,C++ 支持多重继承;虽然 Java 的类不可以多继承,但是接口可以多继承。
    • Java 有自动内存管理垃圾回收机制(GC),不需要程序员手动释放无用内存。
    • C++同时支持方法重载和操作符重载,但是 Java 只支持方法重载(操作符重载增加了复杂性,这与 Java 最初的设计思想不符)。
  • 包装

    • 包装类型的缓存机制。
    • 所有整型包装类对象之间值的比较,全部使用 equals 方法比较。
    • 拆箱(xxxValue())与装箱(valueOf()),尽量避免,会影响性能。
  • 浮点数精度丢失,无限循环小数无法存储在有限空间内,如果精确,用BigDecimal。超过Long整型用BigInteger,性能差一些。

  • 可变长参数,所谓可变长参数就是允许在调用方法时传入不定长度的参数(String… args)

  • 深拷贝与浅拷贝,Cloneable接口与clone()方法。

  • 重写 Equals() 时必须重写 hashCode() 方法。Map,Set等底层都是先用了HashCode(),再用了Equals

  • String

    • StringBuffer线程安全,StringBuilder 相比使用 StringBuffer 仅能获得 10%~15% 左右的性能提升,但却要冒多线程不安全的风险。
    • String不可变?String 类中使用 final 关键字修饰字符数组来保存字符串,保存字符串的数组被 final 修饰且为私有的,并且String 类没有提供/暴露修改这个字符串的方法。String 类被 final 修饰导致其不能被继承,进而避免了子类破坏 String 不可变。
    • “+”和“+=”是专门为 String 类重载过的运算符,也是 Java 中仅有的两个重载过的运算符。字符串对象通过“+”的字符串拼接方式,实际上是通过 StringBuilder 调用 append() 方法实现的,拼接完成之后调用 toString() 得到一个 String 对象 。循环“+”不会复用StringBuilder,每次都创建一个新的,性能不好。
    • JDK 9 之后,你可以放心使用“+” 进行字符串拼接了。字符串相加 “+” 改为了用动态方法 makeConcatWithConstants() 来实现,而不是大量的 StringBuilder 了。
  • 字符串常量池

    • new String()创建一个或两个。池有了就一个,池没有就两个。
    • String.intern() 是一个 native(本地)方法。存在就返回,不存在就创建再返回。注意s3.intern()和s3没有一点关系,和s3的字符串在字符串常量池中的状态有关。
    • 变量和常量做“+”,字符串常量拼接得到的字符串常量在编译阶段就已经被存放字符串常量池,变量不行。基本数据类型、final 修饰的基本数据类型和字符串变量、字符串通过 “+”拼接得到的字符串符合条件。引用的值在程序编译期是无法确定的,编译器无法对其进行优化。
  • 异常

    • finally里面不要return,try & finally都有return,try中的return会被忽略。try(return) -> finally -> finally(return),其实也符合常理,毕竟最后执行的是finally,以最后执行的为主。
    • finally不一定会被执行,例如JVM被终止运行,线程死亡,CPU被关闭。
    • Try-with-resources 代替 try-catch-finally。
    • 异常使用注意点:信息有意义,具体。日志打印日常后就不再抛出。
  • DOIP/IRP协议,序列化在这一层。也就是说,序列化在应用层(具体来说是表示层)

  • 值传递和引用传递

    • 值传递是实际参数值的拷贝,会创建副本
    • 引用不创建副本,直接就是同一个地址。
    • Java只有值,判断依据是,创建了副本!对象的传递本质上是通过一个相同的地址值副本来实现的昂!
  • 代理

    • 静态代理:为某个类套个固定的代理,代理和代理的类一一对应,一动皆动,不够灵活。
    • 动态代理:确定固定的代理,不同传入的动态的类都可以使用。(根据传入的类,动态作用,就很Smart)
  • Unsafe

    • 操作内存,本地方法
    • 内存屏障:禁止指令重排 -> CPU内存模型
    • StampedLock,读写锁改进版本,乐观读锁。
    • 对象操作,数据操作,CAS,线程调度,Class操作,系统信息
  • SPI

    • 和普通接口不一样:一个是实现方为了别人使用自己的服务,定义的对外接口。另外一个是调用方角度,调用方自己进行抽象并制定标准接口,实现方根据调用方的接口去提供服务。
    • 依赖ServiceLoader实现。
  • 可能的坑:

    • 泛型
      • List这一类的都会类型擦除,编译器看起来是一样的昂(例如重载的环境下,List都会被认为是相同的参数)。
      • 泛型不能用于catch,无法区别不同的异常类型。
      • 泛型含有静态变量,类型擦除,所有泛型类关联同一份字节码,静态变量共享。
    • 自动装箱和拆箱
      • 整数区间-128到+127,Integer相同。
    • 增强for循环
      • For(Object obj: objs) -> objs.remove(obj),有问题,内部使用Iterator,会fail fast,请使用iterator.remove()来删除。(iterator独立线程,索引表内容不会随objs改变,导致找不到下一个元素)

集合


后端开发小复习
https://alexanderliu-creator.github.io/2023/09/02/hou-duan-kai-fa-xiao-fu-xi/
作者
Alexander Liu
发布于
2023年9月2日
许可协议