Java编程思想重点笔记(Java开发必看)

本文深入探讨了Java编程思想中的关键知识点,包括多态性的理解,is-a关系与is-like-a关系的区别,以及运行时类型信息(RTTI)和反射的运用。内容涵盖构造函数的多态行为、代理模式与动态代理、即时编译器JIT技术,以及final关键字的作用。此外,文章还讨论了策略设计模式与适配器模式的区别,内部类的使用,以及不可变的String类型和序列化控制策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java编程思想,Java学习必读经典,不管是初学者还是大牛都值得一读,这里总结书中的重点知识,这些知识不仅经常出现在各大知名公司的笔试面试过程中,而且在大型项目开发中也是常用的知识,既有简单的概念理解题(比如is-a关系和has-a关系的区别),也有深入的涉及RTTI和JVM底层反编译知识。


1. Java中的多态性理解(注意与C++区分)

  • Java中除了static方法和final方法(private方法本质上属于final方法,因为不能被子类访问)之外,其它所有的方法都是动态绑定,这意味着通常情况下,我们不必判定是否应该进行动态绑定—它会自动发生。

    • final方法会使编译器生成更有效的代码,这也是为什么说声明为final方法能在一定程度上提高性能(效果不明显)。
    • 如果某个方法是静态的,它的行为就不具有多态性:

           
           
           
      1. class StaticSuper {
      2. public static String staticGet() {
      3. return "Base staticGet()";
      4. }
      5. public String dynamicGet() {
      6. return "Base dynamicGet()";
      7. }
      8. }
      9. class StaticSub extends StaticSuper {
      10. public static String staticGet() {
      11. return "Derived staticGet()";
      12. }
      13. public String dynamicGet() {
      14. return "Derived dynamicGet()";
      15. }
      16. }
      17. public class StaticPolymorphism {
      18. public static void main(String[] args) {
      19. StaticSuper sup = new StaticSub();
      20. System.out.println(sup.staticGet());
      21. System.out.println(sup.dynamicGet());
      22. }
      23. }

      输出:

      Base staticGet() 
      Derived dynamicGet()

  • 构造函数并不具有多态性,它们实际上是static方法,只不过该static声明是隐式的。因此,构造函数不能够被override。

  • 在父类构造函数内部调用具有多态行为的函数将导致无法预测的结果,因为此时子类对象还没初始化,此时调用子类方法不会得到我们想要的结果。

       
       
       
    1. class Glyph {
    2. void draw() {
    3. System.out.println("Glyph.draw()");
    4. }
    5. Glyph() {
    6. System.out.println("Glyph() before draw()");
    7. draw();
    8. System.out.println("Glyph() after draw()");
    9. }
    10. }
    11. class RoundGlyph extends Glyph {
    12. private int radius = 1;
    13. RoundGlyph(int r) {
    14. radius = r;
    15. System.out.println("RoundGlyph.RoundGlyph(). radius = " + radius);
    16. }
    17. void draw() {
    18. System.out.println("RoundGlyph.draw(). radius = " + radius);
    19. }
    20. }
    21. public class PolyConstructors {
    22. public static void main(String[] args) {
    23. new RoundGlyph(5);
    24. }
    25. }

    输出:

    Glyph() before draw() 
    RoundGlyph.draw(). radius = 0 
    Glyph() after draw() 
    RoundGlyph.RoundGlyph(). radius = 5

    为什么会这样输出?这就要明确掌握Java中构造函数的调用顺序

    (1)在其他任何事物发生之前,将分配给对象的存储空间初始化成二进制0; 
    (2)调用基类构造函数。从根开始递归下去,因为多态性此时调用子类覆盖后的draw()方法(要在调用RoundGlyph构造函数之前调用),由于步骤1的缘故,我们此时会发现radius的值为0; 
    (3)按声明顺序调用成员的初始化方法; 
    (4)最后调用子类的构造函数。

  • 只有非private方法才可以被覆盖,但是还需要密切注意覆盖private方法的现象,这时虽然编译器不会报错,但是也不会按照我们所期望的来执行,即覆盖private方法对子类来说是一个新的方法而非重载方法。因此,在子类中,新方法名最好不要与基类的private方法采取同一名字(虽然没关系,但容易误解,以为能够覆盖基类的private方法)

  • Java类中属性域的访问操作都由编译器解析,因此不是多态的。父类和子类的同名属性都会分配不同的存储空间,如下:

       
       
       
    1. // Direct field access is determined at compile time.
    2. class Super {
    3. public int field = 0;
    4. public int getField() {
    5. return field;
    6. }
    7. }
    8. class Sub extends Super {
    9. public int field = 1;
    10. public int getField() {
    11. return field;
    12. }
    13. public int getSuperField() {
    14. return super.field;
    15. }
    16. }
    17. public class FieldAccess {
    18. public static void main(String[] args) {
    19. Super sup = new Sub();
    20. System.out.println("sup.filed = " + sup.field +
    21. ", sup.getField() = " + sup.getField());
    22. Sub sub = new Sub();
    23. System.out.println("sub.filed = " + sub.field +
    24. ", sub.getField() = " + sub.getField() +
    25. ", sub.getSuperField() = " + sub.getSuperField());
    26. }
    27. }

    输出:

    sup.filed = 0, sup.getField() = 1 
    sub.filed = 1, sub.getField() = 1, sub.getSuperField() = 0

    Sub子类实际上包含了两个称为field的域,然而在引用Sub中的field时所产生的默认域并非Super版本的field域,因此为了得到Super.field,必须**显式地指明**super.field。

2. is-a关系和is-like-a关系

  • is-a关系属于纯继承,即只有在基类中已经建立的方法才可以在子类中被覆盖,如下图所示: 
     
    基类和子类有着完全相同的接口,这样向上转型时永远不需要知道正在处理的对象的确切类型,这通过多态来实现。

  • is-like-a关系:子类扩展了基类接口。它有着相同的基本接口,但是他还具有由额外方法实现的其他特性。 

    缺点就是子类中接口的扩展部分不能被基类访问,因此一旦向上转型,就不能调用那些新方法。

3. 运行时类型信息(RTTI + 反射)

评论 24
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值