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:路径通了,门没锁 访问成功。 - 如果是
private:路径通了,但门锁了 编译报错 (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
