来Javaer,学学go吧(二)

简介: Go与Java

9.Go与Java的赋值对比


1).go的赋值


Go方法内的赋值符号可以用  := ,也可以用 =,方法外只能用 = 。
例如:
package main
import(
   //包含print函数
   "fmt"
)
//方法外只能用 = 赋值
var my_name  string = "my_name"
var my_name2 = "my_name2"
//my_name3:="my_name3"    不在方法内,错误
func main() {
   fmt.Println("name = ",my_name)
   fmt.Println("name2 = ",my_name2)
}
Go支持多变量同时赋值:
package main
import(
   //包含print函数
   "fmt"
)
func main() {
   //多变量同时赋值
   var name,name2 = "li_ming","xiao_hong"
   fmt.Println("name = ",name)
   fmt.Println("name2 = ",name2)
}
Go的丢弃赋值
package main
import(
   //包含print函数
   "fmt"
)
func main() {
   //丢弃赋值    把 1和2丢弃 只取3
   //在必须一次取两个以上的值的场景下,又不想要其中一个值的时候使用,比如从map中取key,value
   var _,_,num = 1,2,3
   fmt.Println("num = ",num)
}


2).java的赋值


public class MyTest {
    public static void main(String[] args) {
        //直接用 = 赋值
        String name = "xiao_ming";
        int i = 10;
        System.out.println("name ="+name);
        System.out.println("i ="+i);
    }
}


10.Go与Java的注释


Go中的注释写法和Java中的基本一样。
例如:
//单行注释,两者相同
/*
    Go的多行注释
*/
/**
  Java多行注释
*/


11.Go和Java的访问权限设置区别


首先我们来回忆一下,Java的权限访问修饰符有哪些?


public      全局可见

protected  继承相关的类可见

default   同包可见

private    私有的,本类可见


关于Java中的访问权限修饰符,是用于修饰变量,方法,类的,被修饰的对象被不同的访问权限修饰符修饰后,其它程序代码要想访问它,必须在规定的访问范围内才可以,比如同包,同类,父子类,全局均可访问。


那么,Go中的访问权限设置又有什么区别呢?


要理解这个问题,首先来看一下一个Go程序的程序文件组织结构是什么样子的?

一个可运行的编译后的Go程序,必须有一个入口,程序从入口开始执行,这个入口必须是main包,并且从main包的main函数开始执行。


但是,为了开发的效率和管理开发任务的协调简单化,对于代码质量的可复用,可扩展等特性的要求,一般采用面向对象的,文件分模块式的开发。


比如,一个游戏程序,main函数启动后,首先要启动UI界面,那么关于UI界面相关的代码我们一般会专门分出一个模块去开发,然后这个模块有很多个程序文件,这里关于UI模块比如有3个文件,a.go,b.go,c.go,那么我们在实际当中会建一个以ui为名的包文件夹,然后把a.go,b.go,c.go全部放到ui这个包文件夹下,然后因为这个包没有main包,没有main函数,所以它打出来的一个程序文件就是以.a结尾的工具包,类似于Java中的jar包,工具包文件名为  ui.a。


参考如下:


----com.ababa.niu.ui

------------------------------------a.go
    ------------------------------------b.go
    ------------------------------------c.go

a.go文件如下示例:

//这里的ui,也就是package后面的名称尽量和包文件夹的名称一致,不一致也可以
package ui
//相关方法和业务
func main() {
}
//启动游戏UI
func StartGameUI() {
}

这里需要注意一个点,在程序中的 package后面的 ui包名可以和文件夹com.ababa.niu.ui中最后一层的ui文件夹名称不一致,


一般按规范写是要求写一致的,不一致时的区别如下:


把ui.a打包完毕后,就可以在别的程序中用import导入这个包模块 ,然后使用其中的内容了。


上面两个ui不同之处在于,在import 的代码后面,需要写的模块名称是在 ${gopath}/src/下的文件夹名,也就是com.ababa.niu.ui中的ui。


例如:

//游戏主程序
package main
//这里的ui是com.ababa.niu.ui的最后一层文件夹名
import "ui"
//相关方法和业务
func main() {
  //这里的ui不是文件夹名,而是之前a.go程序中package后面写的包名
  ui.StartGameUI()
}

image.png

image.png

接下来进入主题,我们的go语言关于访问修饰符的是指的限制什么权限,以及如何实现?


之前可以看出来,实战中的go程序是有一个main程序import很多其它包模块,每个模块实现对应的功能,最后统一在main程序中组合来完成整个软件程序,那么有一些其它模块的函数和变量,我只想在本程序文件中调用,不想被其它程序import能调用到,如何实现?


import后是否能调用对应包中的对象(变量,结构体,函数之类的)就是go关于访问权限的定义,import后,可以访问,说明是开启了访问权限,不可以访问,是说明关闭了其它程序访问的权限。


在go中,为了遵循实现简洁,快速的原则,用默认的规范来规定访问权限设置。

默认规范是:某种类型(包括变量,结构体,函数,类型等)的名称定义首字母大写就是在其它包可以访问,首字母非大写,就是只能在自己的程序中访问。


这样我们就能理解为什么导入fmt包后,他的PrintF函数的首字母P是大写的。


参照如下代码:

package ui
import "fmt"
func main() {
   //这里的P是大写
   //所有调用别的包下的函数,都是首字母大写
   fmt.Printf("aa")
}
//这里的Person的首字母P也是表示外部程序导入该包后可以使用此Person类
type Person struct{
}
//这里的D同上
var Data string = "li_ming"


12.Go与Java程序文件的后缀名对比


Java的编译文件是.class结尾,多个.class打成的一个可执行文件是.jar结尾,.jar不能直接在windows和linux上执行,得用java命令在JVM中执行。
Go语言的程序文件后缀为.go,有main包main函数的,.go文件打包成二进制对应操作系统的可执行程序,如windows上的.exe结尾的可执行程序。
Java的类库会以.jar结尾,Go语言非main包没有main函数的程序编译打包会打成一个类库,以.a结尾,也就是说Go语言的类库以.a结尾。
Go的类库如下:
            包名.a     
            my_util.a
注:my_util是最顶层文件夹名,里面包含着一个个程序文件。


13.Go与Java选择结构的对比


1).if


Go中的if和Java中的if使用相同,只不过是把小括号给去掉了。       


示例1:


package main
import (
   "fmt"
)
func main() {
   /*
      单分支结构语法格式如下:
         if 条件判断 {
            //代码块
         }
   */
   var num int
   fmt.Printf("请输入数字")
   fmt.Scan(&num)
   if num > 10 {
      fmt.Println("您输入的数字大于10")
   }
}


示例2:


package main
import (
   "fmt"
)
func main() {
   /*
      if else分支结构语法格式如下:
         if 条件判断 {
            //代码块
         } else {
            //代码快2
         }
   */
   var num int
   fmt.Printf("请输入数字")
   fmt.Scan(&num)
   if num > 10 {
      fmt.Println("您输入的数字大于10")
   } else {
      fmt.Println("您输入的数字不大于10")
   }
}


示例3:


package main
import (
   "fmt"
)
func main() {
   /*
      if else分支结构语法格式如下:
         if 条件判断 {
            //代码块
         } else if 条件判断{
            //代码块2
         } else {
            //代码块3
         }
   */
   var num int
   fmt.Printf("请输入数字")
   fmt.Scan(&num)
   if num > 10 {
      fmt.Println("您输入的数字大于10")
   } else if num == 10{
      fmt.Println("您输入的数字等于10")
   } else {
      fmt.Println("您输入的数字小于10")
   }
}


2).switch


示例1(go语言case语句默认只执行一个,不需要break):

package main
import (
   "fmt"
)
func main() {
   var a = "xiao_ming"
   switch a {
   case "xiao_ming":
      fmt.Println("Hello!XiaoMing")
   case "xiao_hong":
      fmt.Println("Hello!XiaoHong")
   default:
      fmt.Println("No!")
   }
}


示例2:一分支多值


package main
import (
   "fmt"
)
func main() {
   var name = "xiao_ming"
   var name2 = "xiao_hong"
   switch name {
   //li_ming或xiao_hong 均进入此
   case "xiao_ming", "xiao_hong":
      fmt.Println("xiao_ming and xiao_hong")
   }
   switch name2 {
   case "xiao_ming", "xiao_hong":
      fmt.Println("xiao_ming and xiao_hong")
   }
}


示例3:switch表达式


package main
import (
   "fmt"
)
func main() {
   var num int = 11
   switch{
      case num > 10 && num < 20:
         fmt.Println(num)
   }
}


示例4:fallthrough下面的case全部执行


package main
import (
   "fmt"
)
func main() {
   var num = 11
   switch {
   case num == 11:
      fmt.Println("==11")
      fallthrough
   case num < 10:
      fmt.Println("<12")
   }
}


14.Go与Java循环结构的对比


1).for循环


示例1:省略小括号

package main
import (
"fmt"
)
func main() {
   for i := 1; i < 10; i++ {
      fmt.Println(i)
   }
}


示例2:和while相同,break,continue同java


package main
import (
   "fmt"
)
func main() {
   i := 0
   //省略另外两项,相当于java中的while
   for i < 3 {
      i++
   }
   //break用法相同
   for i == 3 {
      fmt.Println(i)
      break
   }
}


示例3:死循环,三项均省略


package main
func main() {
   for {
   }
   for true {
   }
}


示例4:嵌套循环和java也一样,不演示了


示例5: range循环


package main
import "fmt"
func main() {
   var data [10]int = [10]int{1,2,3,4,5,6,7,8,9,10}
   for  i, num := range data {
      fmt.Println(i,num)
   }
}


2).goto


package main
import "fmt"
func main() {
   //goto可以用在任何地方,但是不能跨函数使用
   fmt.Println("start")
   //go to的作用是跳转,中间的语句不执行,无条件跳转
   goto my_location //goto是关键字, my_location可以自定义,他叫标签
   fmt.Println("over")
   my_location:
   fmt.Println("location")


15.Go与Java的数组对比


1)go的一维数组


var 数组名 [数组长度]数组类型  = [数组长度]数组类型{元素1,元素2...}


示例1:


package main
import "fmt"
//全局
var my_arr [6]int
var my_arr_1 [3]int = [3]int{1,2,3}
func main() {
   //方法内:
   this_arr := [2]int{1, 2}
   fmt.Println(my_arr)
   fmt.Println(my_arr_1)
   fmt.Println(this_arr)
}


2)二维数组


package main
import "fmt"
//全局
var my_arr [4][6]int
var my_arr_1 [2][3]int = [...][3]int{{1, 2, 3}, {4, 5, 6}}
func main() {
   //方法内:
   this_arr := [2][3]int{{1, 2, 3}, {8, 8, 8}}
   // 第 2 纬度不能用 "..."。
   this_arr2 := [...][2]int{{1, 1}, {2, 2}, {3, 3}}
   fmt.Println(my_arr)
   fmt.Println(my_arr_1)
   fmt.Println(this_arr)
   fmt.Println(this_arr2)
}


16.Go有指针概念,Java没有指针概念


Go中有指针的概念,Java中没有指针的概念。
指针简单的说就是存储一个【变量地址】的【变量】。
Go中使用指针的方法
//*+变量类型 = 对应变量类型的指针类型,&+变量名 = 获取变量引用地址    
var  指针变量名 *指针变量类型 = &变量名  
例如:
var my_point *int = &num
//通过&+指针变量 = 修改原来的变量真实值
&指针变量名 = 修改的变量值
例如:
&my_point = 100;

示例:

package main
import "fmt"
func main() {
  // 声明实际变量
  var name string="xiao_ming"
  // 声明指针变量
  var name_point *string
  // 指针变量的存储地址
  name_point = &name
  //直接访问变量地址
  fmt.Println("name 变量的地址是:", &name  )
  // 指针变量的存储地址
  fmt.Println("name_point变量储存的指针地址:", name_point )
  // 使用指针访问值
  fmt.Println("*name_point 变量的值:", *name_point )
}


输出结果:


name 变量的地址是: 0x10ae40f0
name_point变量储存的指针地址: 0x10ae40f0
*name_point 变量的值: xiao_ming


17.Go语言的中new,make和Java中的new对象有什么区别?


首先,Java中的new关键字代表创建关于某一个类的一个新的对象。

如:


List list = new ArrayList(); 


Go中的创建一个struct结构体的对象,是不需要用new关键字的,参考【20】中有代码示例讲解如何创建结构体对象。


Go中new的概念是和内存相关的,可以通过new来为基础数据类型申请一块内存地址空间,然后把这个把这个内存地址空间赋值给


一个指针变量上。(new主要就是为基础数据类型申请内存空间的,当我们需要一个基础数据类型的指针变量,并且在初始化这个基础指针变量时,不能确定他的初始值,此时我们才需要用new去内存中申请一块空间,并把这空间绑定到对应的指针上,之后可以用该指针为这块内存空间写值。new关键字在实际开发中很少使用,和java很多处用new的情况大不相同)


参考如下示例代码:

package main
import "fmt"
func main() {
   var num *int
   //此处num是nil
   fmt.Println(num)
   //此处会报空指针异常,因为num为nil,没有申请内存空间,所以不能为nil赋值
   *num = 1
   fmt.Println(*num)
}

改为如下代码即可:

package main
import "fmt"
func main() {
   //在内存中申请一块地址,并把内存地址存入num
   var num = new(int)
   //此处num的值是申请出来的内存空间地址值,一个十六进制的数字
   fmt.Println(num)
   //正常
   *num = 1
   fmt.Println(*num)
}
复制代码

go中的make是做什么用的?


go中的make是用来创建**slice(切片),map(映射表),chan(线程通信管道)**这三个类型的对象的,返回的就是对应类型的对象,他的作用就相当于Java中new一个ArrayList,new一个HashMap时候的new的作用,只不过是go语法规定用make来创建slice(切片),map(映射表),chan(线程通信管道)。


示例代码如下:

package main
import "fmt"
func main() {
   //make只能为map,channel,slice申请分配内存,只有这三种,没有第四种
   //所有通过make创建的这三种类型都是引用类型,传递参数时虽然是引用值传递,
   //但是对方法内引用变量参数的修改可以影响到外部的引用变量
   //1.通过make创建map对象  如下代码类似于Java中 Map<String,Integer> myMap = new HashMap<>();
   //在这里make就是申请分配map的内存,和java中创建map的new一样
   myMap := make(map[string]int)
   myMap["xiao_ming"] = 20
   //2.通过make创建channel,make函数内可以有一个参数,也可以有两个参数,有两个参数时第二个参数
   //为通道的缓存队列的长度
   //2.1) 只有一个参数,通道的缓存队列长度此时为0,也就是无缓存。
   //创建一个传输int类型数据的通道
   myChan := make(chan int)
   fmt.Println(myChan)
   //2.2) 有两个参数,第二个参数2代表此时代表缓存队列的长度为2
   //创建一个传输int类型数据的通道,缓存为2
   mychan2 := make(chan int,2)
   fmt.Println(mychan2)
   //此处暂时不做通道缓存队列数多少有何区别的讲解
   //3.通过make创建slice切片
   //有两种方式,一种是两个参数,一种是三个参数
   //我们只有在创建一个空的切片时才会使用make
   //如果通过一个已有的数组创建切片往往是下面的形式
   //创建一个底层数组
   myArr := []int{1,2,3,4,5}
   //如果通过一个数组创建切片,往往是用 原始数组变量名[切片起始位置:切片结束位置] 创建一个切片
   mySlice1 := myArr[2:4]
   fmt.Println(mySlice1)
   //我们如果是想创建一个空的slice,则用make创建切片
   //如下形式 make(int[],num1,num2)
   //num1 = 切片的长度(默认分配内存空间的元素个数)
   //num2 = 切片的容量(解释:底层数组的长度/切片的容量,超过底层数组长度append新元素时会创建一个新的底层数组,
   //不超过则会使用原来的底层数组)
   //代表底层数组的长度是4,默认给底层数组的前两个元素分配内存空间
   //切片指向前两个元素的地址,如果append新元素,在元素数小于4时都会
   //在原来的底层数组的最后一个元素新分配空间和赋值,
   //append超过4个元素时,因为原数组大小不可变,也也存储不下了,
   //所以会新创建一个新的底层数组,切片指向新的底层数组
   mySliceEmpty := make([]int,2,4)
   fmt.Println(mySliceEmpty)
   //两个参数,代表切片的长度和切片的容量(底层数组长度)均为第二个参数那个值
   mySliceEmpty2 := make([]int,5)
   fmt.Println(mySliceEmpty2)
}


18.Go相关的数据容器和Java的集合框架对比


Go中有的数据结构:数组,切片,map,双向链表,环形链表,堆
Go自己的类库中没有set,没有集合(List),但是第三方库有实现。
Java中有: Map,Set,List,Queue,Stack,数组
Java中没有切片的概念。
Go中的数组打印格式是[1,2,3,4,5] 
Go中的切片打印格式是[[1,2,3]]
Go中切片的概念:切片是数组的一个子集,就是数组截取某一段。
Go的map和Java的map大致相同


19.Go中的函数,Go的方法和Java中的方法对比


1).Go中的函数定义


Go中返回值可以有多个,不像Java中多个值得封装到实体或map返回
//注:【】内的返回值可不写,无返回值直接把返回值部分全部去掉即可。
func 函数名(变量1 变量类型,变量2 变量2类型...)【(返回值1 类型1,返回值2 类型2...)】  {        
//注意:这个方法的右中括号必须和func写在同一行才行,否则报错,不能按c语言中的换行写

示例1:

package main
import "fmt"
func main() {
   //定义局部变量
   var a int = 100
   var b int = 200
   var result int
   //调用函数并返回最大值
   result = max(a, b)
   fmt.Println( "最大值是 :", result )
}
/* 函数返回两个数的最大值 */
func max(num1, num2 int) int {
   /* 定义局部变量 */
   var result int
   if (num1 > num2) {
      result = num1
   } else {
      result = num2
   }
   return result
}

示例2:返回多个值

package main
import "fmt"
func main() {
   a, b := swap("xiao_ming", "xiao_hong")
   fmt.Println(a, b)
}
func swap(x, y string) (string, string) {
   //返回多个值
   return y, x
}


注意点:函数的参数:基础类型是按值传递,复杂类型是按引用传递


示例3: 函数的参数:变长参数传递

package main
import "fmt"
func main() {
  manyArgs(1,2,"2","3","4")
  manyArgs(1,2,"5","5","5")
  dataStr := []string{"11","11","11"}
  //传数组也可以,加三个点
  manyArgs(1,2,dataStr...)
}
//可变参数必须放在最后面
func manyArgs(a int,b int ,str ...string ){
  for i,s := range str {
    fmt.Println(i,s)
  }
}

注意点:函数的返回值:如果有返回值,返回值的类型必须写,返回值得变量名根据情况可写可不写。


示例4: defer:推迟执行(类似于java中的finally)

package main
import "fmt"
func main() {
   testMyFunc();
}
func testDefer1() {
   fmt.Println("print defer1")
}
func testDefer2() {
   fmt.Println("print defer2")
}
func testMyFunc() {
   //defer会在方法返回前执行,有点像java中的finally
   //defer写在任意位置均可,多个defer的话按照逆序依次执行
   defer testDefer2()
   defer testDefer1()
   fmt.Println("print my func")
}

示例5 :丢弃返回值

package main
import "fmt"
func main() {
   //方式一丢弃:丢弃num1和str
   _,num2,_:= testFun(1,2,"3");
   fmt.Println(num2)
   //方式二丢弃:
   _,num3,_:= testFun(1,3,"4");
   fmt.Println(num3)
}
func testFun(num1,num2 int,str string) (n1 int,n2 int,s1 string){
   n1 = num1
   n2 = num2
   s1 = str
   return
}
func testFun2(num1,num2 int,str string) (int,int,string){
   return num1,num2,str
}


2).Java中的方法定义


访问修饰符   返回值类型   方法名(参数1类型  参数1,参数2类型 参数2...) {
       return 返回值;
 }

示例:

public Integer doSomething(String name,Integer age) {
    return 20;
 }


目录
相关文章
来Javaer,学学go吧(四)
在学go的过程中,也是一脸蒙蔽,语法和java有很大区别也很随意,直到学到goroutine,实现并发编程太方便简洁了,真香!
109 5
|
消息中间件 缓存 运维
|
架构师 Java 程序员
慢聊Go之Javaer转型|Go主题月
慢聊Go之Javaer转型|Go主题月
152 0
慢聊Go之Javaer转型|Go主题月
|
消息中间件 缓存 安全
来Javaer,学学go吧(三)
在学go的过程中,也是一脸蒙蔽,语法和java有很大区别也很随意,直到学到goroutine,实现并发编程太方便简洁了,真香!
90 0
|
SQL Java 数据库连接
javaer to go之简单的ORM封装
身为一个做企业级开发的javaer,习惯使用hibernate、ibatis等ORM框架来操作数据库。虽然也发现golang也有ORM框架,像beego ORM等。 为了熟悉golang的一些特性,我还是觉得自己封装一个ORM。 <h1 id="1struct与interface
3507 0
|
网络协议 Java Go
javaer to go之TCP Socket与Goroutine
<div class="markdown_views"> <h1 id="1前言"> 1、前言</h1> <p>其实我前面一篇笔记的例子就是socket的一个例子,但是由于大部分的笔记说明都是在整理基础的东西,所以socket的笔记单独列在这里。</p> <p>server.go</p> <pre class="prettyprint"><code class=" h
2340 0
|
Go
javaer to go之byte类型转换
<div class="markdown_views"> <p>在Socket的Server和Client通信的过程中,传输的都是字节。而我们需要展示和使用的是字符串、整形等。这个时候,我们需要对字节进行处理,把byte类型的数据转成我们需要的类型。</p> <h2 id="1byte与16进制字符串">1、[]byte与16进制字符串</h2> <ul> <li>[]by
2195 0
|
SQL 关系型数据库 MySQL
javaer to go之mysql操作
<div class="markdown_views"> <p>经过度娘后,发现比较常用golang mysql驱动包有两种mymysql和go-sql-driver/mysql。个人觉得mymysql这个名字起得不够文雅。所以我选择了go-sql-driver/mysql。</p> <h2 id="1go-sql-drivermysql的安装">1、go-sql-drive
2086 0
|
Java Go 网络协议
javaer to go之基础
<div class="markdown_views"> <h2 id="1开始">1、开始</h2> <p>我是一个javaer,最近空闲时间在学习golang。</p> <p>度娘后,安装好Go环境和LiteIDE后,一开始我也没从基础开始看,而是想把现有的java项目改成是golang版本的。</p> <p>原项目内容:</p> <ol> <li>socket模块
1952 0
|
1天前
|
编译器 Go
go语言编译选项
【10月更文挑战第17天】
10 5