重新入门一下Java,这次,离开了Spring,我必不可能还是废物。

基本编程结构

面向对象编程

  • 除去几个基本类型,所有的值都是对象,所有的变量都是引用。
  • this指针。
  • 默认初始化:0, false, null。
  • final变量,不会再修改的变量,但注意它只是引用,更改目标的属性是可以的。
  • 静态初始化块,通常用来初始化static数组。
  • import static java.lang.Math.*,可以不需类名地使用Math静态方法。
  • 嵌套类,声明在类内部,并且带static修饰,只是多了访问限制。
  • 内部类,没有static,每个内部类对象都有外部类对象的引用,由此可访问外部的类成员。

接口和lambda表达式

  • 接口的所有方法默认为public,也可以提供默认实现。

  • Java强制类型转换,为了避免运行时错误,可先用instanceof检测类型。

  • 继承接口,extends。

  • 一个类可以implements多个接口。

  • 定义在接口中的变量,都是public static final,即常量。接口无法定义实例变量,原因是它不描述状态。

  • 默认方法使得添加接口方法能和以前的实现兼容,旧的类不需要强制实现新的方法。

  • 当从多个接口继承默认方法时,可能会发生冲突,此时需要程序员显式地在子类中重新实现该方法。此时可通过super将实现委托给父类。

    1
    public int getId() { return Identified.super.getId(); }
  • 从java9开始,接口可以有私有方法,通常用来辅助实现default方法。

  • Runnable、Comparator等接口,都只有一个抽象方法。这样的接口被称为函数式接口。Lambda可以简化对函数式接口的使用,一个临时匿名接口实现。

继承与反射

  • Java使用extends派生一个新类,不支持多继承。

    • Python有专门的算法处理菱形继承、交叉继承。
    • Cpp支持多继承,使用虚继承处理冗余,调用方法时则需要显式指明。
    • Dart支持Mix-in,多继承时,只允许有一个可实例化的父类,其他的都是抽象父类,只有方法。有点像同时继承了类和接口,而接口又有默认实现。
  • 子类只能使用父类的public、protected部分,虽然连带private一起继承会多很多有用方法,但破坏了封装性,让父类开发不能随心所欲地修改private部分了。

  • 子类必须调用父类的构造函数来初始化,如果没有显式写出,则会使用不带参数的默认构造。

  • 子类对象可以被赋值给父类变量,Java的动态方法查找会让子类覆盖方法正常运行。

  • final方法不可被覆盖,final类不可被继承。

  • 抽象类,不能实例构造,比接口多了实例变量和构造函数。

  • 匿名类,将子类实现直接贴出。双重大括号语法可用来初始化匿名类对象。

  • 从类和接口继承了相同的方法时,Java优先使用类方法,不给出编译错误。

  • super关键字用来访问父类的方法和变量。

  • 所有的类都继承自Object,所以它们都有如下方法。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    String toString() # 默认打印类名和hashcode
    boolean equals(Object other)
    int hashCode() # 相等的对象必须有相同的hashCode
    Class<?> getClass()
    protected Object clone()
    protected void finalize()
    wait()
    notify()
    notifyAll()
  • 枚举类型

    • 每个枚举常量都是一个匿名子类,可以有构造函数、方法和域。
    • 枚举常量初始化在静态成员之前,因此不能在构造函数里引用静态成员,可以在static块中初始化。
    • switch枚举。
  • 运行时类型信息和资源:Class对象有一些方法帮助获取类型、方法信息。

异常、断言和日志处理

泛型编程

  • Java的泛型编程是发布后新加入的特性,为了兼容曾经的代码,使用了一个名为类型擦除的技术。
    • 在编译阶段,泛型的类型信息都会被擦除,只有泛型声明的信息保留。因此,getClass得不到运行时T的类型信息。
    • 在擦除之后,所有的类型都是Object或者Arraylist<Object>。除非声明时有类型限定,则用限定的类型替换Object。
  • 类型擦除和多态的冲突
    • 选定一个类型声明一个确定的类,比如C<String>,然后继承这个类后重写泛型方法,将参数改为String,此时希望子类能够在调用时应用多态特性,调用重写的子类方法,但是,String会被擦除,变成Object去处理,JVM无法按照String签名去查找方法。为了解决这个问题,JVM引入了桥方法。即产生一个参数为Object的方法,转换类型后再调用我们重写的方法,这样可以保证JVM在动态查找时,能够找到对应的方法,同时又是按照类型调用相应的方法,实现了多态。
  • 泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数。

集合