OO TB2
一些补充
ArrayList
- 调用:

- 泛型定义 (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
- 使用
extendskeyword - 意义: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
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;
// 实现接口方法
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;
// 重写计数方法
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()。只能通过“接口名”这一个入口进入,不能通过“对象”入口进入。
- Default methods: 允许接口有方法体,可以重写,调用旧版方式:
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 (构造器链)
super(): 调用父类构造器。必须在构造器第一行。
如果没写,编译器默认调用父类的
super()→没构造器public ClassName() { super(); }指定 pass arguments into a call to super(参数列表)
本质初始化父类空间
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
