Java和Golang的区别

从几方面比较java和golang的差别

Posted by Silence on May 1, 2017

1. 结构体 -> 类

// 包名即为包含该文件的目录名字
package collection

// 声明一个结构体,类似Java中的类
type Stack struct {
    data []string
}

// 声明一个Push函数,并通过一个Stack的指针对象实现该方法
// 类似声明了Stack的成员方法
func (s *Stack) Push(x string) {
    s.data = append(s.data, x)
}

func (s *Stack) Pop() string {
    n := len(s.data) - 1
    res := s.data[n]
    s.data[n] = "" // to avoid memory leak
    s.data = s.data[:n]
    return res
}

func (s *Stack) Size() int {
    return len(s.data)
}
  • 结构体对应Java里的类, 但结构体里只能有变量,不能有方法

  • 方法名称前面的 (stack *Stack) 声明了该方法的接收者,对应Java中的 this

  • := 操作符声明并初始化了一个变量,变量的类型取决于操作符右边的表达式

package collection_test

import (
    "fmt"
    "lambert.com/collection" // 引入包
)

func ExampleStack() {
    var s collection.Stack  // 可以通过包名+结构体的名称使用
    s.Push("world!")
    s.Push("Hello, ")

    for s.Size() > 0 {
        fmt.Print(s.Pop())
    }

    fmt.Println()
}

主要区别

  • 面向对象

    • Go中没有带有构造函数的类,没有实例方法,也没有类继承;只有动态的方法查找,Go只提供了结构体和接口

    • Go允许将方法置于任何类型上,不需要封装;方法的接收者对应Java中的this, 可以是值或指针

    • Go提供了两种访问级别,对应Java中的public和private。以大写字母开头的声明是public的,其他都是包私有的

  • 函数式编程

    • 函数是Go中的一等公民,函数可以在方法的参数上传递
  • 指针和引用

    • Go提供了任意类型的指针,不只是对象和数组

    • Go用nil指向无效指针

    • 数组在Go中是值,当数组作为函数的参数时,函数接受到的是一个数组的拷贝,并不是一个指针。一般,使用slices作为函数参数,slices是引用

    • maps, slices, channels 传递的是引用

  • 内置类型

    • string -> string

    • maps -> HashTable

  • 错误处理

    • Go不使用异常,而使用erros来表示异常情况
  • 缺少的功能

    • 不支持隐式类型转换

    • 不支持函数重载,同一作用域中的函数和方法必须具有唯一的名称

    • 没有泛型

  • 变量声明

    Go Java
    var v int int v = 1;
    var v *int Integer v = null;
    var v string String v = “”;
    var v4 [10]int int[] v4 = new int[10];
    var v5 []int int[] v5 = null;
    var v6 *struct{ a int } class C { int a; } C v6 = null;
    var v7 map[string]int HashMap<String, Integer> v7 = null;
    var v8 func(a int) int interface F { int f(int a); } F v8 = null;
  • 多个变量同时声明

var (
    n int
    x float64
)
  • 函数类型

    在Go中函数是一等公民,可以作为变量

  • for 循环的区别

    • 普通循环
        for i := 0; i < len(a); i++ {

        }
    
1
* 循环,对于数组,slice和字符串来说,i为index,v为值;循环map时,i和v为键值对;循环channel是只有值
    for i, v := range a {
        ...
    }
    
  • switch 的区别

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    
      switch n {
          case 0: // 当n为0时不执行任何操作
          case 1:
              f() // 仅当n为1时执行
      }
    
      switch n {
          case 0, 1:
              f() // f is called if n == 0 || n == 1.
    
    
      switch { // case后面可以是表达式
          case n < 0:
              f1()
          case n == 0:
              f2()
          default:
              f3()
      }}
    
  • 自增和自减

    Go不允许 n = i++ 等类似的操作

  • Defer (延迟)
    • 一个deferred的函数会在它所包围的函数执行完之前调用
    1
    2
    3
    4
    5
    6
    7
    
      func main() {
          defer fmt.Println("World")
          fmt.Println("Hello")
      }
    
      Hello
      World
    
    • deferred调用会在函数panics的时候提前执行
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
      func main() {
          defer fmt.Println("World")
          panic("Stop")
          fmt.Println("Hello")
      }
    
      World
      Stop
    
    
    • 多个deffered函数调用时遵循后进先出的规则
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
      func main() {
          fmt.Println("Hello")
          for i := 1; i <= 3; i++ {
              defer fmt.Println(i)
          }
          fmt.Println("World")
      }
    
      Hello
      World
      3
      2
      1
    
    • deffered函数可以修改包裹它的函数的返回值
    1
    2
    3
    4
    5
    6
    
      func foo() (result string) {
          defer func() {
              result = "Change World" // change value at the very last moment
          }()
          return "Hello World"
      }
    
    • deffered的一般使用场景是来关闭开启的资源
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    
      func CopyFile(dstName, srcName string) (written int64, err error) {
          src, err := os.Open(srcName)
          if err != nil {
              return
          }
          defer src.Close()   // 再执行它
    
          dst, err := os.Create(dstName)
          if err != nil {
              return
          }
          defer dst.Close()   // 函数执行完时先执行它
    
          return io.Copy(dst, src)
    }
    
    
  • Struct

    • 一个结构体指针类似Java中的对象
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    
      type MyStruct struct {
          s string
          n int64
      }
    
      var x MyStruct     // x is initialized to MyStruct{"", 0}.
      var px *MyStruct   // px is initialized to nil.
      px = new(MyStruct) // px points to the new struct MyStruct{"", 0}.
    
      x.s = "Foo"
      px.s = "Bar"