前面两小节讨论的都是 CPU、Java 虚拟机的字节序,通常叫做主机(host)字节序。在网络编程中,字节流在网络中传输是遵循大端序的,也叫网络字节序。由于 Java 虚拟机的字节序和网络字节序是一致的,对于 Java 程序员来说,通常不太关心字节序的问题。然而,当 Java 程序和 C 程序进行通信的时候,需要关心字节序的问题。
1.1 基础环境推荐内存2G以上磁盘4G以上操作系统Windows7及以上, MacOs, Linux(Unbuntu)1.2 安装包准备首先,需要在 PC 操作系统(Windows、Mac 或 Linux)上安装 Eclipse IDE。由于 Eclipse 有很多的版本,这里推荐下载 Eclipse IDE for Java Developers 的版本,因为可能在其他版本对 Kotlin 支持不是很好。Eclipse IDE for Java Developers 下载:Mac下载 Eclipse IDE for Java Developers;Windows下载 Eclipse IDE for Java Developers;Linux下载 Eclipse IDE for Java Developers。
在 Kotlin 中默认修饰符与 Java 则不一样,在 Kotlin 默认是 public 而 Java 则默认是 default (包级可见性)。此外 Kotlin 中还存在独有的 internal 访问可见修饰符。下面列出一张对应表格修饰符表示含义与 Java 比较 publicKotlin 默认修饰符,全局可见与 Java 中显式指定的 public 效果一致 protected 受保护修饰符,类和子类可见与 Java 一致,除了类和子类可见,其包内也可见 private 私有修饰符,只有本类可见,类外文件内可见只能类内可见 internal 模块内可见无该修饰符
大部分听过 Eclipse 的人都会认为它就是一个 Java 集成开发环境(IDE)。但是如果跳出工具软件的概念,Eclipse 可以看做是一个开源社区,这个开源社区专注于构建一个免费开放的开发平台。需要指出的是,大部分人都认为 Eclipse 就是一款被 Java 开发人员用于 Java 开发的工具。但是事实上,Eclipse 对于不同的人来说可能是不同的。因为 Eclipse 提供了插件开发环境(Plug-in Development Environment,简称 PDE) ,它允许所有对 Eclipse 感兴趣的人都可以通过插件来扩展 Eclipse,比如 JDT(Eclipse 中的 Java 开发工具)。这就使用 Eclipse 的使用并不限于 Java 语言(Eclipse 官方就提供了 C/C++、PHP、JavaScript、Rust 等语言版本)。所以,虽然大部分时候 Eclipse 都是指 Java 集成开发环境(IDE),但有时候也可能是指其他语言的集成开发环境。 面向 C/C++ 开发人员的 Eclipse上图是官网所提供的用于 C 和 C++ 开发的 Eclipse IDE。
列表的定义跟 Java 差不多,但是较 Java 中比较简单。我们从代码中来比较:class Example { static void main(String[] args) { // Java的定义方式 def list = new ArrayList() //定义一个空的列表//groovy中定义 def list2 = [] //定义一个空的列表 def list3 = [1,2,3,4] //定义一个非空的列表 println list2.class println list3.class };}--------------输出----------------class java.util.ArrayListclass java.util.ArrayList----------------------------------我们从上面看到,这样定义完是跟 Java 一样的都是ArrayList。下面我们再看下在 Groovy 中定义数组://在groovy中使用as关键字定义数组def array = [1,2,3,4] as int[]//或者使用强类型的定义方式int[] array2 = [1,2,3]Tips: 在 Groovy 中定义数组的方式有两周,一种是跟 Java 一样直接指定 int,一种是用as关键字,但是我们使用时要注意和 List 的区别。
一个 Web 项目可以简单地仅由一些静态的 Web 页面构成,也可以包含更高级的动态功能注意理解这里的所说的动静态并不是指网页的内容是否有动态展示。而是其中的项目中的数据开始和服务器进行交互了。对于 Java 项目,Eclipse 提供了完整的动/静态 Web 项目的支持,包括了 HTML,CSS,JavaScript, JavaServer Pages(JSP)和 Java servlet 的支持,创建和编辑Web应用程序部署描述符(web.xml)文件,Web存档(WAR)文件的导入导出等功能。本章节,我们将介绍如何在 Eclipse 中创建一个 Java Web 项目。涉及到 Java Web 部分,我们后面的章节都将开始使用 Java EE 版本的 Eclipse,它对于 Web 项目提供了更加全面的支持。
Spring MVC 项目可以真正意义上实现零 XML 配置,注意不是不配置,而是可以不使用 XML 配置。Spring MVC 提供了大量的注解,让 JAVA 开发者以自己最擅长的 JAVA 语法编写配置信息。本节课程,将向大家介绍如何使用纯 JAVA 的方式搭建 Spring MVC 项目,通过本节课程,你将学习到:了解搭建 Spring MVC 的流程。这既是本章节的难点也是重点;了解纯 JAVA 配置的重要注解。
在 Java 开发程序的过程中,经常会去调用一些方法,有的人设计方法的参数有很多,而且参数命名有时候还不太规范(不能达到见名知意),并且设计的时候几个相同的参数类型还是挨着的。这个实际上给调用者带来了很大的困扰和麻烦,谨慎的程序猿会定位到这个函数定义的地方,大概看了下参数的调用的顺序以及每个参数的函数。特别当这个方法被打包成一个 lib 的时候,查看就比较麻烦。而且相同类型参数挨着很容易对应错。一起看个例子: // A开发的函数接口顺序(调用者必须按照这个顺序传) static String joinToString(List<Integer> nums, String prex, String sep, String postfix) { StringBuilder builder = new StringBuilder(prex); for (int i = 0; i < nums.size(); i++) { builder.append(i); if (i < nums.size() - 1) { builder.append(sep); } } builder.append(postfix); return builder.toString(); } // B开发的函数接口顺序(调用者必须按照这个顺序传) static String joinToString(List<Integer> nums, String prex, String postfix, String sep) { StringBuilder builder = new StringBuilder(prex); for (int i = 0; i < nums.size(); i++) { builder.append(i); if (i < nums.size() - 1) { builder.append(sep); } } builder.append(postfix); return builder.toString(); } //假如现在修改一下,拼接串前缀或分隔符,仅从外部调用是无法知道哪个参数是前缀、分隔符、后缀 public static void main(String[] args) { //后面传入的三个字符串顺序很容易传错,并且外部调用者如果不看具体函数定义根本很难知道每个字符串参数的含义,特别公司中一些远古代码,可能还得打成库的代码,点进去看实现肯定蛋疼。 //调用A的接口 System.out.println(joinToString(Arrays.asList(new Integer[]{1, 3, 5, 7, 9}), "<", ",", ">")); //调用B的接口 System.out.println(joinToString(Arrays.asList(new Integer[]{1, 3, 5, 7, 9}), "<", ">", ",")); }其实针对以上问题,AndroidStudio 的给我们做了个很好的优化提示,但是在 3.0 之前是没有这个提示的,如图:实际上 jetBrains 实际上把这个提示是直接融入了他们开发的Kotlin语言中,力图开发者尽量让在语法的层面上少犯错误,少走弯路,更加注重于代码本身的实现;让你直接在语法的层面上就更加明确,减少疑惑性。
@JvmStatic 的作用能被用在对象声明或者 Companion object 伴生对象的方法上,把它们暴露成一个 Java 的静态方法源码定义//作用于函数、属性、属性的setter和getter@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)@MustBeDocumented@OptionalExpectationpublic expect annotation class JvmStatic()注解使用@JvmStatic 这个注解一般经常用于伴生对象的方法上,供给 Java 代码调用:class Data { companion object { fun getDefaultDataName(): String { return "default" } }}//在java中调用,只能是Data.Companion.getDefaultDataName()调用public class Test { public static void main(String[] args) { System.out.println(Data.Companion.getDefaultDataName()); }}反编译后 Java 代码:public final class Data { public static final Data.Companion Companion = new Data.Companion((DefaultConstructorMarker)null); public static final class Companion { @NotNull public final String getDefaultDataName() { return "default"; } private Companion() { } // $FF: synthetic method public Companion(DefaultConstructorMarker $constructor_marker) { this(); } }}使用 @JvmStatic 注解后:class Data { companion object { @JvmStatic fun getDefaultDataName(): String { return "default" } }}//在java中调用,可以直接这样Data.getDefaultDataName()调用public class Test { public static void main(String[] args) { System.out.println(Data.getDefaultDataName()); }}反编译后的 Java 代码public final class Data { public static final Data.Companion Companion = new Data.Companion((DefaultConstructorMarker)null); @JvmStatic @NotNull //注意它会在Data类内部自动生成一个getDefaultDataName,然后内部还是通过Companion.getDefaultDataName()去调用。 public static final String getDefaultDataName() { return Companion.getDefaultDataName(); } public static final class Companion { @JvmStatic @NotNull public final String getDefaultDataName() { return "default"; } private Companion() { } // $FF: synthetic method public Companion(DefaultConstructorMarker $constructor_marker) { this(); } }}
在 Lambda 表达式出现之前,一个 Java 程序的行为总是与对象关联,以标识、状态和行为为特征。然而 Lambda 表达式则违背了这个规则。虽然 Lambda 表达式可以共享对象的一些属性,但是表示行为是其唯一的用处。由于没有状态,所以表示问题也就不那么重要了。在 Java 语言的规范中对 Lambda 表达式唯一的要求就是必须计算出其实现的相当的函数接口的实例类。如果 Java 对每个 Lambda 表达式都拥有唯一的表示,那么 Java 就没有足够的灵活性来对系统进行优化。
按照上面的操作,我们已经在 Linux 上成功安装了 JDK 14 ,接下来我们需要配置一个 JAVA_HOME环境变量,来指向 Java 的安装目录,并且将JAVA_HOME的bin目录附加到系统变量的PATH上, 其目的是为了我们在任何目录位置都可以执行 java 命令。Java 的默认安装目录为 /usr/java/jdk-14,编辑启动脚本 ~/.bash_profile,在启动脚本下添加如下两行命令export JAVA_HOME=/usr/java/jdk-14export PATH=$JAVA_HOME/bin:$PATH为了让刚刚在启动脚本添加的环境变量生效,执行 source 命令:source ~/.bash_profile最后,打印一下 PATH 系统变量,查看环境变量是否正确添加:[root@Colorful ~]# echo $PATH/usr/java/jdk-14/bin:/usr/java/jdk-13.0.2/bin:/usr/local/node/8.11.1/bin:/usr/local/node/8.9.3/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/root/bin:/root/bin
在 Kotlin 中的循环有两种方式分别是for,while,在for循环中使用"in"来遍历,并且有两个遍历方式。1. for 循环:val items = listOf("java", "kotlin", "android")for (item in items) {//for遍历集合 println("lang $item")}for (index in items.indices) {//类似于java中的数组的length-index的遍历 println("The $index index is ${items[index]}")}2. while 循环:val items = listOf("java", "kotlin", "android")var index = 0while (index < items.size) {//while 循环的遍历方式 println("The $index lang is ${items[index++]}")}
1. 对集合进行迭代:fun main(args: Array<String>) { val items = list.of("java", "kotlin", "python") for (item in items) { println(item) }}2. 使用 in 运算符判断集合内是否包含某个实例:when { "java" in items -> println("is good lang") "kotlin" in items -> println("is good good lang") else -> println("python is best lang")}3. 使用 lambda 表达式来过滤(filter)和映射(map)集合:fun main(args: Array<String>) { val langs = listOf("C", "C++", "Java", "Python", "JavaScript") langs.filter { it.startsWith("C") } .sortedBy { it } .map { it.toUpperCase() } .forEach { println(it) }}
参数作用:-XX:+TraceClassLoading 参数是为了跟踪类的加载。为了更好的理解并掌握 -XX:+TraceClassLoading 参数,我们通过如下步骤进行操作。步骤 1:在 VM Options 中配置参数 -XX:+TraceClassLoading 并保存;步骤 2:运行示例代码,观察执行结果。结果验证:由于追踪的结果日志非常庞大,此处仅展示具有代表性的类的加载。全部的类加载日志,请学习者自行执行代码进行验证。[Opened C:\Program Files\Java\jdk1.8.0_152\jre\lib\rt.jar][Loaded java.lang.Object from C:\Program Files\Java\jdk1.8.0_152\jre\lib\rt.jar][Loaded java.util.ArrayList$SubList from C:\Program Files\Java\jdk1.8.0_152\jre\lib\rt.jar][Loaded java.util.ListIterator from C:\Program Files\Java\jdk1.8.0_152\jre\lib\rt.jar][Loaded java.util.ArrayList$SubList$1 from C:\Program Files\Java\jdk1.8.0_152\jre\lib\rt.jar][Loaded DemoMain.TracingClassParamsDemo from file:/D:/GIT-Repositories/GitLab/Demo/out/production/Demo/][Loaded java.lang.Class$MethodArray from C:\Program Files\Java\jdk1.8.0_152\jre\lib\rt.jar][Loaded java.lang.Void from C:\Program Files\Java\jdk1.8.0_152\jre\lib\rt.jar][Loaded java.lang.Shutdown from C:\Program Files\Java\jdk1.8.0_152\jre\lib\rt.jar][Loaded java.lang.Shutdown$Lock from C:\Program Files\Java\jdk1.8.0_152\jre\lib\rt.jar]结果分析:我们来对类的加载日志进行分析。第一行:Opened rt.jar。打开 rt.jar,rt.jar 全称是 Runtime,该 jar 包含了所有支持 Java 运行的核心类库,是类加载的第一步;第二行:加载 java.lang.Object。Object 是所有对象的父类,是首要加载的类;第三、四、五行:加载了 ArrayList 的相关类,我们的示例代码中使用到了 ArrayList,因此需要对该类进行加载;第六行:加载我们的测试类 TracingClassParamsDemo ;第七行:加载 java.lang.Class 类,并加载类方法 MethodArray;第八行:加载 java.lang.Void 类,因为我们的 main 函数是 void 的返回值类型,所以需要加载此类;第九、十行:加载 java.lang.Shutdown 类, JVM 结束运行后,关闭 JVM 虚拟机。从以上对日志的分析来看,JVM 对类的加载,不仅仅加载我们代码中使用的类,还需要加载各种支持 Java 运行的核心类。类加载的日志量非常庞大,此处仅仅对重点类的加载进行日志的解读,全部的类加载日志,请学习者自行执行代码进行验证。
打开 Eclipse 官网下载地址 ,点击 Download Packages。找到 Eclipse IDE for Java Developers,这个包是任何 Java 开发者都可以使用的一个基本工具。点击右侧对应平台的下载链接即可开始下载。
接下来引入mysql-connector-java驱动,由于我本地安装的MySQL版本为8.0.21,因此mysql-connector-java的版本号也选择8.0.21,大家根据自己实际情况选择对应版本。打开pom.xml文件,在<dependencies></dependencies>节点内插入如下xml:<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java --><dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>8.0.21</version></dependency>由于我们已经配置了允许自动导入依赖,稍等片刻,mysql-connector-java 8.0.21就会被成功导入。可在idea右侧点击Maven按钮查看项目的依赖关系:
本章节讲解了如何使用 XML 方式搭建 Spring MVC 项目,虽然现在流行使用 JAVA 方式,但 XML 仍然是一个不错的选择。无论是使用 XML 还是 JAVA 方式,其本质是一样的,只是使用了不同的语法方式进行表达。这相当于有人用英文或中文对你说 “我爱你”。当然,你需要了解英文或中文。对于 Spring MVC 而言,对 XML 和 JAVA 的理解是无障碍的。也意味着你可以随心选择 JAVA 或 XML 方式。
在 Java 中定义无返回值类型的函数一般是使用void, 在 Kotlin 中则使用Unit, 或者省略Unit类型。//Kotlin定义fun output(userName: String): Unit { println("current user name is $userName")}//可简写成以下形式fun output(userName: String) { println("current user name is $userName")}//Java定义public void output(String userName) {//注意在Java中 void不能省略 System.out.println("current user name is " + userName);}
这篇文章一起来看下 Kotlin 中类型系统,其中涉及到一个很重要的概念就是大家常说的可空性以及为什么 Kotlin 相比 Java 在一定程度上能降低空指针异常。此外在 Kotlin 中完全采用和 Java 不同思路来定义它的类型系统。也正因为这样类型系统天然具有让 Kotlin 在空指针异常出现的频率明显低于 Java出现的频率的优势。此外 Kotlin 考虑使用和 Java 完全不同类型系统,以及它是如何去做到极大兼容和互操作。
在 Kotlin 中最大的一个特点就是可以和 Java 做到极高的互操作性,我们知道 Kotlin 的语法和 Java 语法还是有很大的不同,要想做到与 Java 做到很大兼容性可能需要携带一些额外信息,供编译器或者运行时做类似兼容转换。其中注解就起到了很大的作用,在 Kotlin 内置很多个注解为了解决 Java 中的调用 Kotlin API 的一些调用习惯和控制 API 的调用。它们就是 Kotlin 中的 @Jvm 系列的注解,咱们一一来看下它们都有哪些。
关键字 (Keyword) 是 Java 语言中的特殊标记。它已经被语言本身预先使用,因此我们不能使用关键字作为我们标识符的命名。例如 Java 基本类型的 int、boolean,流程控制语句中的 if、for,访问修饰符 public,以及一些用于声明和定义 Java 类、包、接口的 class、package、interface。而保留字 (Reserved word) 可能是未来的关键字,也就是说可能在未来的版本中,Java 语言作为特殊标记。Tips:无论是关键字还是保留字,我们都要记住:不能使用它们作为我们的代码中的标识符。
在构建 Java 项目时,我们通常会选择源代码和编译结果保存到不同的文件夹中。这项功能在 Eclipse 中的设置位于首选项中的 Java > Build Path,我们勾选 Folders 选项即可,如下图所示:
自定义枚举类有两种方式:在 Java 5.0 之前,需要通过普通 Java 类的“改装”来定义一个枚举类;在 Java 5.0 之后,可以使用 enum关键字来定义枚举类。下面我们分别来看下这两种定义枚举类的方式。
JVM 是 Java 语言的一大关键亮点,对于 JVM 的作用,我们这里介绍两个主要的作用,来体现 JVM 的价值所在。跨平台性:Java 语言之所以有跨平台的优点,完全是 JVM 的功劳,跨平台性是 JVM 存在的最大的亮点。以上一个知识点部分所举出例子来说,Windows 操作系统安装上 JVM 之后,可以支持 Java 程序的运行; Linux 操作系统安装上 JVM 之后,可以支持 Java 程序的运行;同理,Unix 操作系统等等所有我们熟悉的操作系统,安装上 JVM 之后,都可以支持 Java 程序的运行。这大大提升了 Java 语言的平台灵活性,能够在众多语言争鸣的时代,脱颖而出。优秀的垃圾回收机制: Java 语言的诞生,极大的降低了软件开发人员的学习难度,除了 Java 面向对象编程的特性能够降低学习难度以外,还有一个比较重要的点,就是在进行 Java 编程的时候,可以更少的去考虑垃圾回收机制。学习过 C 语言的技术人员都能够体会这一点,因为 C 语言编程过程中,要通过代码手动实现内存垃圾的回收与空间释放,这提升了编程的难度,因为考虑内存空间释放,更多的会涉及到底层的知识,这是非常高的一个门槛。从 JVM 的角度来说,JVM 拥有自己的垃圾回收机制,为开发人员分担了部分工作。Tips:JVM 在 Java 语言中占据了非常重要的地位,学习 JVM 是 Java 技术人员必须要做的事情,目前企业对于 Java 从业者对 JVM 的掌握程度要求非常高,是重点学习内容。
在上一节中我们学习了 Zookeeper 的 Java 客户端之一 ZkClient ,除了 ZkClient 之外,还有就是 Zookeeper 最流行的 Java 客户端之一的 Curator。Curator 与 ZkClient 相比较又有什么区别呢?接下来我们就开始 Curator 的学习。