建構子
子類別預設呼叫super()
以下看似什麼都沒有做。
1
2
class Father {}
class Child extends Father {}
但實際上子類別的建構子,會先呼叫super()父類別無參數建構子super,建立完父類別,才建立自己。
1
2
3
4
5
6
7
8
9
class Father {
public Father() { }
}
class Child extends Father{
public Child() {
super(); // 先呼叫父類別無參數建構子,建立父類別
// 建立完父類別,才建立自己
}
}
如果父類別沒有無參數建構子,會產生錯誤。
父類別沒有無參數建構子
以下父類別沒有無參數建構子Parent() {}
1
2
3
4
5
6
7
8
9
10
11
public class Parent {
String name;
int age;
Parent(String name) {
this.name = name;
}
Parent(String name, int age) {
this.name = name;
this.age = age;
}
}
子類別繼承父類別,會產生錯誤。
1
public class Child extends Parent {}
原因是,父類別沒有無參數建構子Parent() {}
,編譯器在編譯時,會添加super()在子類別的建構子中。
以下是編譯器自動增加的:
1
2
3
4
5
public class Child extends Parent{
Child() {
super(); //父類別沒有無參數建構子,所以產生error
}
}
解決辦法
子類別呼叫任何一個有參數的父建構子
在 Java 中,當一個類別(Child)繼承自另一個類別(Parent),而父類別沒有無參數的建構函式(default constructor)時,子類別必須明確地呼叫父類別的某個建構函式(使用 super(…))。
不管如何,子類別至少呼叫任何一個有參數的父建構子。
1
2
3
4
5
public class Child extends Parent{
Child(String name) {
super(name);
}
}
父類別加上無參數建構子
父類別加上無參數建構子
1
2
3
4
5
6
7
8
9
10
11
12
public class Parent {
String name;
int age;
Parent(String name) {
this.name = name;
}
Parent(String name, int age) {
this.name = name;
this.age = age;
}
Parent() {}
}
子類別就無需呼叫父類別的無參數建構子,編譯器會自動產生在程式碼。
1
2
public class Child extends Parent{
}
父類別與子類別建立順序
建立Child
1
2
3
public static void main(String[] args) {
Child child = new Child();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class Grandpa {
public Grandpa() {
// 3.建立Grandpa
System.out.println("Grandpa無參數建構子");
}
}
class Father extends Grandpa{
public Father() {
super(); // 2.先呼叫父類別無參數建構子
// 4. 建立Father
System.out.println("Father無參數建構子");
}
}
class Child extends Father{
public Child() {
super(); // 1.先呼叫父類別無參數建構子
// 5. 建立Child
System.out.println("Child無參數建構子");
}
}
Grandpa無參數建構子
Father無參數建構子
Child無參數建構子
子類別有參數建構子呼叫順序
執行以下程式碼,執行順序是什麼?
1
2
3
public static void main(String[] args) {
Child child = new Child("Momo");
}
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
class Grandpa {
public Grandpa() {
// 3.建立Grandpa
System.out.println("Grandpa無參數建構子");
}
}
class Father extends Grandpa{
public Father() {
super(); // 2.先呼叫父類別無參數建構子
// 4. 建立Father
System.out.println("Father無參數建構子");
}
}
class Child extends Father{
public Child() {
super();
System.out.println("Child無參數建構子");
}
public Child(String name) {
super(); // 1.先呼叫父類別無參數建構子
// 5. 建立Child
System.out.println("Child有參數建構子");
}
}
Grandpa無參數建構子
Father無參數建構子
Child有參數建構子
注意!呼叫有參數的建構子,不會再去呼叫無參數建構子。
this()呼叫無參數建構子
執行以下程式碼,執行順序是什麼?
1
2
3
public static void main(String[] args) {
Child child = new Child("Momo");
}
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
class Grandpa {
public Grandpa() {
// 4.建立Grandpa
System.out.println("Grandpa無參數建構子");
}
}
class Father extends Grandpa{
public Father() {
super(); // 3.先呼叫父類別無參數建構子
// 5. 建立Father
System.out.println("Father無參數建構子");
}
}
class Child extends Father{
public Child() {
super();// 2.先呼叫父類別無參數建構子
// 6.
System.out.println("Child無參數建構子");
}
public Child(String name) {
this(); // 1.呼叫無參數建構子
// 7. 這裡執行完有參數建構子,才建立Child
System.out.println("Child有參數建構子");
}
}
Grandpa無參數建構子
Father無參數建構子
Child無參數建構子
Child有參數建構子
super()與this()只能擇一,且只能放第一行
以下編譯錯誤
1
2
3
4
5
6
7
8
9
10
class Child extends Father{
public Child() {
super();
}
public Child(String name) {
this();
super();
// this與super只能擇一
// 且只能在第一行,super不能放在第二行
}
最後一定會呼叫Object()
所有建構子,最後一定會呼叫Object()建構子,因為Object是所有類別的父類別。
滑鼠對著子類別名稱,按下ctrl + h,出現以下階層圖,可以由此圖知道Object是所有類別的父類別。
以下為呼叫過程圖,最後會在Heap中建立一個記憶體空間0x00055,包含每個父類別的「屬性」,而父類別「們」的方法則存放在metadata的vtable中。
匿名程式碼區塊
英文是Anonymous code blocks
{}花括號裡面的內容,就是匿名程式碼區塊
{
// 花括號裡面的內容
}
先執行匿名程式碼區塊,再執行建構子
建立物件時,會先執行匿名稱式碼區塊,再執行建構子
1
2
3
4
5
6
7
8
9
10
11
public class Test {
{
System.out.println("匿名區塊");
}
Test() {
System.out.println("建構子區塊");
}
public static void main(String[] args) {
Test test = new Test();
}
}
匿名區塊
建構子區塊