编译语言 vs 解释语言

本文会参照Java来比较分析GO的编译,为了解两者区别,阅读正文前可以先了解下这两个概念

程序的执行,说到底就是将代码编译成平台能运行的机器码,然后执行的过程

执行方式分成了两种:

编译型:通过编译器,将代码编译成平台特定的机器码。编译与运行隔开,一次编译,可多次运行。代表有C、C++

解释型:通过解释器,逐行编译代码成平台的机器码,并立即运行。即每次运行时都编译。代表有Python、Ruby

编译型语言效率高,但跨平台得重新编译程序;解释型语言易跨平台执行,但每次运行要编译效率低。

Golang 是编译型语言

Java是半编译半解释型语言(编译成jvm的字节码,即class文件,然后jvm解释执行)

GOPATH定义

刚学go语言时,我一直都没有弄懂这个变量到底是做什么的,先看看官方的定义:

GOPATH 环境变量指定了你的工作空间位置。它或许是你在开发Go代码时, 唯一需要设置的环境变量。

Go代码必须放在工作空间内。它其实就是一个目录,其中包含三个子目录:

src 目录包含Go的源文件,它们被组织成包(每个目录都对应一个包),

pkg 目录包含包对象,

bin 目录包含可执行命令。

go 工具用于构建源码包,并将其生成的二进制文件安装到 pkg 和 bin 目录中。src 子目录通常包会含多种版本控制的代码仓库(例如Git或Mercurial), 以此来跟踪一个或多个源码包的开发

总结一下官方的描述重点:

所有Go代码必须放在GoPath中

src包含所有源代码,pkg包含编译后的包文件(go中后缀为.a,java中为.jar),bin包含编译后的可执行文件(go中根据平台不一样后缀不一样,java中所有平台都为.jar)

疑问一:为啥Go代码必须放在GOPATH中

从java转过来的我表示不能理解,为啥规定所有代码都要在GoPath目录?万能的java里,项目在任何目录都是可以执行的呀

我们来实验一下,在非GoPath创建项目是否可以运行。

在D://创建如下goProject项目,包含一个main.go,及引用到的basic.hello.go

代码如下:

main.go:

package main

import "basic"

func main() {

basic.Hello()

}

hello.go:

package basic

import "fmt"

func Hello() {

fmt.Print("Hello! ")

}

尝试编译main.go文件,发现报错:

PS D:\goProject\src> go build -n main.go

main.go:3:8: cannot find package "basic" in any of:

D:\Program Files\go\src\basic (from $GOROOT)

E:\workspace\go\src\basic (from $GOPATH)

从错误信息中我们了解到,编译失败的原因在于,寻找引用包basic时,并没在像我们想象的自动在项目路径src下寻找,而是分别在$GOROOT和$GOPATH进行了查找。

也就是说,代码只有都放进$GOPATH,才能保证import的引用都能正确的被找到。如果你的代码除了官方引用($GOROOT),没有其他包的引用,也是可以正常编译运行的。

扩展:为什么Java项目放在任何路径都可以正常编译呢?

Java中有一个类似GOPATH的参数classpath,它是Java运行时环境搜索类和其他资源文件(比如jar\zip等资源)

的路径。

classpath默认为jdk的相关目录(lib)和当前目录。java程序编译和运行时,都可以指定classpath。我们之所以感觉java项目可以任意目录执行,是因为idea、maven这些工具帮我们指定好了运行时依赖的classpath路径。(在文章末尾有纯命令编译运行java项目的例子,想要了解的朋友可以简单看看)

Go中其实也可以在项目运行的环境变量中指定GOPATH,这样的好处在于每个项目的依赖包相互隔离。

但是个人感觉GOPATH的设计理念就是基于想把所有的依赖包、代码、二进制文件统一到一个目录。并且GO这么设计的时候很粗暴的不支持依赖包有不同版本:

Go philosophy is that everything should be backward compatible. If you release a library, you have to ensure it stay compatible with older versions's public API. If you need to break the API, then it is a new package and should have a new import path.

Go设计的哲学思维是,所有的代码都应该向后兼容。如果你发布一个库,你必须保证之前版本的API仍然是可以正常使用的。如果不能,那新版本的API应是在新的包路径中被引用

Go这样的设计应该是没有得到很大的认可,所以在后续的版本中,Go还是加入了依赖包的版本管理(go 1.11和1.12版本中新增了go module)

疑问二:为啥Go编译后的可执行文件那么大?

我们上面的项目放入$GOPATH后编译,得到如下可执行文件:

image.png

一个hello world级别的代码,编译出来的可执行文件居然快2M?我们将java程序打包成可执行jar包,也不会这么大呀。

我们来详细看下main.go的编译过程:

E:\workspace\go\src\github.com\Mrdshu\codeDemo\goDemo> go build -x main.go

WORK=C:\Users\xxx\AppData\Local\Temp\go-build130222670 ----(指定临时编译目录)

mkdir -p $WORK\b002\

cat >$WORK\b002\importcfg << 'EOF' # internal

# import config

packagefile fmt=D:\Program Files\go\pkg\windows_amd64\fmt.a

EOF

cd E:\workspace\go\src\github.com\Mrdshu\codeDemo\goDemo\basic

----(compile依赖包,并将编译好的归档文件pkg_.a文件复制到缓存目录,注意并不是$GOPATH/pkg目录)

"D:\\Program Files\\go\\pkg\\tool\\windows_amd64\\compile.exe" -o "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b002\\_pkg_.a" -trimpath "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b002" -p github.com/Mrdshu/codeDemo/goDemo/basic -complete -buildid G_nVir86m2b03lvrDAWh/G_nVir86m2b03lvrDAWh -goversion go1.11 -D "" -importcfg "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b002\\importcfg" -pack -c=4 "E:\\workspace\\go\\src\\github.com\\Mrdshu\\codeDemo\\goDemo\\basic\\type.go"

"D:\\Program Files\\go\\pkg\\tool\\windows_amd64\\buildid.exe" -w "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b002\\_pkg_.a" # internal

cp "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b002\\_pkg_.a" "C:\\Users\\xxx\\AppData\\Local\\go-build\\50\\5026df2f79f2ef5ea4775d8d700e1ab5086453e6fe91b37d372e005c5655a6fc-d" # internal

mkdir -p $WORK\b001\

cat >$WORK\b001\importcfg << 'EOF' # internal

# import config

packagefile github.com/Mrdshu/codeDemo/goDemo/basic=$WORK\b002\_pkg_.a ----(指定import依赖包的)

packagefile runtime=D:\Program Files\go\pkg\windows_amd64\runtime.a

EOF

cd E:\workspace\go\src\github.com\Mrdshu\codeDemo\goDemo

----(编译main.go)

"D:\\Program Files\\go\\pkg\\tool\\windows_amd64\\compile.exe" -o "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b001\\_pkg_.a" -trimpath "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b001" -p main -complete -buildid vFLkQqJe-TIZKPTKaKqi/vFLkQqJe-TIZKPTKaKqi -goversion go1.11 -D _/E_/workspace/go/src/github.com/Mrdshu/codeDemo/goDemo -importcfg "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b001\\importcfg" -pack -c=4 "E:\\workspace\\go\\src\\github.com\\Mrdshu\\codeDemo\\goDemo\\main.go"

"D:\\Program Files\\go\\pkg\\tool\\windows_amd64\\buildid.exe" -w "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b001\\_pkg_.a" # internal

cp "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b001\\_pkg_.a" "C:\\Users\\xxx\\AppData\\Local\\go-build\\89\\89f263733604869aad0807de6f81086dc556c2e81ace89d9b484618fb0d5d586-d" # internal

cat >$WORK\b001\importcfg.link << 'EOF' # internal

----(以下是链接地址)

packagefile command-line-arguments=$WORK\b001\_pkg_.a

packagefile github.com/Mrdshu/codeDemo/goDemo/basic=$WORK\b002\_pkg_.a

packagefile runtime=D:\Program Files\go\pkg\windows_amd64\runtime.a

packagefile fmt=D:\Program Files\go\pkg\windows_amd64\fmt.a

packagefile internal/bytealg=D:\Program Files\go\pkg\windows_amd64\internal\bytealg.a

packagefile internal/cpu=D:\Program Files\go\pkg\windows_amd64\internal\cpu.a

packagefile runtime/internal/atomic=D:\Program Files\go\pkg\windows_amd64\runtime\internal\atomic.a

packagefile runtime/internal/sys=D:\Program Files\go\pkg\windows_amd64\runtime\internal\sys.a

packagefile errors=D:\Program Files\go\pkg\windows_amd64\errors.a

packagefile io=D:\Program Files\go\pkg\windows_amd64\io.a

packagefile math=D:\Program Files\go\pkg\windows_amd64\math.a

packagefile os=D:\Program Files\go\pkg\windows_amd64\os.a

packagefile reflect=D:\Program Files\go\pkg\windows_amd64\reflect.a

packagefile strconv=D:\Program Files\go\pkg\windows_amd64\strconv.a

packagefile sync=D:\Program Files\go\pkg\windows_amd64\sync.a

packagefile unicode/utf8=D:\Program Files\go\pkg\windows_amd64\unicode\utf8.a

packagefile sync/atomic=D:\Program Files\go\pkg\windows_amd64\sync\atomic.a

packagefile internal/poll=D:\Program Files\go\pkg\windows_amd64\internal\poll.a

packagefile internal/syscall/windows=D:\Program Files\go\pkg\windows_amd64\internal\syscall\windows.a

packagefile internal/testlog=D:\Program Files\go\pkg\windows_amd64\internal\testlog.a

packagefile syscall=D:\Program Files\go\pkg\windows_amd64\syscall.a

packagefile time=D:\Program Files\go\pkg\windows_amd64\time.a

packagefile unicode/utf16=D:\Program Files\go\pkg\windows_amd64\unicode\utf16.a

packagefile unicode=D:\Program Files\go\pkg\windows_amd64\unicode.a

packagefile math/bits=D:\Program Files\go\pkg\windows_amd64\math\bits.a

packagefile internal/race=D:\Program Files\go\pkg\windows_amd64\internal\race.a

packagefile internal/syscall/windows/sysdll=D:\Program Files\go\pkg\windows_amd64\internal\syscall\windows\sysdll.a

packagefile internal/syscall/windows/registry=D:\Program Files\go\pkg\windows_amd64\internal\syscall\windows\registry.a

EOF

mkdir -p $WORK\b001\exe\

cd .

----(编译链接,得到可执行文件)

"D:\\Program Files\\go\\pkg\\tool\\windows_amd64\\link.exe" -o "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b001\\exe\\a.out.exe" -importcfg "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b001\\importcfg.link" -buildmode=exe -buildid=y5HJgFD5pvt8M7MF2-zO/vFLkQqJe-TIZKPTKaKqi/P1SUhx5DB4gHx03j6wd9/y5HJgFD5pvt8M7MF2-zO -extld=gcc "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b001\\_pkg_.a"

"D:\\Program Files\\go\\pkg\\tool\\windows_amd64\\buildid.exe" -w "C:\\Users\\xxx\\AppData\\Local\\Temp\\go-build130222670\\b001\\exe\\a.out.exe" # internal

cp $WORK\b001\exe\a.out.exe main.exe

rm -r $WORK\b001\

从如上的编译过程,我们可以大致的知道:

go build会先编译依赖包,并将编译的归档文件最终放入一个Local\\go-build的缓存目录

编译命令源码文件main.go时,除了链接缓存目录下的依赖包外,还链接了go自身的许多库。

java的jar包之所以小是因为只包含了真正源代码的字节码(class文件),等到jvm运行时才编译链接成二进制文件,最终执行;

而go程序编译时链接了go语言底层的代码库,不单单只有源代码。

最后,引用官方文档中的解释来进一步理解:

Why is my trivial program such a large binary?

The linker in the gc toolchain creates statically-linked binaries by default. All Go binaries therefore include the Go runtime, along with the run-time type information necessary to support dynamic type checks, reflection, and even panic-time stack traces.

A simple C "hello, world" program compiled and linked statically using gcc on Linux is around 750 kB, including an implementation of printf. An equivalent Go program using fmt.Printf weighs a couple of megabytes, but that includes more powerful run-time support and type and debugging information.

A Go program compiled with gc can be linked with the -ldflags=-w flag to disable DWARF generation, removing debugging information from the binary but with no other loss of functionality. This can reduce the binary size substantially.

疑问三:为什么编译后GOPATH的pkg、bin中没有文件?

上面我们编译命令源码文件main.go后,得到的二进制可执行文件在当前目录,并不是bin目录。而编译依赖包后生成的归档文件也不在pkg目录,而是在缓存目录。

那pkg、bin目录下什么时候有文件呢?

答案是使用go install时。有兴趣的朋友可以尝试使用go install -x来观察执行过程,go install过程和go build差不多,只是最后多了一行命令将生成的文件移动到bin或pkg中。

另外,当pkg目录、缓存目录同时存在依赖包的归档文件时,编译器会使用pkg目录下的归档文件。

附加:Java 项目的编译示例

不用maven、grade等项目管理工具,我们看一个“原生态”的java项目的结构:

如图可分为src(存放源码)、target(存放编译后的class文件)、lib(存放第三方引用jar包)三个目录。

A.java

package packageA;

public class A {

private String name;

public A(String name) {

this.name = name;

}

public String getName() {

return name;

}

}

Main.java

package packageA;

import org.springframework.util.StringUtils;

public class Main {

public static void main(String[] args) {

A a = new A("aaaa");

String name = a.getName();

if (StringUtils.isEmpty(name)){

System.out.println("name is empty");

}

else{

System.out.println("name is "+name);

}

}

}

我们直接在源码路径编译项目:

PS D:\project\src\packageA> javac -verbose -encoding UTF-8 -classpath "D:\project\lib\spring-core-5.0.7.RELEASE.jar" -d

D:\project\target\classes A.java Main.java

[解析开始时间 RegularFileObject[A.java]]

[解析已完成, 用时 18 毫秒]

[解析开始时间 RegularFileObject[Main.java]]

[解析已完成, 用时 2 毫秒]

[源文件的搜索路径: D:\project\lib\spring-core-5.0.7.RELEASE.jar]

[类文件的搜索路径: D:\Program Files\Java\jdk1.8.0\jre\lib\resources.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\rt.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\sunrsasign.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\jsse.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\jce.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\charsets.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\jfr.jar,D:\Program Files\Java\jdk1.8.0\jre\classes,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\access-bridge-64.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\cldrdata.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\dnsns.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\jaccess.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\jfxrt.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\localedata.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\nashorn.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\sunec.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\sunjce_provider.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\sunmscapi.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\sunpkcs11.jar,D:\Program Files\Java\jdk1.8.0\jre\lib\ext\zipfs.jar,D:\project\lib\spring-core-5.0.7.RELEASE.jar]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Object.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/String.class)]]

[正在加载ZipFileIndexFileObject[D:\project\lib\spring-core-5.0.7.RELEASE.jar(org/springframework/util/StringUtils.class)]]

[正在检查packageA.A]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/io/Serializable.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/AutoCloseable.class)]]

[已写入RegularFileObject[D:\project\target\classes\packageA\A.class]]

[正在检查packageA.Main]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Byte.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Character.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Short.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Long.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Float.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Integer.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Double.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Boolean.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Void.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/System.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/io/PrintStream.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Appendable.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/io/Closeable.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/io/FilterOutputStream.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/io/OutputStream.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/io/Flushable.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/Comparable.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/CharSequence.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/StringBuilder.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/AbstractStringBuilder.class)]]

[正在加载ZipFileIndexFileObject[D:\Program Files\Java\jdk1.8.0\lib\ct.sym(META-INF/sym/rt.jar/java/lang/StringBuffer.class)]]

[已写入RegularFileObject[D:\project\target\classes\packageA\Main.class]]

[共 258 毫秒]

-verbose:输出有关编译器正在执行的操作的消息

-encoding:指定源文件使用的字符编码

-classpath:指定查找用户类文件和注释处理程序的位置。classpath默认为.;%JAVA_HOME%\lib;%JAVA_HOME%\lib\tools.jar

编译顺序:先编译A.java,再编译使用到A的Main.java

通过日志我们可以清晰的看到,java程序编译时,到指定的classpath路径下搜索用到的源文件和类文件,然后找到依赖的class文件并引用,最终在指定的\target\classes目录生成了对应的class文件。

在target\classes目录我们运行程序:

运行时java的类加载器会将class文件加载进去,然后进行链接、初始化,最终执行

java -classpath "D:\project\lib\spring-core-5.0.7.RELEASE.jar;." -verbose packageA/Main

##output:name is aaaa

java需要转go吗,【Java转Go】弄清GOPATH相关推荐

  1. 广东java工资一般多少_广东java工资待遇,广东java工资一般多少,广东java工资底薪最低多少...

    广东java工资待遇,广东java工资一般多少,广东java工资底薪最低多少 首页 > java > 广东java工资待遇 作者:镀金池   发布时间:2018-12-22 11:20 在 ...

  2. inside java security_Inside The JVM Part2: java如何实现安全性

    网络移动性和平台无关性略过...看看java如何实现安全性 Java通过提供一个"安全沙箱"来保证从网络或者其他不信任的地方下载并运行的程序不会破坏本地数据,为了确保沙箱是可靠的, ...

  3. java ee 6 sdk中文版,Java EE 6 SDK+Eclipse JEE+Android ADT-Fun言

    很多时候,为了生存,需要不断的了解,学习新东西,于是头脑塞满了便便- -|||- -----------------------.. 按照自己的理解: JDK = Java Develope Kit ...

  4. java 生成pdf itext_使用Java组件itext 生成pdf介绍

    iText是一个能够快速产生PDF文件的Java类库.iText的java类对于那些要产生包含文本,表格,图形的只读文档是很有用的.它的类库尤其与java Servlet有很好的给合.使用iText与 ...

  5. java初始化数据报_初始化java原因

    虚拟机的类加载机制 虚拟机把描述类的数据从Class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的Java类 即虚拟机的类加载机制. 在Java中,类型的加载.链接 ...

  6. java中的action_浅析java中action的作用

    正如早先指出的那样,action()并不是我们对所有事进行分类后自动为handleEvent()调用的唯一方法.有三个其它的被调用的方法集,如果我们想捕捉某些类型的事件(键盘.鼠标和焦点事件),因此我 ...

  7. java写exe程序实例,java实现可安装的exe程序实例详解

    java实现可安装的exe程序实例详解 通过编写java代码,实现可安装的exe文件的一般思路: 1.在eclipse中创建java项目,然后编写java代码,将编写好的java项目导出一个.jar格 ...

  8. java基础入门传智播客 源码_Java-_2020年版Java零基础视频教程(Java 0基础,Java初学入门)魔鬼讲师老杜出品...

    不会闲聊!!!不会扯淡!!!小UP只会分享与Java相关的学习资源 还记得那年带你Java入门的一声"吼"吗? B站目前播放量已经快到450多万播放量的Java零基础教程的创作者& ...

  9. Java项目:车租赁管理系统(java+Gui+文档)

    源码获取:博客首页 "资源" 里下载! 功能介绍: 登陆界面.管理员界面.用户界面.汽车租赁文档 系统主页: @SuppressWarnings("serial" ...

  10. 编写运行最简单的java程序——使用记事本编写java程序

    编写运行最简单的java程序--使用记事本编写java程序 第一个java程序--使用记事本编辑 经过上篇文章的java环境搭建成功的小伙伴们可以在自己的计算机上编写属于自己的java程序了yo~ 还 ...

最新文章

  1. 思科——单臂路由与DHCP的结合
  2. caffe FCN网络的训练——以SIFT-Flow 数据集为例
  3. python怎么安装pip-安装 Python 模块
  4. 独立开发者:新手做2D手游该用哪些工具?
  5. MySQL数据库同步小工具(Java实现)
  6. linux tomcat6 jmx,Zabbix3.2.6之通过JMX监控Tomcat
  7. Redis张工的set存储结构(实现)原理
  8. sas数据导入终极汇总-之二
  9. 男女之间应该保留多少隐私
  10. python pdb调试基本命令整理
  11. 百度网盘搜索源码,新加分词功能,内容相关度聚合更高
  12. 《业务需求说明书》检查单 zz
  13. 关于MDT自动部署软件的一些资料
  14. Proteus8.版本以上中文教程
  15. 读《GRESNET: GRAPH RESIDUAL NETWORK FOR REVIVING DEEP GNNS FROM SUSPENDED ANIMATION》
  16. 写给跨端玩家:支撑淘宝上亿日活的跨端框架—— Rax 的入门教程(附 TODO Demo)
  17. 如何关闭联想电脑的大小写切换桌面提示
  18. 虚拟机-安装与使用(详细教程)
  19. C/C++中宏概念理解
  20. 大数据学习笔记之一:Hadoop 常用指令集合与启动注意项

热门文章

  1. Python切片中的误区与高级用法
  2. Python中国际化(i18n)完整指南
  3. int main中char** argv与char *argv[]区别?(main函数)
  4. linux shell #[感叹号]/bin/bash 是什么意思?
  5. Angular CLI版本问题(Your global Angular CLI version (12.2.7) is greater than your local version (9.0.3))
  6. Intel Realsense C/C++ 转 python rs-align 使用深度颜色映射介绍空间流对齐的概念(转不起来,缺少信息)
  7. C++ 中 vector 的作用:
  8. linux——Shell脚本说明、创建、执行、调试
  9. 黑马程序员pink老师前端入门教程,零基础必看的h5(html5)+css3+移动端前端视频教程(边框,阴影,浮动)
  10. 你学废了 Mybatis 动态批量修改吗?