用写论文的心态写博客
中国的百度百科上对Go语言是这样阐述的:“Go(又称Golang)是Google开发的一种静态强类型、编译型、并发型,并具有垃圾回收功能的编程语言”。维基百科上对Go语言是这样阐述的:“Go (also referred to as Golang) is a statically typed, compiled programming language designed at Google by Robert Griesemer, Rob Pike, and Ken Thompson.Go is syntactically similar to C, but with memory safety, garbage collection, structural typing,and CSP-style concurrency.”。维基百科上翻译过来意思其实和百度百科差不多。不管是百度还是维基都没有直接说Go语言到底是不是一门面向对象的语言。
这一来,就导致了业内对Go语言到底是不是一门面向对象的语言产生了一波讨论。有的认为Go语言没有像Java一样通过Class关键字直接标记类,所以严格意义上来说Go语言不是一门面向对象的编程语言。有的认为Go语言虽然没有直接使用像Java和C#的Class关键字,但是Go语言可以通过一些编程技巧,比如巧妙的使用结构体,接口等,Go语言同样能达到与面向对象同样效果,所以这群人认为Go语言是一门面向对象的编程语言。“公说公有理,婆说婆有理”,笔者比较偏向后者的观点。
业内基本上说面向对象都是说Java,C#等高级编程语言。通过其他语言总结出了面向对象的三大特性:封装、继承和多态。以下是摘自博客园博主韩亦乐的三段文字介绍。
封装,就是把客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操作,对不可信的进行信息隐藏。一个类就是一个封装了数据以及操作这些数据的代码的逻辑实体。在一个对象内部,某些代码或某些数据可以是私有的,不能被外界访问。通过这种方式,对象对内部数据提供了不同级别的保护,以防止程序中无关的部分意外的改变或错误的使用了对象的私有部分。
不知道读者是否学过Java代码,在Java中,我们会经常看到如下代码:一个矩形的简单定义,x代表的是长,y代表的是宽。Rect方法是一个构造函数,getArea方法是一个求该矩形面积函数。private和public代表属性或者方法的访问权限。在Java中,通过关键字private、public、protected、default来控制访问权限,而在Go语言中则是通过申明变量的大小写字母来控制变量和方法的访问权限,字母开头以大写则为包外可见,开头以小写则为包内可见。
public class Rect {
private int x;//矩形的长
private int y;//矩形的宽
public Rect(int x, int y) {//构造函数
this.x = x;
this.y = y;
}
public int getX() {//getter
return x;
}
public void setX(int x) {//setter
this.x = x;
}
public int getY() {//getter
return y;
}
public void setY(int y) {//setter
this.y = y;
}
public int getArea(){//求面积函数
return x * y;
}
}
而在Go语言中,上面的Java代码,则要写成如下。
type Rect struct {
x,y int
}
func (r *Rect) GetArea() int{
return r.x * r.y
}
func NewRect(x, y int) *Rect {
return &Rect{x,y}
}
func (r *Rect) SetX(x int) {
r.x=x
}
func (r *Rect) GetX() int {
return r.x
}
func (r *Rect) SetY(y int) {
r.y = y
}
func (r *Rect) GetY() int {
return r.y
}
对于初学者而言,可能不太明白为什么func后要加(r *Rect),这是因为Go语言比较酷炫的地方。我们把这个叫做“为特定类型定义函数”,也就是说为该类型的对象定义方法。要是大家想了解更多Go中关于函数的知识点,可以参考Go中国的Golang func函数这篇文章。作者写得十分的详细。
继承,指可以让某个类型的对象获得另一个类型的对象的属性的方法。它支持按级分类的概念。继承是指这样一种能力:它可以使用现有类的所有功能,并在无需重新编写原来的类的情况下对这些功能进行扩展。 通过继承创建的新类称为“子类”或“派生类”,被继承的类称为“基类”、“父类”或“超类”。继承的过程,就是从一般到特殊的过程。要实现继承,可以通过 “继承”(Inheritance)和“组合”(Composition)来实现。继承概念的实现方式有二类:实现继承与接口继承。实现继承是指直接使用基类的属性和方法而无需额外编码的能力;接口继承是指仅使用属性和方法的名称、但是子类必须提供实现的能力。
Java中继承是比较常用的。为了给大家更好的比较Java与Go中对继承的设计。我们直接上代码,参考CSDN li_101357的文章。
public class Address {
public int number;
public String Street;
public String City;
public String State;
public String Country;
}
public class Person extends Address{
private String name;
public void Talk(){
System.out.println("Hi!My name is "+name);
}
public void Location(){
System.out.println("I am at "+number+","+Street+","+City+","+State+","+Country);
}
}
那么在Go语言中,上面的代码要写成这个样子。通过下面例子,我们可以看到其实Go语言的设计者在设计过程中,并没有特意去强调继承这一概念,而是通过使用结构体里申明其他结构体的方式来巧妙的避开了继承这个问题。
type Address struct {
Number int
Street string
City string
State string
Country string
}
type Person struct {
Name string
adrs Address
}
func (p *Person) Talk() {
fmt.Println("Hi!My name is ",p.Name);
}
func (p *Person) Location() {
fmt.Println("I am at "+strconv.Itoa(p.adrs.Number)+","+p.adrs.Street+","+p.adrs.City+","+p.adrs.State+","+p.adrs.Country);
}
多态,是指一个类实例的相同方法在不同情形有不同表现形式。多态机制使具有不同内部结构的对象可以共享相同的外部接口。这意味着,虽然针对不同对象的具体操作不同,但通过一个公共的类,它们(那些操作)可以通过相同的方式予以调用。
Java中的多态其实并不难理解,说得简单点就是“向上转型”和“向下转型”。Java多态存在的前提是1)要有继承2)要有重写3)父类引用指向子类对象。我们再来看一段Java代码多态的例子。
public class Main {
public static void main(String[] args) {
Person boy = new Boy("Li Hua");
Person girl = new Girl("Xiao Hong");
List<Person> list = new ArrayList();
list.add(boy);
list.add(girl);
for (int i=0;i<list.size();i++) {
Person person = list.get(i);
person.SayHello();
}
}
}
public class Person{
public void SayHello(){
}
}
public class Boy extends Person {
public String name;
public Boy(String name) {
this.name = name;
}
@Override
public void SayHello() {
super.SayHello();
System.out.println("My name is " + name);
}
}
public class Girl extends Person {
public String name;
public Girl(String name) {
this.name = name;
}
@Override
public void SayHello() {
super.SayHello();
System.out.println("My name is " + name);
}
}
那假如用Go语言又如何实现类似于Java中的多态呢?我们将上面的代码改成用Go来实现。注意同样在定义Person的时候,Java使用的是Class,而Go使用的Interface。
type Person interface {
SayHello()
}
type Boy struct {
Name string
}
type Girl struct {
Name string
}
func (this *Boy) SayHello() {
fmt.Println("My name is ", this.Name)
}
func (this *Girl) SayHello() {
fmt.Println("My name is ", this.Name)
}
func main() {
g := &Girl{"girl"}
b := &Boy{"boy"}
p := map[int]Person{}
p[0] = g
p[1] = b
for _, v := range p {
v.SayHello()
}
}
其实从上面的多态的例子,我们不难发现Go在对多态的代码风格上要比Java更加的简洁。好了,这就是关于Go与Java对面向对象的一些粗略解释。笔者资历尚浅,欢迎批评指正。