一些补充

  • ArrayList

    • 调用:

    image-20260402130952536

    • 泛型定义 (Parameterized)ArrayList<Flower> myList = new ArrayList<>();(注意尖括号的使用)。
    • 常用方法表
      • add(Object): 末尾添加。
      • remove(Object)remove(index): 删除。
      • contains(Object): 返回布尔值,查是否存在。
      • indexOf(Object): 查找元素位置。
      • isEmpty(): 判断是否为空。
    • 核心区别ArrayList 是动态扩容的,而 Array 是固定长度的。
  • Design Process … taking inheritance into account

    • Look for objects that have common attributes and behaviours.

    • Design the class (superclass) that represents the common state and behaviour.

    • Decide if a subclass needs behaviours (methods implementation) that are specific to that particular subclass type

    • Look for more opportunities to use abstraction, by finding two or more subclasses that might need common behaviour.

    • Finish the class hierarchy

Part 1: Class Relationships & Inheritance (类关系与继承)

1.1 类与类之间的关系

  • Aggregation (Has-a) / 聚合: Objects are instance variables in the class
  • Inheritance (Is-a) / 继承: Subclasses inherit the properties (attributes and operations) of their superclass
    • 使用 extends keyword
    • 意义:creating subclasses from a superclass (parent class)
    • 特性:A subclass object can be treated as an object of its superclass,并且具有传递性:A 继承 B,B 继承 C,则 A 也是 C,但是是单向的,反向不成立
    • 优点: Avoids duplicating code, allows specialisation by overriding methods

1.2 Access Modifiers (访问权限控制)

  • instance variables and methods

  • By default, you should make all instance variables private

    修饰符 本类内部 同包其他类 不同包子类 不同包非子类 说明
    private not inherited + 子类不可见
    default 只有同包能访问
    protected 专门为继承设计
    public 任何地方均可访问

1.3 Polymorphism (多态)

  • 向上转型 (Upcasting) 定义: Using a single definition (superclass) with different types (subclass)

    • Creature a = new Turtle(); (允许)
    • 可以创建父类类型的数组来存储不同的子类对象Creature[] list = {new Dog(), new Cat()};
  • Downcasting (向下转型): 将父类引用转回子类引用。

    • Dog d = (Dog) a;
    • 风险: 必须确保该引用实际指向的就是该子类对象,否则报运行时错误。

Part 2: Abstract Classes & Interfaces (抽象类与接口)

2.1 Abstract Class (抽象类)

  • 特点: The compiler will not let you instantiate an abstract class(不能 Creature aCreature = new Creature()
  • 用途: The only use it has is in being extended,作为子类的模板。(能 Creature bCreature = new Rabbit(),Creature作为引用的类型,规定方法有哪些)
  • Lots of classes in the API are abstract!
  • Concrete class: non-abstract class is called a concrete class
  • Abstract Method (抽象方法):有抽象方法必是抽象类
    • 特点:没有方法体,the method must be overridden in the child class
    • 要求(Contract):A subclass must implement ALL abstract methods from its superclass (or be declared abstract)
    • 意义:规定必须有的方法,方便放心的统一调用

2.2 Interfaces (接口)

  • 本质: 100% 的抽象类→NO implemented methods(Java 8 之前)→interfaces can’t be instantiated

  • 与类的相似: Both abstract classes and interfaces can contain constants that are inherited;Like classes, interfaces can be extended as well;

  • 与类的不同→多重继承: Java 类只能 extends 一个父类,但可以 implements 多个接口。解决 “Deadly Diamond Problem”。

  • 优点:An interface allows polymorphic capabilities without the problems of multiple inheritance

  • “要求”: If a class implements an interface, but only implements some of its methods, then this class becomes an abstract class ; it cannot be instantiated

  • What happens if interface contain same named methods and variables (constants)?

    • Same named methods:

      • If they have different parameters, then Child interface has both (this is same as overloading).
      • If they differ by only return type, then error.
      • If the two methods are identical, only keep one
    • Same-named constants: we keep both constants. To refer to them, use parent interface name as prefix.→To refer to them, we use: Father.age or Mother.age

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      32
      33
      34
      35
      36
      37
      38
      39
      40
      41
      42
      43
      44
      45
      46
      47
      48
      49
      50
      51
      52
      53
      54
      55
      56
      57
      58
      59
      60
      61
      62
      63
      64
      65
      66
      67
      68
      69
      70
      71
      // 飞行接口
      public interface Flyable {
      // 接口中方法默认就是 public abstract,可省略
      void fly();
      }

      // 生物父类(代码中用到但未定义,补充定义避免编译错误)
      class Creature {}

      // 飞鼠类:继承生物,实现飞行接口
      public class FlyingSquirrel extends Creature implements Flyable {
      // 必须实现接口方法,权限必须是 public
      @Override
      public void fly() {
      // 飞行逻辑
      }

      // 自定义方法
      public void run(int duration) {
      // 奔跑逻辑
      }
      }

      // 计数接口
      public interface Countable {
      // 接口中变量默认:public static final 常量
      int x = 20;
      int y = 30;

      // 接口抽象方法
      void counting();
      }

      // 实现计数接口
      public class Example implements Countable {
      // 子类的成员变量(隐藏接口常量)
      int x = 1;
      int y = 2;
      int sum = 0;

      // 实现接口方法
      @Override
      public void counting() {
      sum = x + y; // 使用本类变量 x=1, y=2
      System.out.println("Sum is " + sum);
      }
      }

      // 继承 Example 并实现 Countable
      public class Example1 extends Example implements Countable {
      int sub = 0;

      // 重写计数方法
      @Override
      public void counting() {
      // 接口常量 y(30) - 父类 Example 的 x(1) = 29
      sub = Countable.y - super.x;
      System.out.println("Sub is " + sub);
      }
      }

      // 测试运行类
      public class ResultOfCount {
      public static void main(String args[]) {
      Example x = new Example();
      x.counting(); // 输出 Sum is 3

      Example1 y = new Example1();
      y.counting(); // 输出 Sub is 29
      }
      }
  • 接口成员:

    • 变量: 默认是 public static final (常量)

      • 在复杂的继承链中,如何精确找到你想要的那个变量?
      • 访问接口常量:使用 接口名.变量名(例如 Countable.y)。
      • 访问直接父类变量:使用 super.变量名(例如 super.x 指向 Example 里的 x)。
      • 访问本类变量:直接写变量名或使用 this.变量名
      • 注意:子类不能修改接口里的变量值
    • 方法: 默认是 public abstract

  • Java 8+ 新特性:

    • Default methods: 允许接口有方法体,可以重写,调用旧版方式:InterfaceName.super.methodName()
    • Static methods: 接口内的工具方法,不能被子类重写,调用方式:InterfaceName.methodName()。只能通过“接口名”这一个入口进入,不能通过“对象”入口进入。

2.3 核心对比:Abstract Class vs Interface

  • Prefer interface over abstract class when no method implementation is provided
  • 如果需要定义变量状态(非静态变量)或部分方法实现,选择 Abstract Class

Part 3: Overriding & Object Class (方法重写与顶层类)

3.1 Method Overriding (方法重写规则)

  • 子类重写父类行为: 使用 @Override 标签。
  • 权限限制: 重写后的方法访问权限不能比父类更严格(例如父类是 public,子类不能是 private)。
  • super.methodName()调用原版
  • 不可重写的情况:
    • private 成员(不可见)。
    • final 方法(禁止重写)。
    • static 方法(属于类,不参与多态重写)。
    • 构造器(Constructor)。

3.2 java.lang.Object (万类之祖)

所有类隐式继承自 Object。常用方法需按需重写:

  • equals(): 默认比较内存地址(==),通常重写为比较内容。
  • toString(): 默认返回 类名@哈希值,建议重写以返回对象属性信息。
  • hashCode(): 返回对象的唯一 ID(通常基于内存地址)。
  • getClass(): 返回运行时的类对象。

Part 4: Memory & Life Cycle (内存管理与生命周期)

4.1 JVM Memory Structure

  • Running a Java program: Memory is obtained by the JVM, from the OS being used

  • Stack (栈): 存储局部变量 (Local variables) 和方法调用 (Stack frame)

    • 动作:每当一个方法被调用,它就会被“压入” (Push) 栈顶。

    • Stack Frame (栈帧):What actually is pushed onto the Stack, contains the state of the method:

      • 局部变量 (Local variables):values of all local variables
      • 执行进度:which line of code is executing
    • 规则

      • LIFO (后进先出):Method goes on top of the Stack when it is called and stays in the Stack until it’s done
      • 销毁:当方法运行到closing curly brace } 时,该栈帧会被“弹出” (Pop),里面的局部变量瞬间消失。
  • Heap (堆): 存储所有 对象 (Objects) 和 实例变量 (Instance variables)

    • Life of Objects: depends only on the life of reference variables referring to it
    • instance variables: live for as long as object they belong to live

4.2 Variable Scope & Life (变量生命周期)

  • 类型

    • 基本类型 (primitive)

    • Reference Variables: 变量在栈中存储的是“地址reference”,指向堆中的对象,而非真实的对象

  • 作用位置

    • Local Variables: 存活于所属方法在栈中的时间,临时

      • Is in scope only within the method where it was declared.
      • Is alive (and maintains its state) but is not in scope when its own method calls another.
      • A variable can only be used when it is in scope
    • Instance Variables: 存活于所属对象在堆中的时间

      第一阶段:在类内 (Inside the Class Body)

      • 规则:只看 Scope
      • 表现:由于实例变量的作用域覆盖全类,你可以直呼其名。
      • 修饰符:在这里毫无存在感(private 也能随便调)。

      第二阶段:在类外 (Outside the Class Body)

      • 规则 1 (Scope):变量名本身已失效(不可直呼其名)。
      • 规则 2 (Path):你必须通过 对象.名 提供路径。
      • 规则 3 (Access)权限修饰符开始接管。
        • 如果是 public:路径通了,门没锁 $\rightarrow$ 访问成功
        • 如果是 private:路径通了,但门锁了 $\rightarrow$ 编译报错 (Access Error)
  • 变量储存在哪里,生命周期只和作用位置有关

    存储位置 对应的变量类型 生命周期(何时 “死”) 管理机制
    Stack (栈) 局部变量 (Local Vars) 极短:随方法调用开始而生,随方法结束(})立即消失。 自动管理:由 CPU 的栈指针控制,速度极快。
    Heap (堆) 对象 (Objects) & 实例变量 较长:只要还有 “引用” 指向它,它就活着。 垃圾回收 (GC):由 JVM 扫描并清理,速度较慢。存储位置

    A local variable that is a reference to an object goes on the Stack (the object it refers to still goes on the Heap)

4.3 Garbage Collection (垃圾回收 GC)

  • 如何分配?Objects in Java are dynamically allocated and created on demand

    • 时间:memory space for an object is allocated at runtime, not at compile time
    • 触发:the new statement causes the memory for an object to be allocated
    • 问题The memory taken up by a program will grow (and shrink) as the program executes
  • 只管引用变量,也就是new出来的对象,基本变量随着消失

  • 回收触发条件: 当一个对象没有活着的引用(Live Reference)指向它时。

    • 引用超出作用域(Permanent exit scope)→局部引用变量
    • 引用被赋值给另一个对象
    • 引用被显式设为 null
      • Unless initialised/assigned to, instance reference variables have a default value of null
      • If you use the dot operator on a null reference, you will get a NullPointerException error at runtime
  • 你已急哭:If a program gets low on memory, the GC will destroy as many eligible objects as possible, to avoid the program running out of RAM

  • Finalizer (析构): finalize() 方法,用于对象销毁前的清理(不推荐依赖)

  • 为什么要学stack&heap

    • variable scope;
    • issues with creating objects;
    • memory management (*);
    • threads (**);
    • exception handling

Part 5: Constructors & Chaining (构造器与调用链)

5.1 Constructor Rules

  • 作用:Initialization
  • 规则:Programmers should always write a “no arguments” constructor
  • Default Constructor: 如果没写构造器,编译器自动补上无参构造器
  • Overloading: 构造器可以重载,但Must have different argument lists (it’s the variable type and order that matters)

5.2 Constructor Chaining (构造器链)

  1. super(): 调用父类构造器。

    • 必须在构造器第一行。

    • 如果没写,编译器默认调用父类的 super()→没构造器public ClassName() { super(); }

    • 指定 pass arguments into a call to super(参数列表)

    • 本质初始化父类空间

  2. this(): 调用本类其他重载构造器。

    • 必须在构造器第一行。

    • 从其他构造器接入super

    • super()this() 不能同时出现在同一个构造器内

5.3 子类对象内存布局——分层结构

  • 物理事实:当你 new 一个 SubClass 对象时,triggers a chain reaction of constructors being run implicitly**(all the constructors in its inheritance tree must be run)**,内存中holds both its own declared instance variables and everything from its superclasses
  • Every class in Java extends class Object (java.lang.Object)
  • 结论:An object is only completely formed when all the superclass parts of itself are formed