Go没有直接的继承关键字,只能用结构体的匿名组合来实现继承,在实现机制和效果上和Java的继承是有差异的,虽然两者都是在编译期实现的。
示例Go代码:
type People struct {
}
func (p *People) ShowA() {
fmt.Println("showA")
p.ShowB()
}
func (p *People) ShowB() {
fmt.Println("showB")
}
type Teacher struct {
People
}
func (t *Teacher) ShowB() {
fmt.Println("teachershowB")
}
func main() {
t := Teacher{}
t.ShowA()
}
输出:
showA
showB
如果改成对应的Java代码:
public class People {
public void showA() {
System.out.println("ShowA");
this.showB();
}
public void showB() {
System.out.println("ShowB");
}
}
public class Teacher extends People{
public void showB() {
System.out.println("ShowTeacherB");
}
public static void main(String[] args){
Teacher t = new Teacher();
t.showA();
}
}
则输出:
ShowA
ShowTeacherB
为什么会有这种差异呢?因为在编译期,Go的编译器会自动给Teacher生成一个ShowA函数,内部调用一个People实例的showA函数,这样调用顺序是Teacher.ShowA()->People.ShowA()->People.ShowB()。Go的继承在运行时仍然是一个组合关系,Teacher仍然要通过People的实例去调用People的函数。
func (t *Teacher) ShowA() {
t.People.ShowA()
}
Java的编译器则会把People ShowA函数的内容拷贝过来给Teacher生成一个ShowA函数,里面的this在运行时对应的就是Teacher的实例,所以调用顺序是Teacher.showA()->Teacher.showB()。Java在运行时Teacher实例内部不会再有People的实例存在。
public void showA() {
System.out.println("ShowA");
this.showB();
}
附:
Go关于新生成的Teacher.ShowA函数的汇编代码如下。其中调用People.ShowA函数的代码是
“ 0x001c 00028 (<autogenerated>:1) JMP "".(*People).ShowA(SB)”
"".(*Teacher).ShowA STEXT dupok size=40 args=0x4 locals=0x0
0x0000 00000 (<autogenerated>:1) TEXT "".(*Teacher).ShowA(SB), DUPOK|ABIInternal, $0-4
0x0000 00000 (<autogenerated>:1) MOVL TLS, CX
0x0007 00007 (<autogenerated>:1) MOVL (CX)(TLS*2), CX
0x000d 00013 (<autogenerated>:1) CMPL SP, 8(CX)
0x0010 00016 (<autogenerated>:1) JLS 33
0x0012 00018 (<autogenerated>:1) FUNCDATA $0, gclocals·1a65e721a2ccc325b382662e7ffee780(SB)
0x0012 00018 (<autogenerated>:1) FUNCDATA $1, gclocals·69c1753bd5f81501d95132d08af04464(SB)
0x0012 00018 (<autogenerated>:1) FUNCDATA $2, gclocals·9fb7f0986f647f17cb53dda1484e0f7a(SB)
0x0012 00018 (<autogenerated>:1) PCDATA $0, $1
0x0012 00018 (<autogenerated>:1) PCDATA $1, $1
0x0012 00018 (<autogenerated>:1) MOVL ""..this+4(SP), AX
0x0016 00022 (<autogenerated>:1) TESTB AX, (AX)
0x0018 00024 (<autogenerated>:1) PCDATA $0, $0
0x0018 00024 (<autogenerated>:1) PCDATA $1, $0
0x0018 00024 (<autogenerated>:1) MOVL AX, ""..this+4(SP)
0x001c 00028 (<autogenerated>:1) JMP "".(*People).ShowA(SB)
0x0021 00033 (<autogenerated>:1) NOP
0x0021 00033 (<autogenerated>:1) PCDATA $1, $-1
0x0021 00033 (<autogenerated>:1) PCDATA $0, $-1
0x0021 00033 (<autogenerated>:1) CALL runtime.morestack_noctxt(SB)
0x0026 00038 (<autogenerated>:1) JMP 0