欢迎光临
我们一直在努力

【小白学习系列】Java编程思想第5章趟坑笔记

一、变量初始化相关

  • 成员变量有默认值,局部变量完全无默认值(最大误区)
    新手错觉:所有变量不用赋值也能使用。
    真相:

    • 类成员(实例变量、静态变量):系统自动赋默认值(数值0、布尔false、对象null);
    • 方法内局部变量:不会自动初始化,不手动赋值直接使用编译报错。
      反常识:哪怕是int a;局部变量,打印、运算都会报错,不会默认给0。
  • 初始化顺序:静态 > 实例 > 构造器,构造器不是最先执行
    执行顺序:
    静态变量赋值 → 静态代码块 → 实例变量赋值 → 实例代码块 → 构造方法
    坑:在构造器里读取静态变量没问题,但如果静态代码块依赖还未加载的实例,会出现null/0异常。

  • 父类静态内容先于子类所有代码执行
    子类new对象时:先执行父类静态、再子类静态;再父类实例、父构造,最后子类实例、子类构造。
    易错:以为子类静态比父类先初始化。

  • 二、构造器相关反常识坑

  • 子类构造器默认隐式调用父类无参构造super(),且必须第一行

    • 父类只写了带参构造、无无参构造时,子类不写super(参数)直接编译报错;
    • super()必须放在构造方法第一行,前面不能写任何代码。
  • 构造器没有返回值,不能写void/任何返回类型
    新手容易误写void Test(){},这不再是构造器,只是普通方法,new时不会执行。

  • 构造器可以私有(单例模式),普通方法不行靠私有实现单例
    反常识:构造器修饰符支持private,禁止外部new本类对象。

  • 三、final三重语义极易混淆(本章重点坑)

  • final修饰三种东西完全不同,新手混为一谈
    • final 基本变量:值不可修改;
    • final 引用变量:引用地址不能变,但对象内部属性可以改(大坑);
      例:final List<Integer> list = new ArrayList<>(); list.add(1); 合法,只是不能list = 新集合。
    • final 方法:不能被子类重写;
    • final 类:禁止继承。
  • 四、代码块(静态块/实例块)易错点

  • 实例代码块每次new对象都会执行;静态代码块仅类加载执行1次
    误区:以为静态块每次创建实例都会跑。

  • 实例代码块可以访问实例变量,静态代码块不能直接访问非静态成员
    静态块中调用实例属性/实例方法,编译报错。

  • 五、清理、垃圾回收、finalize(经典反常识)

  • finalize() 不可靠,绝对不能用来释放资源
    新手误区:重写finalize关闭流、数据库连接。
    真相:JVM不保证finalize一定会执行,执行时机不确定,OOM时可能直接跳过,生产环境禁止依赖。

  • 对象不会立刻被GC,没有手动销毁对象的语法
    没有类似C++ delete关键字,把引用置为null只是帮助GC,不代表立即回收。

  • 循环内创建大量对象,不会立刻释放,容易内存堆积
    新手以为循环结束对象自动消失,短期大量创建会造成GC频繁。

  • 六、数组初始化坑

  • 数组作为成员变量默认初始化为null,数组内元素有默认值int[] arr; // 局部变量,无默认值,不能使用
    int[] arr2; // 成员变量,默认null
    int[] arr3 = new int[5]; // 数组内每个元素默认0

    易错:直接操作成员数组arr2[0],报空指针。

  • 七、方法参数初始化、重载构造器

  • 构造器互相调用this(参数),同样必须放在第一行,且不能和super共存
    一个构造器要么this调用本类其他构造,要么super调用父类,二者只能选其一。

  • 初始化表达式、代码块先于构造器执行
    实例变量赋值、{}实例块,都在构造器代码之前运行。
    陷阱:构造器修改了同一个变量,会覆盖前面初始化的值。

  • 八、隐藏小反常识点

  • 基本类型包装类成员变量默认是null,不是0

    Integer num; // 成员默认null
    int num2; // 成员默认0

    直接调用num.intValue() 空指针,新手高频bug。

  • 静态变量属于类,所有实例共享一份
    修改任意对象的静态变量,全部对象读取都会变化,很多人误以为每个实例独立一份。

  • 九、习题巩固

    第1题
    题目:下列关于变量默认初始化说法正确的是?
    A. 方法内局部int变量默认值为0
    B. 类的实例Integer成员变量默认值为0
    C. 静态成员变量会自动赋予默认初始值
    D. 局部对象变量默认值为null
    正确答案:C
    解析:
    A 错误:局部变量无默认值,不赋值直接使用编译报错;
    B 错误:Integer是包装类引用,成员默认null,不是0;
    C 正确:静态变量、实例成员变量都会由JVM自动赋予默认初始值;
    D 错误:局部引用变量没有默认值,不存在自动null。

    第2题
    题目:类初始化执行顺序正确的是?
    A. 实例变量 → 静态代码块 → 构造器
    B. 静态变量赋值 → 静态代码块 → 实例变量赋值 → 实例代码块 → 构造器
    C. 构造器最先执行
    D. 实例代码块先于静态代码块执行
    正确答案:B
    解析:
    类加载阶段先处理静态相关:静态变量赋值 → 静态代码块(仅执行一次);
    创建对象时执行实例相关:实例变量赋值 → 实例代码块 → 构造方法。
    A、C、D顺序全部颠倒错误。

    第3题
    题目:关于final修饰引用变量,代码final List<String> list = new ArrayList<>();下列操作合法的是?
    A. list = new ArrayList<>();
    B. list.add(“test”);
    C. list = null;
    D. list.clear()之外所有修改集合的操作都报错
    正确答案:B
    解析:
    final修饰引用变量,限制的是引用地址不可变,不限制对象内部内容修改。
    A、C:试图重新赋值list引用,编译报错;
    B:往集合添加元素,修改集合内部,完全合法;
    D:错误,add、remove、clear等修改集合元素都允许。

    第4题
    题目:子类构造器相关描述错误的是?
    A. 子类构造第一行默认隐式调用super()
    B. super()与this()不能同时出现在一个构造器内
    C. 若父类只有带参构造,子类不写super(参数)也能编译通过
    D. this()调用本类其他构造必须放在方法第一行
    正确答案:C
    解析:
    A:正确,子类构造器首行默认隐藏super()调用父类无参构造;
    B:正确,super()和this()都要求放在第一行,二者无法共存;
    C:错误,父类不存在无参构造时,子类必须手动写super(对应参数),否则编译报错;
    D:正确,this()调用同类其他构造必须放在构造方法第一行。

    第5题
    题目:有关静态代码块与实例代码块说法正确的是?
    A. 每次new对象都会执行静态代码块
    B. 静态代码块可以直接访问实例成员变量
    C. 实例代码块在构造器代码执行前运行
    D. 实例代码块仅在类加载时执行一次
    正确答案:C
    解析:
    A 错:静态代码块只在类加载时执行1次,多次new不会重复执行;
    B 错:静态上下文无法直接访问实例成员,编译报错;
    C 对:实例变量赋值、实例代码块{} 都在构造器内部代码之前执行;
    D 错:实例代码块每次创建对象都会执行。

    第6题
    题目:关于finalize()方法,描述正确的是?
    A. 可以依靠finalize释放文件、数据库连接等资源
    B. JVM一定会在对象回收前执行finalize()
    C. finalize执行时机完全不可控,不能用于资源清理
    D. 对象置为null后会立刻触发finalize执行
    正确答案:C
    解析:
    A 错误:finalize执行时机不确定,甚至可能不执行,不能用来释放资源;
    B 错误:JVM不保证finalize一定执行,内存耗尽时可能直接丢弃对象;
    C 正确;
    D 错误:引用置null只是让对象可被GC,不会立刻触发回收与finalize。

    第7题
    题目:下列代码会编译报错的是?
    A. 构造方法 private Test(){}
    B. void Test(){}
    C. Test(){super();}
    D. Test(){int a = 10;}
    正确答案:B
    解析:
    A:构造器可以用private修饰,用于单例,合法;
    B:void Test(){} 带有返回值void,不再是构造方法,只是普通成员方法,该写法会导致new时不会执行这个方法,属于典型错误写法;
    C:构造器第一行写super()显式调用父类无参构造,合法;
    D:构造器内先定义局部变量,无问题。

    第8题
    题目:下面关于成员变量默认值说法错误的是?
    A. int 实例成员变量默认值为0
    B. Boolean 静态成员变量默认值为null
    C. boolean 实例成员变量默认值为false
    D. Integer局部变量默认值为null
    正确答案:D
    解析:
    A 正确:基本类型int成员默认0;
    B 正确:Boolean是包装类,引用类型成员默认null;
    C 正确:基本boolean成员默认false;
    D 错误:局部变量没有任何默认值,不会自动赋值null,直接使用编译报错。

    第9题
    题目:下列关于构造器中 this() 描述正确的是?
    A. this() 可以写在构造方法任意一行
    B. 一个构造器可以同时调用 this() 和 super()
    C. this() 作用是调用本类其他构造方法
    D. 静态方法里可以使用 this()
    正确答案:C
    解析:
    A 错误:this() 必须放在构造器第一行,前面不能写任何代码;
    B 错误:this() 和 super() 都要求首行,二者不能共存;
    C 正确;
    D 错误:this、this() 都依赖实例,静态方法没有实例,无法使用。

    第10题
    题目:有如下代码结构,创建子类对象时执行顺序正确的是?
    class Parent{
    static {System.out.println(“父静态块”);}
    {System.out.println(“父实例块”);}
    Parent(){System.out.println(“父构造”);}
    }
    class Son extends Parent{
    static {System.out.println(“子静态块”);}
    {System.out.println(“子实例块”);}
    Son(){System.out.println(“子构造”);}
    }
    A. 父静态块 → 子静态块 → 父实例块 → 父构造 → 子实例块 → 子构造
    B. 父静态块 → 父实例块 → 父构造 → 子静态块 → 子实例块 → 子构造
    C. 子静态块 → 父静态块 → 父实例块 → 父构造 → 子实例块 → 子构造
    D. 父静态块 → 子静态块 → 子实例块 → 子构造 → 父实例块 → 父构造
    正确答案:A
    解析:

  • 类加载阶段:先加载父类执行父静态块,再加载子类执行子静态块(静态只执行一次);
  • 创建实例阶段:先初始化父类实例:父实例代码块 → 父构造方法;
  • 再初始化子类实例:子实例代码块 → 子构造方法。
    完整顺序对应选项A。
  • 第11题
    题目:下列描述错误的是?
    A. 静态代码块只能访问静态变量、静态方法
    B. 实例代码块可以访问静态成员
    C. 局部基本变量不赋值也能直接打印
    D. 引用类型成员变量默认值为null
    正确答案:C
    解析:
    A 正确:静态上下文没有实例,不能直接访问实例成员,只能访问静态;
    B 正确:实例代码块同时持有类与实例上下文,静态成员可随意访问;
    C 错误:局部变量无默认值,不赋值直接使用编译报错;
    D 正确:所有引用类型成员变量默认初始值都是null。

    第12题
    题目:代码:final Integer num = 10; 后续操作合法的是?
    A. num = 20
    B. Integer temp = num;
    C. num = null
    D. num++
    正确答案:B
    解析:
    final修饰基本类型变量,变量存储的值不可修改。
    A:num=20 试图重新赋值final变量,编译报错;
    B:Integer temp = num; 只是拷贝数值,完全合法;
    C:给final变量赋null,编译报错;
    D:num++等价于num = num + 1,修改final变量,编译报错。
    核心知识点:final修饰基本变量,值全程不能修改,只能读取,不能二次赋值、自增自减。

    第13题
    题目:以下关于数组初始化说法错误的是?
    A. int[] arr; 作为成员变量,默认值为null
    B. int[] arr = new int[3]; 数组内部每个元素默认0
    C. Integer[] arr; 局部变量,直接调用arr[0]不会报错
    D. Integer[] arr = new Integer[2]; 数组元素默认null
    正确答案:C
    解析:
    A 正确:数组是引用类型,成员变量默认null;
    B 正确:基本类型数组元素默认值为0;
    C 错误:arr是局部变量,无默认值,未赋值直接使用编译报错;
    D 正确:包装类数组内部元素默认null。

    第14题
    题目:下面关于静态变量特点描述正确的是?
    A. 每个对象都拥有一份独立静态变量
    B. 修改任意实例的静态变量,所有实例读取结果都会变化
    C. 静态变量只能在静态代码块中赋值
    D. 静态变量不具备默认初始值
    正确答案:B
    解析:
    A 错误:静态变量属于类,全局共享,不存在每个实例独立副本;
    B 正确;
    C 错误:静态变量可直接定义时赋值、静态块赋值;
    D 错误:静态成员变量会自动赋予默认值。

    赞(0)
    未经允许不得转载:171主机测评 » 【小白学习系列】Java编程思想第5章趟坑笔记
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址