一、面向对象
1.Java是纯正的面向对象语言,Go相对于Java而言,就比较简洁,没有例如类的继承、接口的实现、构造函数和析构函数、隐藏的 this 指针等,也没有 public、protected、private 之类的访问修饰符。
2.类型系统
类型系统是指一个语言的类型体系结构。一个典型的类型系统通常包含如下基本内容:
(2)在 Go 语言中,只要两个接口拥有相同的方法列表(与顺序无关),那么它们就是等同的,可以相互赋值。不过,这里有一个前提,那就是接口变量持有的是基于对应实现类的实例值,所以接口与接口间的赋值是基于类实例与接口间的赋值的。
此外,接口赋值并不要求两个接口完全等价(方法完全相同)。如果接口 A 的方法列表是接口 B 的方法列表的子集,那么接口 B 也可以赋值给接口 A。
8.类型断言
(1)Java提供了 instanceof 关键字来进行接口和类型的断言,这种断言其实就是判定一个对象是否是某个类(包括父类)或接口的实例。
(2)Go没有提供类似的关键字,而是通过类型断言运算符 .(type) 来实现,其中 type 对应的就是要断言的类型。
注意:在 Go 语言结构体类型断言时,子类的实例并不归属于父类,即使子类和父类属性名和成员方法列表完全一致,因为类与类之间的「继承」是通过组合实现的,并不是 Java中的父子继承关系。父类实现了某个接口,不代表组合类它的子类也实现了这个接口。(其实这里已经和传统的面向对象编程中的父子类完全不是一个概念了,其本质原因就是 Go 使用了组合而非继承来构建类与类之间的关联和层次关系。)
(3)Go还可以基于反射在运行时动态进行类型断言,使用 reflect 包提供的 TypeOf 函数即可实现。
对于基本数据类型,比如 int、string、bool 这些,不必通过反射,直接使用 variable.(type) 表达式即可获取 variable 变量对应的类型值
9.空接口
(1)Java号称血统最纯正的面向对象编程语言中,「万事万物皆对象」,所有类都继承自Object类型,所以 Object 类型变量可以指向任何类的实例。
(2)Go 语言打破了传统面向对象编程中类与类之间继承的概念,而是通过组合实现方法和属性的复用,所以不存在类似的继承关系树,也就没有所谓的祖宗类,而且类与接口之间也不再通过 implements 关键字强制绑定实现关系,所以 Go 语言的面向对象编程非常灵活。
在 Go 语言中,类与接口的实现关系是通过类所实现的方法在编译期推断出来的,如果我们定义一个空接口的话,那么显然所有的类都实现了这个接口,反过来,我们也可以通过空接口来指向任意类型,从而实现类似 Java 中 Object 类所承担的功能,而且显然 Go 的空接口实现更加简洁,通过一个简单的字面量即可完成:
注意:空接口和接口零值不是一个概念,前者是 interface{},后者是 nil。
10.反射和泛型
(1)Java支持反射,最典型的应用场景就是IOC容器。
(2)Go 也支持反射功能,并且专门提供了一个 reflect 包用于提供反射相关的 API。reflect 包提供的两个最常用、最重要的类型就是 reflect.Type 和 reflect.Value。前者用于表示变量的类型,后者用于存储任何类型的值,分别可以通过 reflect.TypeOf 和 reflect.ValueOf 函数获取。
(3)Java自1.5之后支持泛型。
(4)Go没有在语言层面支持泛型,可以通过空接口结合反射实现。
二、 错误处理
1.error类型
(1) Java中Throwable是所有错误或异常的超类,其下又分为Error和Exception两个大的分类。Error错误,表示Java系统内部和资源耗尽的错误,不会抛出该类异常,只会告知用户然后终止程序运行。Exception又分作运行时异常RuntimeException和检查异常CheckedException,运行时异常是正常抛出的错误,而检查异常是外部错误,需要程序去捕获。
(2)Go 语言为错误处理定义了一个标准模式,即 error 接口,其中只声明了一个 Error() 方法,用于返回字符串类型的错误消息。:
关于自定义并返回 error 类型错误信息,可以通过 Go 标准错误包 errors 提供的 New() 方法快速创建一个 error 类型的错误实例。
2.defer语句
Go中的defer语句相当于Java中的final语句,不同的是,defer语句的个数没有限制,而且最后执行时按照后入先出的顺序执行所有的defer语句。
defer语句要写在方法最前面,防止后面的代码中断执行后程序感知不到。
defer语句后也可以加一个匿名函数来执行复杂的语句。
3.panic和recover
当代码运行时出错,而又没有在编码时显式返回错误时,Go 语言会抛出 panic,类似Java的RuntimeException.
无论是 Go 语言底层抛出 panic,还是我们在代码中显式抛出 panic,处理机制都是一样的:当遇到 panic 时,Go 语言会中断当前协程(即 main 函数)后续代码的执行,然后执行在中断代码之前定义的 defer 语句(按照先入后出的顺序),最后程序退出并输出 panic 错误信息,以及出现错误的堆栈跟踪信息。
还可以通过 recover() 函数对 panic 进行捕获和处理,从而避免程序崩溃然后直接退出,而是继续可以执行后续代码,实现类似 Java中 try…catch 语句的功能。
可以类比为 panic、recover、defer 组合起来实现了传统面向对象编程异常处理的 try…catch…finally 功能。