Go和Java异同总结(项⽬开发和数据类型)
⽬录
⼀、项⽬开发
1.Go和Java⼀样,是编译型的静态语⾔,但Java的特点“⼀次编译,到处运⾏”,是因为Java编译成为.class⽂件之后,由虚拟机解释成⼆进制⽂件执⾏,Java程序运⾏在虚拟机上,虚拟机屏蔽了平台差异,同时也带来了限制,Java程序的运⾏要经过两个步骤,⽽且必须要运⾏在JVM上。⽽Go语⾔则是直接编译成⼆进制可执⾏⽂件,⽐较灵活。
2.Go使⽤Go Modules来管理代码,类似Java中的Maven。Go Modules的项⽬根⽬录下默认包含了⼀个go.mod⽂件,通过这个⽂件管理项⽬依赖,类似Maven中的l⽂件。下图为例calc项⽬结构,使⽤go build构建项⽬。
3.Go的程序⼊⼝⽂件为,这个⽂件必须在main包中。Java中程序⼊⼝为类中的main⽅法,如果⼀个类中没有main⽅法,则该类⽆法独⽴运⾏。
4.Go在单元测试需要引⼊testing包,类似于Java中的JUnit。
5.Go使⽤包作为基本单位来管理代码,每个 Go 源代码⽂件的开头都是⼀个 package 声明,表⽰该⽂件中 Go 代码所属的包。包是 Go 语⾔⾥最基本的分发单位,也是⼯程管理中依赖关系的体现。有些类似Java中包+类的作⽤。
6.在引⼊ Go Modules 以前,Go 语⾔会基于 GOPATH 这个系统环境变量配置的路径为根⽬录(可能有多个),然后依次去对应路径下
的 src ⽬录下根据包名查对应的⽂件⽬录,如果⽬录存在,则再到该⽬录下的源⽂件中查对应的变量、类属性、函数和成员⽅法。
在启⽤ Go Modules 之后,不再依赖 $GOPATH 定位包,⽽是基于 go.mod 中 module 配置值作为根路径,在该模块路径下,根据包名查对应⽬录,如果存在,则继续到该⽬录下的源⽂件中查对应变量、类属性、函数和成员⽅法。
7.在 Go 语⾔中,可以通过 import 关键字导⼊官⽅提供的包、第三⽅包、以及⾃定义的包,导⼊第三⽅
包时,还需要通过 go get 指令下载才能使⽤,如果基于 Go Modules 管理项⽬的话,这个依赖关系会⾃动维护到 go.mod 中。
⼆、数据类型
1.Go和Java都是强类型语⾔,不同的是,Java在声明变量时有严格的格式和类型,⽽Go则⽐较随意,通过var来声明变量,也可以使⽤:=运算符声明并初始化变量(此时可以省略var),虽然看起来和动态语⾔声明变量类似,但是Go也是强类型语⾔,底层会⾃动根据赋值判断对应变量的类型,这个判断过程是在编译期做的,不是运⾏期,所以Go也是静态语⾔。
如上图所⽰,Go对变量的声明,类型放在变量名之后,⽽且可以省略,Java类型在变量名之前,不可省略。
2.所有的Go语句不需要分号作为结束符,Java语句结束必须加分号。
3.Java和Go的变量命名均遵循驼峰命名法。
java环境变量自动配置4.Go⽀持多重赋值,例如,交换i,j变量,如果在Java中需要⼀个中间变量来实现,在Go中只需要i, j = j,
i;这⼀句即可。
5.Go⽀持匿名变量,可使⽤_接受不想要的变量,会直接抛弃。
6.Go通过const关键字定义常量,常量类型可以指定也可以省略(由底层⾃动推导)。Java通过static final组合关键字定义常量,类型不可省略。
7.Go预定义的常量:true、false、iota。iota是Java中没有的,可以被认为是⼀个可被编译器修改的常量,在每⼀个 const 关键字出现时被重置为 0,然后在下⼀个 const 出现之前,每出现⼀次 iota,其所代表的数字会⾃动增 1。
8.Java中枚举的关键字是enum,在Go中不⽀持enum关键字,通过在 const 后跟⼀对圆括号定义⼀组常量的⽅式来实现枚举。
9.Go中的变量和常量不⽤public和private修饰,通过⾸字母⼤⼩来判断是否包内可见。⾸字母⼤写相当于Java中⽤public修饰包外也可以访问,⾸字母⼩写相当于⽤private修饰,只能包内访问。
10.Go⽀持的基本数据类型:
布尔类型:bool
整型:int8、byte、int16、int、uint、uintptr 等
浮点类型:float32、float64
复数类型:complex64、complex128
字符串:string
字符类型:rune
错误类型:error
(1)Go⽀持的整型类型⾮常丰富,其中int、uint、uintptr的位数与平台有关。
(2)Go在运算时⽆法进⾏⾃动类型转换,不同类型的值进⾏运算会报错。
数据类型之间的互相转化,只需调⽤要转化的数据类型对应的函数即可。(在有符号与⽆符号以及⾼位数字向低位数字转化时,需要注意数字的溢出和截断。)
⽬前 Go 语⾔不⽀持将数值类型转化为布尔型,需要⾃⼰根据需求去实现类似的转化。
(3)Go语⾔中++ 或 -- 只能出现在语句中,不能⽤于表达式,⽽且只能放在变量后,不能放在变量前。
(4)Go中float32相当于Java中的float,Go中的float64相当于Java中的double。
(5)Go⽀持复数类型,复数⽀持两种类型:complex64(32 位实部和虚部) 和 complex128(64 位实部与虚部),对应的表⽰⽰例如下,和数学概念中的复数表⽰形式⼀致:
对于⼀个复数 z = complex(x, y),就可以通过 Go 语⾔内置函数 real(z) 获得该复数的实部,也就是 x,通过 imag(z) 获得该复数的虚部,也就是 y。
(6)Go中字符串是⼀种基本数据类型,Java中字符串是引⽤类型。
Go的字符串默认是通过 UTF-8 编码的字符序列,当字符为 ASCII 码时则占⽤ 1 个字节,其它字符根据需要占⽤ 2-4 个字节,⽐如中⽂编码通常需要 3 个字节。Java中的字符串底层是指针指向的⼀个字符数组。
Go和Java⼀样,字符串可以通过数组下标访问其中的字符,⽽且不可变值。
Go 语⾔中字符串默认是 UTF-8 编码的 Unicode 字符序列
在 Go 语⾔中,可以通过字符串切⽚实现获取⼦串的功能:
切⽚相当于Java中的subString⽅法,取元素的区间同样是左闭右开。
Go 语⾔对字符串中的单个字符进⾏了单独的类型⽀持,在 Go 语⾔中⽀持两种字符类型:
⼀种是 byte,代表 UTF-8 编码中单个字节的值(它也是 uint8 类型的别名,两者是等价的,因为正好占据 1 个字节的内存空间);
另⼀种是 rune,代表单个 Unicode 字符(它也是 uint32 类型的别名,因为正好占据 4 个字节的内存空间。
如果想要将 Unicode 字符编码转化为对应的字符,可以使⽤ string 函数进⾏转化。
UTF-8 编码不能这样转化,英⽂字符没问题,因为⼀个英⽂字符就是⼀个字节,中⽂字符则会乱码,因为⼀个中⽂字符编码需要三个字节,转化单个字节会出现乱码。
(7)Go中整型数据可以通过 Unicode 字符集转化为对应的 UTF-8 编码的字符串:
Unicode 兼容 ASCII 字符集,所以 65 被转化为 A。
此外,还可以将 byte 数组或者 rune 数组转化为字符串,因为字符串底层就是通过这两个基本字符类型构建的:
当然了,byte 是 uint8 的别名,rune 是 uint32 的别名,所以也可以看做是整型数组和字符串之间的转化。
Java中整型数据可以通过String.valueOf()⽅法转化为字符串。
(8)Go 语⾔默认不⽀持将字符串类型强制转化为数值类型,即使字符串中包含数字也不⾏。如果要实
现更强⼤的基本数据类型与字符串之间的转化,可以使⽤ Go 官⽅ strconv 包提供的函数。
Java可以通过Integer.parseInt()⽅法将包含数字的字符串转化为整型数据。
11.Go⽀持的复合类型:
指针(pointer)
数组(array)
切⽚(slice)
字典(map)
通道(chan)
结构体(struct)
接⼝(interface)
(1)对于数组,Go和Java很类似,都是固定长度的、同⼀类型的数据集合。Go⼀些常见的数组声明⽅法如下图所⽰:
Go 语⾔还提供了⼀个关键字 range⽤于遍历数组
range 表达式返回两个值,第⼀个是数组下标索引值,第⼆个是索引对应数组元素值。
(2)Go中的数组是值类型,切⽚是引⽤类型,⽀持动态的添加新元素。
在 Go 语⾔中,切⽚是⼀个新的数据类型,与数组最⼤的不同在于,切⽚的类型字⾯量中只有元素的类型,没有长度:
切⽚从底层管理上来看依然使⽤数组来管理元素,可以看作是对数组做了⼀层简单的封装。
创建切⽚的⽅法主要有三种 —— 基于数组(通过 array[start:end] 这样的⽅式基于数组⽣成⼀个切⽚)、切⽚和直接创建(Go 语⾔提供的内置函数 make() 可以⽤于灵活地创建切⽚)。最终切⽚都是基于数组创建的,切⽚可以看做是操作数组的指针。
切⽚底层结构:
切⽚底层引⽤了⼀个数组,由三个部分构成 —— 指针、长度和容量,指针指向数组起始下标,长度对应切⽚中元素的个数,容量则是切⽚起始位置到底层数组结尾的位置:
可以通过 append() 函数向切⽚追加新元素,append() 的第⼆个参数是⼀个不定参数,可以是若⼲个元素,也可以是⼀个另⼀个切⽚。如果追加的元素超过了原切⽚的容量,底层会⾃动扩容(默认两倍)。
切⽚可以通过copy()函数复制,默认按照⼩切⽚的个数进⾏复制。
切⽚结构体:
两个切⽚指向同⼀个数组会存在内存共享问题,解决办法是将其中⼀个切⽚扩容到⽐原容量⼤,则会⾃动新建⼀个底层数组。
排序可以使⽤sort包。
(3)Go字典类型的声明:
或者类似切⽚,使⽤Go内置的make⽅法:
这种⽅法的初始化可以使⽤下图所⽰⽅法添加键值对:
字典查返回两个值,到的键值和是否成功到的标识
Go在声明字典的键类型时,要求数据类型必须是⽀持通过 == 或 != 进⾏判等操作的类型。在Java中Map类型的键值要求必须重写equals()和hashcode()⽅法。
Go⽤内置函数 delete()删除容器内的元素,Java⽤remove()。
(3)Go⽀持指针,Java不⽀持,但Java的引⽤类型类似指针。Java中⽆指针,所以程序员不能直接操作内存地址,这在⼀定程度上也保证了安全性。
声明指针:var ptr *int // 声明指针类型
*ptr取指针指向的变量值,&a取变量的地址。
Go规定unsafe.Pointer 是特别定义的⼀种指针类型,它可以包含任意类型变量的地址(类似 C 语⾔中的 void 类型指针)。Go 官⽅⽂档对这个类型有如下四个描述:
a.任何类型的指针都可以被转化为 unsafe.Pointer;
b.unsafe.Pointer 可以被转化为任何类型的指针;
c.uintptr 可以被转化为 unsafe.Pointer;
d.unsaf
e.Pointer 可以被转化为 uintptr。
uintprt类型单独列出的原因是:uintptr 是 Go 内置的可⽤于存储指针的整型,⽽整型是可以进⾏数学运算的!因此,将 unsafe.Pointer 转化为 uintptr 类型后,就可以让本不具备运算能⼒的指针具备了指针运算能⼒(如:指向前⼀个元素的指针加上元素偏移量可以得到下⼀个元素的内存地址)。实际使⽤时要
尽量避免,因为可以绕过 Go 指针的安全限制,实现对指针的动态偏移和计算了,这会导致即使发⽣数组越界了,也不会报错,⽽是返回下⼀个内存地址存储的值,这就破坏了内存安全限制,所以这也是不安全的操作。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。