Java漫游笔记-03-02-对象和类的知识点

对象构造过程

  1. 所有属性,如果在声明中没有明确赋值,则初始化为缺省值( 0falsenull );
  2. 按照声明次序,依次执行 static 语句(块);(仅在类首次被加载的时候,执行一次,并且,如果该类继承自某个类,则先执行父类的static 语句)
  3. 按照声明次序,依次执行对象语句块(类似的,如果该类继承自某个类,则先执行父类的语句块);
  4. 执行构造方法(如果在一个构造方法中,有调用另外一个构造方法,则先执行被调用的方法主体)。

方法调用过程

方法调用并不等同于方法执行,而是确定被执行的方法版本的过程。
方法调用有解析和分派(Dispatch)两种类型。
如果被调用的方法,在真正运行前就已经确定,并且在运行期不可变,这类方法的调用就称为解析。
而分派又可以分为静态分派和动态分派。
静态分派会根据传入参数的静态类型选择被调用方法的执行版本。对于同一个类或接口中的重载(Overload)方法,会采用静态分派。
动态分派则会根据调用者的实际类型选择被调用方法的执行版本。子类对父类的覆盖(Override)方法,会采用动态分派。

  1. 如果是 privatestaticfinal 方法或者是构造方法,那么在编译期就能够确定方法的执行版本,等到类加载阶段就可以解析成直接引用;
  2. 静态分派也是在编译期完成的,它和解析并不是排它关系(想想静态方法也是可以重载的),它们分别在不同层次上去确定方法的执行版本;
  3. 而动态分派则是在运行时完成的,执行引擎首先会根据类名、方法名,获取所有的候选方法。然后,再根据方法的参数列表,挑选出最合适的方法(如果同一个方法签名能够匹配到 0 个或者是多个方法,都会报错)。挑选的时候,首先会在实际类型中寻找匹配的方法,否则在父类中继续查找。因为每次调用方法都需要进行搜索,因此,虚拟机会预先为每个类创建一个方法表(一般发生在类加载的链接阶段),来提升性能。

其它

  • 使用 this 关键字,显式地区别对象的属性和局部变量。
  • 对象的属性会初始化为缺省值(如果不嫌麻烦,明确初始化值更好),而局部变量则不会。
  • 使用 gettersetter 方法来操纵对象的属性的主要好处是:增强了类的封装性,它提供了修改类内部实现的可行性。
  • static 变量,属于类变量,为该类所有对象所共享,每个对象都有一份自己的拷贝。
  • 使用 static 变量和 static 方法时,都应使用类名来调用。
  • Java 的方法都是传值调用(call by value),如果方法的参数是一个对象的引用,那么传递的也只是这个引用的一份拷贝。(不妨考虑一下:在一个方法内交换2个对象引用的例子:swap(User a, User b))。
  • 直接返回一个对象的引用时,一定要慎重,因为这可能会破环封装性,不妨考虑一下,能否只是返回该对象的一个克隆作为替代。
  • Java 通过包( package )机制来组织类,相当于命名空间的作用,可以避免类名的冲突。但是这由产生了另外一个问题,就是使用一个类时,需要书写完整的类名,非常繁琐。因此,又有了 import 。通过 import 事先告诉编译器应该去哪里查找某个类,从而达到了简写的目的。精确导入一个类,不会减少代码的大小,但是可以减少编译的时间,也有利于阅读(特别是打印出来的时候)。
  • finalize 方法会在垃圾回收器清除对象之前调用,但是由于很难确定它真正的调用时机,所以不要使用它
  • 封装性是提升类的重用性和可靠性的保证。应尽量私有化属性和方法,因为一旦公开,也就意味着不受控制,不可修改。
  • 应尽可能地减少类和类之间的依赖,也就是所谓的“低耦合”
  • 继承,体现了“is a”的关系。主要的好处是:代码复用
  • 抽象类是不完整的(接口也是如此,就好像一张未完成的蓝图),因此,不要尝试使用它来构造对象(在使用匿名类的时候可能会产生错觉)。但是,通过声明抽象类或接口类型的变量,来实现多态是可取的。
  • 抽象方法,没有方法体,就好比先圈好地,然后等着子类来盖楼。
  • 关于访问控制:private - 默认(也就是不写修饰符) - protected - public ,封闭性递减。

暂时先这么多吧,后面想到再补充。