Java: Inheritance
Object Class
Constructors
创建方式:从上方菜单栏找到 Code,然后选中 Generate,快捷键 command + N
在一个“类”中代码的排序为:
- Fields,即各种参数
- Constructors
- All the public methods
如果父级类的 constructor 有参数,则子级类在构建时要用到 super 函数来传递所需要的参数。
Access Modifiers
Public members 在类之外也是可以使用的。
Private members 只能在类内调用,不能被继承。
Protected members 是在同一个包内可用,但可以在不同包的子类中使用。过于复杂,不常用,也应避免使用。
如果没有声明,则是 package private,则只能在同一个包内使用,即使是不同包的子类也不能继承。过于复杂,不常用,也应避免使用。
Overriding Methods
在子类中重写父类的方法。
注意与重载(overloading)区分,重载指的是通过不同的 signature 来实现同一个 method。
在重写的方法前要进行备注,备注方法如下
1 |
Upcasting and Downcasting
Upcasting : 向上转型,转成父类
Downcasting : 向下转型,转成子类
举例:当一个函数需要一个父类作为参数,但传入的是一个子类时,子类会被自动转型为父类,但是在函数内的操作只能有父类包含的操作,没有子类特有的操作。如果要在函数中进行子类的操作,需要再将函数内的父类向下转型为子类。但这样做的风险是,如果传入的参数是父类,函数就会报错。
如下,若把 show(control)
的注释去掉,则会报错。因为每一个 TextBox
都是 UIControl
但不是每一个 UIControl
都是 TextBox
。
1 | public class Main { |
更改后的如下:
1 | public class Main { |
其中 UIControl
为:
1 | public class UIControl { |
其中 TextBox
为:
1 | public class TextBox extends UIControl { |
Comparing Object
1 | public class Main { |
上面的代码会依次输出“false true 994 994”。但若不重写 equals
函数,第二个也会是 false
。
要重写 equals
就要同时重写 hashCode
。
1 | public class Point { |
简单的重写方式为:
- command + N 打开生成面板
- 选择
equals() and hashCode()
- 直接点击
Next
- 选择用于比较的字段
- 选择用于计算哈希值的字段
- 结束
Polimorphism 多态性
解释:允许一个对象有不同的形式
举例:
创建一个新的类:Check Box 并继承 UIControl。
1 | public class CheckBox extends UIControl{ |
此时,在主类中,我们有:
1 | public class Main { |
如果我们想 render(渲染)controls 中的对象,就要用 if 语句来判断对象的类型,这是很麻烦的。因此我们做出如下调整:
在 UIControl 中构造虚拟方法 render:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22public class UIControl {
private boolean isEnabled = true;
public void render() {
}
public UIControl(boolean isEnabled) {
this.isEnabled = isEnabled;
}
public void enable() {
isEnabled = true;
}
public void disable() {
isEnabled = false;
}
public boolean isEnabled() {
return isEnabled;
}
}
在 TextBox 和 CheckBox 中分别实现 render:
TextBox
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25public class TextBox extends UIControl {
private String text = "";
public TextBox() {
super(true);
}
public void render() {
System.out.println("Render TextBox");
}
public String toString() {
return text;
}
public void setText(String text) {
this.text = text;
}
public void clear() {
text = "";
}
}CheeckBox
1
2
3
4
5
6
7
8
9
10public class CheckBox extends UIControl{
public CheckBox() {
super(true);
}
public void render() {
System.out.println("Render CheckBox");
}
}
此时,我们的主函数中只需要如下代码就可以对不同类别的 UIControl 进行 render:
1
2
3
4
5
6
7
8
9public class Main {
public static void main(String[] args) {
UIControl[] controls = { new TextBox(), new CheckBox() };
for(var control : controls) {
control.render();
}
}
}
Abstract Classes and Methods 抽象类和方法
使用情况:我们声明了一个类或方法,但我们不想把它实例化。
抽象类存在的目的:为它的子类提供公共的代码。
当一个类的所有方法都是抽象的时,我们可以用关键词 abstract 把这个类声明为抽象的,abstract 的位置在 class 前。
当一个类被声明为 abstract 时,就不能被实例化了,只能被继承。
当一个方法被声明为 abstract 时,就会要求这个方法所在的类的所有的非抽象子类都要实现该方法。
1 | public abstract class UIControl { |
Final Classes and Methods
当一个类被声明为 final 时,就不能再被继承。非特殊情况下不用。
当一个方法被声明为 final 时,就不能再被重写。
Deep Inheritance Hierarchies 深度继承等级
不要多重继承,不要超过 3 层。
Multiple Inheritance
Python 中,一个类可以有多个父类,这叫做 Multiple Inheritance,但 Java 中并没有这个设定,因为这会导致很多模棱两可的问题。