3.1_2 JavaSE入门 P1 【Java基础】Java语言概述、JDK编译

相关链接



All From 传智培训课程 + 后期自己整理补充内容

  • 搭建maven项目运行,参考pom.xml 用junit测试类执行代码
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>4.1.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>8</source>
                    <target>8</target>
                </configuration>
            </plugin>
        </plugins>
    </build>

Part1 Java语言概述

1 Java语言概述


1.1 Java发展史

  1991年4月,由詹姆斯高斯林(James Gosling)博士领导的绿色计划(Green Project)开始启动,此计划最初的目标是开发一种能够在各种消费性电子产品(如机顶盒、冰箱、收音机等)上运行的程序架构。这个计划的产品就是Java语言的前身:Oak(得名与James Gosling办公室外的一棵橡树)。Oak当时在消费品市场上并不算成功,但随着1995年互联网潮流的兴起,Oak迅速找到了最适合自己发展的市场定位并蜕变成为Java语言。
在这里插入图片描述
  1995 年 5 月 23 日,Oak语言改名为Java,并且在SunWorld大会上正式发布Java 1.0 版本。Java语言第一次提出了“Write Once,Run Anywhere”的口号。

  1996 年 1 月 23 日,JDK 1.0 发布,Java语言有了第一个正式版本的运行环境。JDK 1.0 提供了一个纯解释执行的Java虚拟机实现(Sun Classic VM)。JDK 1.0 版本的代表技术包括:Java虚拟机、Applet、AWT等。

  1996 年 4 月,十个最主要的操作系统和计算机供应商声明将在产品中嵌入Java技术。同年9月,已有大约8.3万个网页应用了Java技术来制作。在1996年5月底,Sun于美国旧金山举行了首届JavaOne大会,从此JavaOne成为全世界数百万Java语言开发者每年一度技术盛会。

  1997 年 4 月,Sun公司发布了 JDK 1.1,Java里许多最基础的技术支撑点(如JDBC)等都是在JDK 1.1 版本中提出的,JDK 1.1 版的技术代表有:JAR文件格式JDBCJavaBeansRMI等。Java语言的语法也有了一定的增强,如内部类(Inner Class)反射(Reflection)都是在这个时候出现的。

  直到1994 年 4 月 8 日,JDK 1.1 一共发布了 1.1.0 至 1.1.8 这9个版本。从 1.1.4 以后,每个JDK版本都有一个属于自己的名字(工程代号),分别为:JDK 1.1.4 - Sparkler(报送)、JDK 1.1.5 - Pumpkin
(南瓜)、JDK 1.1.6 - Abigial
(阿比盖尔,女子名)、JDK 1.1.7 Brutus
(布鲁图,古罗马政治家和将军)和 JDK 1.1.8 - Chelsea
(切尔西,城市名)。

  1998 年 12 月 4 日,JDK迎来了一个里程碑式的重要版本:工程代号为 Playground(竞技场)的 JDK 1.2,Sun在这个版本中把Java技术体系拆分为三个方向,分别是面向桌面应用开发的 J2SE(Java 2 Platform,Standard Edition)、面向企业级开发的 J2EE(Java 2 Platform,Enterprise Edition)和面向手机等移动终端开发的 J2ME(Java 2 Platform,MicroEdition)。在这个版本中出现的代表性技术非常多,如 EJBJava Plug-inJava IDLSwing等,并且这个版本中 Java 虚拟机第一次内置了JIT(Just In Time)即时编译器(JDK 1.2 中曾并存过三个虚拟机,Classic VMHotSpot VMExact VM,其中 Exact VM 只在 Solaris 平台出现过;后面两款虚拟机都是内置了 JIT 即时编译器的,而之前版本所带的 Classic VM 只能以外挂的形式使用即时编译器)。在语言和 API 层面上,Java 添加了 strictfp 关键字,Java 类库添加了现在 Java 编码之中极为常用的一系列 Collections 集合类等。在 1999 年 3 月和 7 月,分别有 JDK1.2.1 和 JDK 1.2.2 两个小升级版本发布。

  1999 年 4 月 27 日,HotSpot 虚拟机诞生。HotSpot 最初由一家名为 “Longview Technologies” 的小公司开发,由于 HotSpot 的优异表现,这家公司在 1997 年被 Sun 公司收购。HotSpot 虚拟机刚刚发布时是作为 JDK 1.2 的附加程序提供的,后来他成为 JDK 1.3 及之后所有 JDK 版本默认的 Java 虚拟机。

  2000 年 5 月 8 日,工程代号为 Kestrel(美洲红隼)的 JDK 1.3 发布。相对于 JDK 1.2,JDK 1.3 的改进主要体现在 Java 类库上(如数学运算和新的 Timer API 等),JNDI 服务从 JDK 1.3 开始被作为一项平台级服务提供(以前 JNDI 仅仅是一项扩展服务),使用 CORBAIIOP 来实现 RMI 的通信协议,等等。这个版本还对 Java 2D 做了很多改进,提供了大量新的 Java 2D API,并添加了新的 JavaSound 类库。 JDK 1.3 有一个修正版本 JDK 1.3.1,工程代号为 Ladybird(瓢虫),于 2001 年 5 月 17 日发布。

  自从 JDK 1.3 开始,Sun 公司维持着稳定的研发节奏:大约每隔两年发布一个 JDK 的主版本,以动物命名,期间发布的各个修正版本则以昆虫作为工程代号。

  2002 年 2 月 13 日,JDK 1.4 发布,工程代号为 Merlin(灰背隼)。JDK 1.4 是标志着 Java 真正走向成熟的一个版本,Compaq、Fujitsu、SAS、Symbian、IBM等著名公司都有参与功能规划、甚至实现自己独立发行的 JDK 1.4 。哪怕是在近二十年后的今天,仍然有一些主流应用能够运行在 1.4 上的版本,JDK 1.4 同样带来了很多新的技术特性,如正则表达式异常链NIO日志类XML 解析器XSLT 转换器,等等。JDK 1.4 有两个后续修正版:2002 年 9 月 16 日发布的工程代号为 Grasshopper(蚱蜢)的 JDK 1.4.1 与 2003 年 6 月 26 日发布的工程代号为 Mantis(螳螂)的 JDK 1.4.2。

  2002 年前后还发生了一件与 Java 没有直接关系,但事实上对 Java 的发展进程影响很大的事件,就是微软的 .NET Framework 发布 。这个无论是技术实现还是目标用于上都与 Java 有很多相近之处的技术平台给 Java 带来了很多讨论、比较与竞争增, .NET 平台和 Java 平台之间声势浩大的孰优孰劣的论战到今天为止都仍没有完全平息。

  2004 年 9 月 23 日,JDK 5 发布,工程代号为 Tiger(老虎)。Sun 公司从这个版本开始放弃了谦逊的 “JDK 1.x” 的命名方式,将产品版本号修改成了 “JDK x”。从 JDK 1.2 以来,Java在语法层面上的变动一直很小,而 JDK 5 的 Java 语法易用性上做出了非常大的改进。如:自动装箱泛型动态注解枚举可变长参数遍历循环(foreache循环)等语法特性都是在 JDK 5 中加入的。在虚拟机和 API 层面上,这个版本改进了 Java 的内存模型(Java Memory Model,JMM)、提供了 java.util.concurrent 并发包等。另外, JDK 5 是官方声明可以支持 Windows 9x 操作系统的最后一个 JDK 版本。

JDK x:Java 从 1.5 版本开始,官方在正式文档与宣传上已经不再使用类似 “JDK 1.5” 的命名,只有程序员内部使用的开发版本号(Developer Version,例如 java -version 的输出)中才继续沿用 1.5 、1.6、1.7 这样的版本号,而公开版本号(Product Version)则是改为 JDK 5.0、JDK 6 、JDK 7 的命名方式,JDK 5.0 中的 “.0” 的后缀从 JDK 6 起也被移除掉。


  2006 年 12 月 11 日,JDK6 发布,工程代号为 Mustang(野马)。在这个版本中,Sun 公司终结了从 JDK 1.2 开始已有八年历史的 J2EE、J2SE、J2ME 的产品线命名方式,启动 Java EE 6、Java SE 6、Java ME 6 的新命名来代替。JDK 6 的改进包括:提供初步的动态语言支持(通过内置的 Mozilla JavaSript Rhino 引擎实现)、提供编译器注解处理器微型 HTTP 服务器 API,等等。同时,这个版本对 Java 虚拟机内部做了大量改进,包括锁与同步垃圾收集类加载等方面的实现都有相当多的改动。

  在 2006 年 11 月 13 日的 JavaOne 大会上,Sun 公司宣布计划要把 Java 开源,在随后的一年多时间内,他陆续的将 JDK 的各个部分在 GPL v2(GNU General Public License v2)协议下公开了源码,并建立了 OpenJDK 组织对这些源码进行独立管理。除了极少量的产权代码(Encumbered Code,这部分代码所有权不属于 Sun 公司,Sun本身也无权进行开源处理)外,OpenJDK 几乎拥有了当时 SunJDK 7 的全部代码,OpenJDK 的质量主管曾经表示在 JDK 7 中,SunJDK 和 OpenJDK 除了代码文件头的版权注释之外,代码几乎是完全一样的,所以 OpenJDK 7 与 SunJDK 7 本质上就是同一套代码库出来的产品。

  JDK 6 发布以后,由于代码复杂性的增加、Java 开源、开发 JavaFX、世界经济危机及 Oracle 对 Sun 的收购案等原因,Sun公司在发展 Java以外的事情上耗费了太多精力和资源, JDK 的更新没有能够继续维持两年发布一个主版本的研发速度,这导致了 JDK 6 的生命周期异常的长,一共发布了 211 个更新升级补丁,最后的版本为 Java SE 6 Update 211,于2018 年 10 月 18 日发布。

  2009 年 2 月 19 日,工程代号为 Dolphin(海豚)的 JDK 7 完成了其第一个里程碑版本。按照 JDK 7 最初的功能规划,一共会设置十个里程碑。最后一个里程碑版本原计划定于 2010 年 9 月 9 日结束,但由于各种原因, JDK 7 最终无法按计划完成。

  从 JDK 7 最原始的功能清单来看,它本应是一个包含许多重要改进的 JDK 版本,其中规划的子项目都为 Java 业界翘首以盼,包括:

  • Lambda 项目:支持 Lambda 表达式,支持函数式编程
  • Jigsaw 项目:虚拟机层面的模块化支持
  • 动态语言支持:Java 是静态语言,为其它运行在 Java 虚拟机上的动态语言提供支持。
  • Garbage-First 收集器
  • Coin 项目:Java语法细节进化


  令人惋惜的是,在 JDK 7 开发期间,Sun 公司相继在技术竞争和商业竞争中陷入泥潭,公司的股票市值跌至仅有高峰时期的 3%,已无力推动 JDK 7 的研发工作按计划继续进行。为了尽快结束 JDK 7 长期跳票的问题,Oracle 收购 Sun公司后随即宣布马上实行 “ B计划 ”,大幅裁减了 JDK 7 预定目标,以保证 JDK 7 的正式版能够于 2011 年 7 月 28 日准时发布。 “ B 计划 ” 的主要措施是吧不能按时完成的 Lambda 项目、Jigsaw 项目和 Coin 项目的部分改进延迟到 JDK 8 之中。最终, JDK 7 包含的改进有:提供新的 G1 收集器(G1 在发布时依然处于 Experimental 状态,直至 2012 年 4 月的 Update 4 中才正式商用)、加强对非 Java 语言的调用支持(JSR-292,这项特性在到 JDK 11 还有改动)、可并行的类加载架构等。

  Oracle 公司接手了 JDK 开发工作以后,迅速展现出了完全不同于 Sun 时期的、极具商业化的处事风格。面对 Java 中使用最广泛而又一直免费的 Java SE 产品线, Oralce 很快定义了一套新的 Java SE Support 产品计划,把 JDK 的更新支持作为一项商业服务。 JDK 7 发布的前 80 个更新仍然免费面向所有用户提供,但后续的其他更新包,用户只能从 “将 Java SE 升级到 Java SE Support ” 与 “将 JDK 7 升级到最新版本”两个选项里挑一个。 JDK 7 计划维护至 2022年,迄今(面向付费用户)已经发布了超过两百个更新补丁,最最新版本为 JDK 7 Update 221。

Java SE Support:除了 Java SE Support 外,还有面向独立软件提供商的 Java SE Advanced & Suite 产品线,差别是后者带有 JMC 等监控工具。详见《深入理解Java虚拟机》 第三版 第四章 周志明著。
用户:特指商业用户,个人实用仍然是可以免费获得这些更新包的。


  对于 JDK 7,还有一点值得提起的是,从 JDK 7 Update 4 起,Java SE 的核心功能正式开始为 Mac OS X 操作系统提供支持,并在 JDK 7 Update 6 中达到所有功能与 Mac OS X 完全兼容的程度;同时,JDK 7 Update 6 还对 ARM 指令集架构提供了支持。至此,官方提供的 JDK 可以运行于 Windows(不含 Windows 9x)、Linux、Solaris 和 Mac OS X 操作系统上,支持 ARM、x86、x86-64 和 SPARC 指令集架构,JDK 7 也是可以支持 Windows XP 操作系统的最后一个版本

最后一个版本:这是官方的声明,而事实上直到 JDK 8 Update 21 之前在 Windows XP 上仍可正常运行。


  2009 年 4 月 20 日,Oralce 宣布正式以 74 亿美元的价格收购市值曾超过 2000 亿美元的 Sun 公司,传奇的 Sun Microsystems 从此落幕成为历史,Java 商标正式划归 Oralce 所有(Java 语言本身并不属于哪间公司所有,他由 JCP 组织进行管理,尽管在 JCP 中 Sun 及后来的 Oracle 的话语权很大)。由于此前 Oralce 已经收购了另外一家大型的中间件企业 EBA 公司,当完成对 Sun 公司的收购之后,Oralce 分别从 BEA 和 Sun 手中取得了世界三大商用虚拟机的其中两个:JRockit 和 HotSpot。当时 Oracle 宣布要在未来一直两年的时间内,把这两个优秀的 Java 虚拟机合二为一(HotRockit)。两者合并的结果只能说差强人意,JRockit 的监控工具 Java Mission Control 被移植到了HotSpot,作为收费功能提供给购买了 Java SE Advanced 产品计划的用户,其他功能由于两者架构的差异性明显,HotSpot 能够直接借鉴融合的功能寥寥无几

HotRockit:“HotRockit” 项目的相关介绍: http://hirt.se/presentations/WhatToExpect.ppt (访问失败)
寥寥无几:除了 JMC 和 JFR ,HotSpot 用本地内存代替永久代实现方法区,支持本地内存使用情况追踪(NMT)功能是从 JRockit 借鉴过来的。


  JDK 8 的第一个正式版本原定于 2013 年 9 月发布,最终还是跳票导了 2014 年 3 月 18 日,尽管仍然是没有赶上正点,但比起 JDK 7 那种以年作为计时单位、直接把公司跳崩的研发状况已是大有改善。为了保证日后 JDK 研发能更顺利的进行,从 JDK 8 开始, Oracle 启用 JEP (JDK Enhancement Proposals)来定义和管理纳入新版 JDK 发布范围的功能特性。JDK 8 提供了那些曾在 JDK 7 中规划过,但最终未能在 JDK 7 中完成的功能,主要包括:

  • JEP 126:对 Lambda 表达式的支持,这让 Java 语言拥有了流畅的函数式表达能力。
  • JEP 104:内置 Nashorn JavaScript 引擎的支持。
  • JEP 150:新的时间、日期 API
  • JEP 122:彻底移除 HotSpot的永久代
  • ……


  “B计划” 中原本说好的会在 JDK 8 提供的 Jigsaw 模块化功能再次被延期到了 JDK 9,不得不说,即使放到整个 Java 发展史看,Jigsaw 都能算是天字第一号的大坑。Java 的模块化系统本身面临的技术挑战就很艰巨,从微软的 DLL 技术开始,到 Java 自己的 JAR,再到 .NET 的 Assembly,工程庞大起来都无一例外会陷入 “模块地狱” 的困境之中,而 Jigsaw 面临的更大困难是厂商之间以标准话语权为目的,以技术为 “找茬” 手段的激烈竞争。

模块地狱:来自于以前的 “DLL Hell”,如果不清楚什么是模块地狱的话,打开计算机的 windows 目录或者C:\\windows\system32 目录就明白了。


  原本 JDK 9 是计划在 2016 年发布的,但在 2016 年伊始,Oralce 就宣布 JDK 9 肯定要延期至 2017 年,后来又连续经过了两次短时间的跳票,最终到 2017 年 9 月 21 日才得以艰难面世。后两次跳票的原因是以 IBM 和 RedHat 为首:的十三家企业在 JCP 执行委员会上联手否决了 Oracle 提出的 Jigsaw 作为 Java 模块化规范进入 JDK 9 发布范围的提案。凭良心说,Java 确实有模块化的刚需,不论是 JDK 自身(例如拆分出 Java SE Embedded 这样规模较小的产品)亦或是 Java 应用都需要用到模块化。这方面 IBM 本身就是各大 Java 发行厂商中做得最好的,它不仅让自家的 JDK 实现了高度模块化,还带头成立了 OSGi 联盟,制定了 Java 框架层面模块化的事实标准,所以它当然会想把 OSGi 推到 Java 规范里去争个 “名份”,而不是被 Jigsaw 革掉 “性命”。可是 Oracle 对此没有丝毫退让,不惜向 JCP 发去公开信,直言如果提案最后无法通过,那 Oracle 将摒弃 JSR 专家组,独立发展带 Jigsaw 的 Java 版本,Java 顿时面临如 Python 2 与 Python 3 那般分裂的危机。

以 IBM 和 RedHat 为首:其实就是以 IBM 为首, IBM 一直与 RedHat 有密切合作,2018 年 IBM 以 340 亿美元天价收购了 RedHat 。
JDK 9 发布范围的提案:投票记录:https://jcp.org/en/jsr/results?id=5959
向 JCP 发去公开信:公开信:https://www.infoq.cn/article/2017/05/jigsaw-open-letter


  不论如何,经过前后六轮投票,经历桌上桌下的斗争与妥协,Java 没有分裂,JDK 9 总算是待着 Jigsaw 最终发布了,除了 Jigsaw 外,JDK 9 还增强了若干工具(JS ShellJLinkJHSDB等),整顿了 HotSpot 各个模块各自为战的日志系统,支持 HTTP 2 客户端 API 等 91 个 JEP。

  JDK 9 发布后,Oracle随即宣布 Java 将会以持续交付的形势和更加敏捷的研发节奏向前推进,以后 JDK 将会在每年的 3 月 9 月各发布一个大版本,目的就是为避免众多功能特性被集中捆绑到一个 JDK 版本上而引发交付风险。这次改革确实从根源上解决了跳票问题,但也为 Java 的用户和发行商带来了颇大的压力,不进程序员感慨 “Java 新版本还没开始用就已经过时了”,Oralce 自己对着一堆 JDK 版本分支也在挠头,不知道如何维护更新,如何提供技术支持。Oracle 的解决方案是顺理成章的终结掉 “每个 JDK 版本最少维护三年” 的优良传统,从此以后,每六个 JDK 大版本中才会被划出一个长期支持(Long Term Support,LTS)版,只有 LTS 版的 JDK 能够获得为期三年的支持和更新,普通版的 JDK 就只有短短六个月的生命周期。 JDK 8 和 JDK 11 会是 LTS 版,在下一个就到了 2021 年发布的 JDK 17 了。

大版本:也该掉了在开发版号中1.7、1.8的命名,从 JDK 10 后将是年份加月份作为开发版本号,比如 18.3 ,即表示 2018年 3 月的大版本。


  2018 年 3月 20 日, JDK 10 如期发布,这版本的主要研发目标是内部重构,诸如统一源仓库统一垃圾收集器接口统一即时编译器接口(JVMCI 在 JDK 9 已经有了,这里是引入新的 Graal 即时编译器)等,这些都将会是对未来 Java 发展大有脾益的改进,但对普通用户来说 JDK 10 的新特性就显得乏善可陈,毕竟它只包含了 12 个 JEP,而且其中只有本地类型推断这一个编码端可见的改进。尽管 JDK 10 可见的改进有限,但 2018 这一年 Java 圈丝毫不缺乏谈资,相继发生了几件与 “金钱” 相关的历史性大事件。

  首先是 2018 年 3 月 27 日,Android 的 Java 侵权案有了最终判决,法庭裁定 Google 赔偿 Oracle 合计 88 亿美元,要知道 2009 年 Oralce 收购 Sun 也就只花了 74 亿,收购完成后随机就用 Sun 的专利把 Google 告上了法庭,经过 Oralce 法务部的几轮神操作,一场官司的赔偿让收购 Sun 公司等同于免费。对此事 Java 技术圈多数吃瓜群众是站在 Google 这边的,认为 Oralce 这样做是自绝 Java 的发展前景,毕竟当年 Android 刚刚起步的时候可以 Sun 公司向 Google 抛去的橄榄枝,Android 的流行也巩固了 Java “第一编程语言” 的行业地位。摒弃对企业好恶情感,就事论事,Google 采用 Java 的语法和 API 类库,开发出来的程序却不能运行在其他 Java 虚拟机之上,这事情无论怎样都是有违 Java 技术的精神原旨的,也肯定违反了 Java 的使用协议。如果说 Oralce 控告 Google “不厚道”,那当年微软用 J++ 做了同样的事情(借用语法和 API,但程序不兼容标准 Java 虚拟机),被 Sun 告到登报道歉,一边赔款一遍割地,声明放弃 J++ 语言和 Windows 平台上的内置虚拟机,这又该找谁说理去?

使用协议:Oralce 与 Google 的官司主要焦点在于 Java API 的版权问题,而不在程序是程序能否运行在标准 Java 虚拟机上。


  按常理说 Java 刚给 Oralce 赚了 88 亿美金,该颇为受宠才对,可 Oralce 是典型之谈利益不讲情怀的公司,InfoWorld 披露了一封 Oralce 高管邮件表明,Java 体系中被认为无法盈利也没有太多战略前景的部分会逐渐被 “按计划报废”(Planned Obsolescence)。这事的第一刀落下是在 2018 年 3 月,Oralce 正式宣告 Java EE 成为历史名词。虽然 Java SE、Java EE 和 Java ME 三条产品线里确实只有 Java SE 称得上成功,但 Java EE毕竟无比辉煌过,现在还持有着 JDBC、JMS、Servlet 等使用极为广泛的基础组件,然而 Oracle 仍选择把他们 “扫地出门”,所有权直接赠送给 Eclipse 基金会,唯一的条件是以后不准再使用 “Java” 这个商标,所以取而代之的将是 Jakarta EE

InfoWorld 披露了一封 Oralce 高管邮件表明:资料来源: https://www.infoworld.com/article/2987529/insider-oracle-lost-interest-in-java.html
以后不准再使用 “Java” 这个商标:最大的争议点是 Oralce 要求包名中不能出现 java 字样,导致一堆 javax.* 开头的包一旦修改或者添加新代码,就必须重新命名,这将让用到它们的代码都收到影响。资料来源:https://www.infoq.cn/article/2018/02/from-javaee-to-jakartaee


  2018 年 10 月,JavaOne 2018 在旧金山举行,此前没有人想到过这会是最后一届 JavaOne 大会,这个在 1996 年伴随着 Java 一同诞生、成长的开发者年度盛会,竟是 Oralce 下一个裁撤的对象,此外还有 Java Mission Control 的开发团队,也在2018 年 6 月被 Oralce 解散。

裁撤的对象:Java One 大会从 2019 年起停办,合并入 Oralce CodeOne 大会中。


  2018 年 9 月 25 日,JDK 11 发布,这是一个 LTS 版本的 JDK , 包含 17 个 JEP,其中 ZGC 这样的革命性的垃圾收集器出现,也有把 JDK 10 中的类型推断加入 Lambda 语法这种可见的改进,但都比不过他发布时爆发出来的谣言轰动:“Java 要开始收费啦!”

  随着 JDK 11发布,Oralce同时调整了 JDK 的授权许可证,里面包含了好几个动作。首先,Oralce 从 JDK 11起把以前的商业特性全部开源给 OpenJDK,这样 OpenJDK 11 和 OralceJDK 11 的代码和功能,在本质上就是完全相同的(官方原文是 官方原文是 Essentially Identicial)。然后,Oralce 宣布以后将会同时发行两个 JDK:一个是以 GPLv2+CE 协议下由 ORALCE 发行的传统 OpenJDK(后面将称为Oralce OpenJDK),另一个是在新的 OTN 写一下发行的传统的 OralceJDK,这两个 JDK 共享绝大部分源码,在功能上几乎是一样的,核心差异是前者可以免费在开发、测试或生产环境中使用,但是只有半年时间的更新支持;后者个人依然可以免费使用,但若在生产环境中商用就必须付费,可以有三年时间的更新支持。如果说有由此能得出“Java 要收费” 的结论,那是纯属标题党,最多只能说 Oralce 在迫使商业用户要么不断升级 JDK 的版本,要么就去购买商业特性

商业特性:需要使用 +XX:+UnilockCommercialFeatures 解锁的新特性,包括 JMC、JFR、NMT、AppCDS 和 ZGC 等。
Essentially Identicial:资料来源:https://blogs.oracle.com/java-platform-group/oracle-jdk-releases-for-java-11-and-later
在功能上几乎是一样的:JDK 11 中仅有的微小差别是 OpenJDK少了几个 Module(如JavaFX),且不提供安装包,以压缩包形式发行。但在 JDK 12 又产生了新的分歧,OpenJDK 的 Shenandoah 垃圾收集器被排除在 OracleJDK 之外,详见《深入理解Java虚拟机》 第三版 第四章 周志明著。
商业支持:这里的商业支持不限定于 Oralce 公司,如 Azul ZingJDK、AdoptOpenJDK 等都能提供商业支持。


  2019 年 2月,在 JDK 12 发布前夕,Oralce 果然如之前宣布那样在六个月之后就放弃了对上一个版本OpenJDK 的维护,RedHat 同时从 Oralce 手上接过 OpenJDK 8 和 OpenJDK 11 的管理权力和维护职责。Oralce 不愿意在旧版本上继续耗费资源,而 RedHat 或者说他背后的 IBM 又乐意扩大自己在 Java 社区的影响力,这是一笔双赢的交易。RedHat 或者说他背后的 IBM 又乐意扩大自己在 Java 社区的影响力,这是一笔双赢的交易。RedHat 代替 Oracle 成为 JDK 历史版本的维护者,应该有利于 Java 的持续稳定,但从技术发展角度来看,这并不能为 Oralce 领导 Java 社区的局面带来根本性的改变,毕竟要添加新的或实验性的功能,仅会针对 Java 的最新版本,而不会在旧版本上动手。

维护职责:Red Hat 此前已经是 OpenJDK 6(自 2013 年起)和 OpenJDK 7 (自 2015 年起)的维护者。


  2019 年 3月 20 日,JDK 12 发布,只包含 8 个 JEP ,其中,主要有 Swtich 表达式、Java微测试套件(JMH)等新功能,最引人注目的特性无疑是加入了由 RedHat 领导开发的 Shenandoah 垃圾收集器。Shenandoah 作为首个非 Oralce 开发的垃圾收集器,其目标又与 Oralce 在 JDK 11 中发布的 ZGC 几乎完全一致,两者天生就存在竞争。Oralce 马上用实际行动抵制了这个新收集器,在 JDK 11 发布时才说应尽可能保证 OralceJDK 和 OpenJDK 的兼容一致,转眼就在 OralceJDK 12 里把 Shenandoah 的代码通过条件编译强行剔除掉,使其成为历史上唯一进入了 OpenJDK 发布清单,但在 OralceJDK 中无法使用的功能。

  Oracle 收购 Sun 是 Java 发展历史上一道明显的分界线。在 Sun 掌舵的前十几年里,Java 获得巨大成功,同时也渐渐显露出来语言演进的缓慢与社区决策的老朽;而在 Oracle 主导 Java 后,因其竞争的同时也带来新的活力,Java 发展的速度要显著高于 Sun 时代。Java 的未来是继续向前、再攀高峰,还是由盛转衰、锋芒挫缩,你我拭目以待。

  Java 面临的危机挑战前所未有的艰巨,属于 Java 的未来也从未如此充满想象与可能。


1.2 java应用平台

  • Java SE 标准版:支持桌面级应用(如Windows下的应用程序)的Java平台,提供了完整的Java核心API,这条产品线在JDK6以前被称为J2SE。
  • Java ME 小型版:支持Java程序运行在移动终端(手机、PDA)上的平台,对Java API有所精简,并加入了移动端的针对性支持,这条产品线在JDK6以前被称为J2ME。注意,现在智能手机上非常流行的、主要是用Java语言开发程序的Android并不属于Java ME。
  • Java EE 企业版:支持使用多层框架的企业级应用(如ERP、MIS、CRM应用)的Java平台,除了提供Java SE API外,还对其作了大量有针对性的扩充,并提供了相关的部署支持,这条产品线在JDK 6以前被称为J2EE,在JDK 10以后被Oracle放弃,捐献给Eclipse基金会管理,此后被称为Jakarta EE。
  • 扩充:这些扩展一半一半 javax.* 作为包名,而以 java.*为包名的包都是 Java SE API 的核心包,但由于历史原因,一部分曾经是扩展包的 API 后来进入了核心包中,因此核心包中也包含了不少 javax.* 开头的包名。

1.3 跨平台原理

参考 => Java编译程序和运行过程详解

  • 平台:指的是操作系统(Windows,Linux,Mac)
  • 跨平台:Java程序可以在任意操作系统上运行,一次编写到处运行
  • 原理:java通过javac将源文件编译为.class文件(字节码文件),该字节码文件遵循了JVM(Java Virtual Machine)的规范,使其可以在不同系统的JVM下运行。
  • 过程:java 编译过程:java源程序(.java)->java编译器(javac.exe)->字节码文件(.class)->java解释器(java.exe)->操作系统
    在这里插入图片描述

在这里插入图片描述


1.4 JVM JRE JDK

JVM和字节码文件的详细解析

JDK    JavaSE Development Kit【Java标准版开发工具包】

 1. JDK是提供给Java开发人员使用的,java开发工具包,是sun公司提供的一套用于开发java应用程序的开发包,它提供了编译、运行java程序所需的各种工具和资源,包括java编译器、java运行时环境,以及常用的java类库等。

 2. JDK中包含了java的开发工具,也包括了JRE。所以安装了JDK,就不用在单独安装JRE了。

 3. 其中的开发工具:编译工具(javac.exe) 打包工具(jar.exe)等

 4. JDK = Java程序设计语言 + JRE

JRE   Java Runtime Environment【java运行环境】

 1. 包括Java虚拟机(JVM Java Virtual Machine)和Java程序所需的核心类库等。JRE是支持Java程序运行的标准环境,用于解释执行Java的字节码文件。普通用户而只需要安装 JRE 来运行 Java 程序。而程序开发者必须安装JDK来编译、调试程序。

 2. JRE = Java虚拟机(JVM)+ Java类库API中的JavaSE API子集

JVM    Java Virtual Machine【java虚拟机】

 1. JVM是java虚拟机(JVM Java Virtual Machine),是JRE的一部分。负责解释执行字节码文件,是可运行java字节码文件(.class文件)的虚拟计算机。

为什么JDK中包含一个JRE
 1. 开发完的程序,需要运行一下看看效果。

JDK,JRE,JVM的作用和关系

 1. JDK包含JRE 和开发工具包

 2. JRE 包含 核心类库和JVM

在这里插入图片描述

在这里插入图片描述


什么是JDK源码? 各厂商JDK版本之间是什么关系?

  OpenJDK是 Sun 公司在 2006 年末把 Java 开源而形成的项目,这里的“开源”是通常意义上的源码开放形式,即源码是可被复用的,例如 OracleJDK、Oralce OpenJDK、AdoptOpenJDK、Azul Zulu、SAP SapMachine、Amazon Corretto、IcedTea、UltraViolet 等都是从 OpenJDK源码衍生出的发行版。但如果仅从 “开源” 的字面有意义(可开放阅读的源码)上讲的话,其实 Sun 公司自 JDK 5 时代起就曾经以 JRL (Java Research License)的形式公开过 Java 的源码,主要是开放给研究人员阅读使用,这种 JRL 许可证的开放源码一直持续到 JDK 6 Update 23 才因 OpenJDK 项目日渐成熟而终止了如果拿 OpenJDK 中的源码跟对应版本的 JRL 许可证时性开放的 Sun/OracleJDK 源码互相比较的话,会发现除了文件头的版权注释外,其余代码几乎都是相同的,只有少量设计引用第三方的代码存在差异,如字体栅格化渲染,这部分内容 OralceJDK 采用了商业实现,源码版权不属于 Oracle 自己,所以也无权开源,而 OpenJDK 中使用的是同样开源的 FreeType 代替。

  当然,“代码相同” 必须建立在两者共有的组建基础之上,OpenJDK 中的源码仓库只包含了标准 Java SE 的源代码,而一些额外的模块,典型的如 JavaFX ,虽然后来也被 Oracle 开源并放到 OpenJDK 组织进行管理 (OpenJFX项目),但是他是存放在独立的源码仓库中,因此 OralcJDK 的安装包中会包含 JavaFX 这种独立的模块,而用 OpenJDK 的话则需要单独下载安装。

  此外,在 JDK 11 以前,OralceJDK 中的源码仓库只包含了标准 Java SE 的源代码,而一些额外的模块,典型的如 JavaFX ,虽然后来也是被 Oracle 开源并放到 OpenJDK 组织进行管理(OpenJFX项目),但是它是存放在独立的源码仓库中,因此 OralceJDK 的安装包中会包含 JavaFX 这种独立的模块,而用 OpenJDK 的话则需要单独下载安装。

  此外,在JDK 11 以前,OralceJDK 中还存在一些 OpenJDK 没有的、闭源的功能,即 OracleJDK 的 “商业特性” 。例如 JDK 8 起从 JRockit 移至改造而来的 Java Flight Recorder 和 Java Mission Control 组件、JDK 10 中的应用类型共享功能(AppCDS) 和 JDK 11 中的 ZGC 收集器,这些功能在 JDK 11 时才全部开源导了 OpenJDK 中。到了这个阶段,我们已经可以认为 OpenJDK 与 OralceJDK 代码实质上已经达到完全一致的程度。

实质上:严格来说,这里 “实质上” 可以理解为除去一些版权信息(如 java -version 的输出)、除去针对 Oralce 自身特殊硬件平台的适配、除去 JDK 12 中 OralceJDK 排除了 Shenandoah 这类特意设置的差异之外是一致的。


  根据 Oralce 的项目发布经理 Joe Darcy 在 OSCON 大会上对两者关系的介绍也证实了 OpenJDK 和 OralceJDK 在程序上是非常接近的,两者共用了绝大部分相同的代码(如图 1-7 所示。注意图中的英文提示了两者共同代码的占比要远高于图形上看到的比例),所以我们自己编译的 OpenJDK,基本上可以认为性能、功能和执行逻辑上都和官方的 OracleJDK 是一致的。

对两者关系的介绍:全文地址:https://blogs.oracle.com/darcy/resource/OSCON/oscon2011_OpenJDKState.pdf
=> 2021-02-08 现在已经打不开了

在这里插入图片描述

  下面再来看一下 OpenJDK 内部不同版本之间的关系,在 OpenJDK 接收 Sun 公司移交的 JDK 源码时,Java 正处于 JDK 6 时代的初期,JDK 6 Update 1 才刚刚发布不久,JDK 7 则完全是处于研发状态的半成品。OpenJDK 的第一个版本就是来自于当时 Sun 公司正在开发的 JDK 7,考虑到 OpenJDK 7 的状况在当时完全不足以支持实际的生产部署,因此又在 OpenJDK 7 Build 22 的基础上建立了一条新的 OpenJDK 6 分支,剥离掉所有 JDK 8 新功能的代码,形成一个可以通过 TCK 6 测试的独立分支,先把 OpenJDK 6 发布出去给公众使用。等到OpenJDK 7 达到了可正式对外发布的状态之后,就从 OpenJDK 7 的主分支延伸出用于研发下一代 Java 版本的 OpenJDK 8 以及用于发布更新补丁的 OpenJDK 7 Update 两条子分支,按照开发习惯,新的功能或 Bug 修复通常是在最新分支上进行的,当功能或修复在最新分支上稳定之后会同步到其他老版本的维护分支上。后续的 JDK 8 和 JDK 9 都重复延续着类似的研发流程。通过图 1-8 (依然是从 Joe Darcy 的 OSCON 演示稿截图的图片)可以比较清楚的理解不同版本分支之间的关系。

  到了 JDK 10 及以后的版本,在组织上出现了一些新变化,此时全部开发工作统一归到 JDK 和 JDK Updates 两条分支主线上,主分支不再带版本号,在内部再用子分支来区分具体的 JDK 版本。OpenJDK 不同版本的源码都可以在它们的主页(http://openjdk.java.net/)上找到。
在这里插入图片描述

  获取 OpenJDK 源码有两种方式。一是通过 Mercurial 代码版本管理工具从 Repository 中直接取得源码(JDK 15 Repository 地址:https://hg.openjdk.java.net/jdk15),获取过程如下命令所示:

  hg clone https://hg.openjdk.java.net/jdk15

  这是直接取得 OpenJDK 源码的方式,从版本管理中看变更轨迹也能够更精确地了解 Java 代码发生的变化,但弊端是在中国访问的速度实在太慢,虽然代码总量只有几百MB,无奈文件数量将近十万,而且仓库没有国内的 CDN 节点。全部复制到本地需要数小时时间。另外,考虑到 Mercurial 远不如 Git 常用,甚至普及程度还不如 SVN、ClearCase 以及更古老的 CVS 等版本控制工具,建议使用第二种方式,直接在仓库中打包出源码压缩包,再进行下载。

  直接访问准备下载的 JDK 版本的仓库页面,比如 https://hg.openjdk.java.net/jdk15,然后点击左边菜单中的 “Browse” ,将显示如下图的源码根目录页面。

在这里插入图片描述

  在国内使用这种方式下载比起从 Mercurial 复制一堆零散的文件要快非常多。我下载的 OpenJDK 15 源码包大小为 163MB,解压之后约为 679MB。


  关于JDK编译、修改JDK源码,等操作可以自行看视频学习 => B站UP主 CodeSheep
                      对应博客地址 => CSDN CodeSheep


  如果多次编译,或者目录结构成功产生后又再次修改了配置,必须先使用 “ make clean ” 和 “ make dist-clean ” 命令清理目录,才能确保新的配置生效。编译产生的目录结构及用途如下所示:

  • buildtools/:用于生成、存放编译过程中用到的工具
  • hotspot/:HotSpot 虚拟机编译的中间文件
  • images/:使用 make *-image 产生的镜像存放在这里
  • jdk/:编译后产生的 JDK 就放在这里
  • support/:存放编译时产生的中间文件
  • test-results/:存放编译后的自动化测试结果
  • configure-support/:这三个目录是存放执行 configure、make 和 test 的临时文件
  • make-support/
  • test-support/

      依赖检查通过后便可以输入 “ make images ” 执行整个 OpenJDK 编译了,这里 “ images ” 是 “ Product-images ” 编译目标(Target)的简写别名,这个目标的作用是编译出整个 JDK 镜像,除了 “ product-images ” 以外,其他编译目标还有:
  • hotspot:只编译HotSpot虚拟机
  • hotspot-<variant>:只编译特定模式的HotSpot虚拟机
  • docs-images:产生JDK的文档镜像
  • test-image:产生JDK的测试镜像
  • all-images:相当于连续调用product、docs、test三个编译目标
  • bootcycle-images:编译两次JDK,其中第二次使用第一次的编译结果作为Bootstrap JDK
  • clean:清理make命令产生的临时文件
  • dist-clean:清理make和configure命令产生的临时文件

1.5 OracleJDK下载

图1-1 Java开发资源          


  • 第二步:点击图1-1中“Java开发资源”可以进入到JDK的下载页面,如图1-2所示。在这里插入图片描述

图1-2 JDK的下载页面          


  • 第三步:在JDK的下载页面中首先看到的是目前JDK最新版本JDK8,在本课程中我们统一安装JDK1.7.0_72。此时只需在如1-2所示的页面中向下看,在页面的最后有Java存档”见1-3,点击“java存档”右侧的“DOWNLOAD”按钮即可进入JDK的历史版本页面见图1-4。
    在这里插入图片描述

    图1-3 Java存档          


    在这里插入图片描述

    图1-4 JDK历史版本页面     


  • 第四步:在JDK历史版本页面中,找到JDK7,点击“Java SE7”,进入JDK7的java SE 7的存档下载页面,找到Java SE Development Kit 7u72
    在这里插入图片描述

    图1-5 java SE 7的存档下载找到Java SE Development Kit 7u72     


  • 第五步:java SE 7的存档下载找到Java SE Development Kit 7u72,点击“Accent Lincense Agreement”接受协议。
    在这里插入图片描述

    图1-6 JDK7. 7u72下载页面     


  • 第六步:接受协议之后,既可以根据自己的系统的版本下载对应的JDK图1-7示。下载完成之后可以看到图1-8所示的一个压缩包。
    在这里插入图片描述

    图1-7 下载相应版本的JDK     

  • 到此JDK的下载工作已经完成。(目前推荐使用JDK1.8 21-01-21)


1.5 OracleJDK下载(2022页面ui更新)

在这里插入图片描述

图2-1 Java下载          


  • 第二步:在图2-2所示位置选择Java SE,进入下载页面。

在这里插入图片描述

图1-2 选择Java SE          


  • 第三步:笔记中所有内容的环境均为JDK1.8,目前2022年国内使用最多的JDK版本依然是1.8,选择Java archive 进入历史版本页面。

在这里插入图片描述

图2-3 Java Downloads          


  • 第四步:选择Java SE 8(8u211 and later),可以理解为JDK8这个分类中的后期版本

在这里插入图片描述

图2-4 Java archive     

在这里插入图片描述
P.S 顺便看了一下我自己电脑中的jdk版本是 java1.8.0_281


  • 第五步:根据自己电脑系统选择对应链接,一般系统都为Windows64位,直接选择JDK8最新版 8u331即可,
    • 另外需要JDK和JRE的注意区别
    • Java SE Development Kit 8u331=JDK8 8u331版本
    • Java SE Runtime Environment 8u331 = JRE 8u331版本

    在这里插入图片描述

    图2-5 JDK下载页面     


  • 第六步:选择接受协议,开始下载

在这里插入图片描述


图1-7 下载相应版本的JDK     


1.6 OracleJDK安装

  • 一直下一步即可,安装完JDK还要安装JRE
  • 安装路径不要有中文或者特殊符号如空格等。开发工具最好安装目录统一(可以参考我的目录)
    • D:\develop\Java\JAVA_HOME\jdk1.8
    • D:\develop\Java\JAVA_HOME\jre1.8

  • 问题:Jdk目录下的bin和jre/bin和单独jre/bin的区别
  • 解答:安装jdk完毕后,会询问你是否安装jre,此时安装的jre就是独立java运行环境,安装这个时,会自动配置环境变量 所以在没有配置环境变量前 在cmd命名行下 输入java命令是有效的。
    • 作为非开发者,安装完jre就可以运行java程序了
    • 作为开发者,还需要更多java工具,如javac等,都是在jdk的bin目录中,而jdk中的jre/bin是java内部使用,jdk包含了jre
    • JDK/bin目录下的不同exe文件的用途
      在这里插入图片描述

在这里插入图片描述

在这里插入图片描述


1.7 配置环境变量

JAVA_HOME

变量名:JAVA_HOME
变量值:D:\develop\Java\JAVA_HOME\jdk1.8  (以上述地址为例)
用途:定义一个变量,供其他地方引用

在这里插入图片描述
在这里插入图片描述


PATH

变量名:Path 
变量值:	%JAVA_HOME%\bin;
		%JAVA_HOME%\jre\bin;    <!-- 这个可以不用配置,JDK中已经包含JRE了 --> 
用途:让系统在任何路径下都可以识别java、javac、javap等命令  
	 JDK 安装目录的bin目录下包含 javac.exe 等54 个.exe(jdk1.8);
	 JRE的bin目录不含javac.exe 等,而且仅有21 个.exe(jre1.8);

在这里插入图片描述


CLASSPATH

变量名:CLASSPATH
变量值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;  
用途:告诉jvm要使用或执行的class放在什么路径上,便于JVM加载class文件,.;表示当前路径,tools.jar和dt.jar为类库路径.
		不配置CLASSPATH后面HellowWorld是运行不了.class文件的

在这里插入图片描述


CLASSPATH详解

  • tools.jar
    • 工具类库(编译和运行等),它跟我们程序中用到的基础类库没有关系。我们注意到在Path中变量值bin目录下的各个exe工具的大小都很小,一般都在27KB左右,这是因为它们实际上仅仅相当于是一层代码的包装,这些工具的实现所要用到的类库都在tools.jar中,用压缩软件打开tools.jar,你会发现有很多文件是和bin目录下的exe工具相对性的,查看图一。当然,如果tools.jar的功能只有这些的话,那么我们根本不用把它加入到CLASSPATH变量中,因为bin目录下的工具自己可以完成对这些类库的调用,因此tools.jar应该还有其他的功能。在里面还可以看到有Applet和RMI等相关的文件,因此tools.jar应该还是远程调用等必须的jar包。tools.jar的其他作用可以查看其他资料。

  • dt.jar
    • 运行环境类库,主要是Swing包,这一点通过用压缩软件打开dt.jar也可以看到。如果在开发时候没有用到Swing包,那么可以不用将dt.jar添加到CLASSPATH变量中。
    • CLASSPATH中的类库是由Application ClassLoader或者我们自定义的类加载器来加载的,这里当然不能包括基础类库,如果包括基础类库的话,并用两个不同的自定义类加载器去加载该基础类,那它得到的该基础类就不是唯一的了,这样便不能保证Java类的安全性。

  • 基本类库和扩展类库rt.jar
    • 基本类库是所有的 import java.* 开头的类,在 %JAVA_HOME%\jre\lib 目录下(如其中的 rt.jar、resource.jar ),类加载机制提到,该目录下的类会由 Bootstrap ClassLoader 自动加载,并通过亲委派模型保证了基础类库只会被Bootstrap ClassLoader加载,这也就保证了基础类的唯一性。
    • 扩展类库是所有的 import javax.* 开头的类,在 %JAVA_HOME%\jre\lib\ext 目录下,该目录下的类是由Extension ClassLoader 自动加载,不需要我们指定。
    • rt.jar 默认就在根classloader的加载路径里面,放在claspath也是多此一举

1.8 测试安装是否成功

  • win +R 输入cmd 回车 进入dos窗口
  • 输入java 和 javac能看到如下效果说明安装成功
    -

2 HelloWorld

  开始编写第一个java程序,使用记事本编辑,保存如下内容,文件名为HelloWorld.java,一定保持和类名HelloWorld一致,注意括号,分号用英文符号

public class HelloWorld{
    public static void main(String[] args){
         System.out.println("Hello World");
    }  

在这里插入图片描述

  • 地址栏直接键入cmd,可以进入dos同时进入当前目录

在这里插入图片描述
  java源程序(.java)->java编译器(javac.exe)->字节码文件(.class)
在这里插入图片描述

  • 生成字节码文件(.class)

在这里插入图片描述

  • 通过JVM运行.class字节码文件,这时实际上是运行HelloWorld.class,但是命令中并不用加后缀名。

在这里插入图片描述


3 注释分类


注释分类

1.单行注释格式: //注释文字
2.多行注释格式: /*  注释文字  */
3.Javadoc文档注释格式: /** 注释文字 */
Buttons
按键
Function
功能
Note
备注
/** 后
ctrl + shift + enter
快速生成注释
/**
*
*/

注释代码规范

  1. 【强制】类、类属性、类方法的注释必须使用 Javadoc 规范,使用 /**内容*/ 格式,不得使用 // xxx 方式。
    说明:在 IDE 编辑窗口中,Javadoc 方式会提示相关注释,生成 Javadoc 可以正确输出相应注释;在 IDEA中,工程调用方法时,不进入方法即可悬浮提示方法、参数、返回值的意义,提高阅读效率。
  2. 【强制】所有的抽象方法(包括接口中的方法)必须要用 Javadoc 注释、除了返回值、参数、
    异常说明外,还必须指出该方法做什么事情,实现什么功能。
    说明:对子类的实现要求,或者调用注意事项,请一并说明。
  3. 【强制】所有的类都必须添加创建者和创建日期。
/**
 * @author GroupiesM
 * @date ${DATE}
 */

在这里插入图片描述
4. 【强制】方法内部单行注释,在被注释语句上方另起一行,使用//注释。方法内部多行注释
使用/* */注释,注意与代码对齐。
5. 【强制】所有的枚举类型字段必须要有注释,说明每个数据项的用途。
6. 【推荐】与其“半吊子”英文来注释,不如用中文注释把问题说清楚。专有名词与关键字保
持英文原文即可。
反例:“TCP 连接超时”解释成“传输控制协议连接超时”,理解反而费脑筋。
7. 【推荐】代码修改的同时,注释也要进行相应的修改,尤其是参数、返回值、异常、核心逻
辑等的修改。
说明代码与注释更新不同步,就像路网与导航软件更新不同步一样,如果导航软件严重滞后,就失去了
导航的意义。
8. 【参考】谨慎注释掉代码。在上方详细说明,而不是简单地注释掉。如果无用,则删除。
说明:代码被注释掉有两种可能性:1)后续会恢复此段代码逻辑。2)永久不用。前者如果没有备注信
息,难以知晓注释动机。后者建议直接删掉(代码仓库已然保存了历史代码)。
9. 【参考】对于注释的要求:第一、能够准确反映设计思想和代码逻辑;第二、能够描述业务
含义,使别的程序员能够迅速了解到代码背后的信息。完全没有注释的大段代码对于阅读者
形同天书,注释是给自己看的,即使隔很长时间,也能清晰理解当时的思路;注释也是给继
任者看的,使其能够快速接替自己的工作。
10. 【参考】好的命名、代码结构是自解释的,注释力求精简准确、表达到位。避免出现注释的
一个极端:过多过滥的注释,代码的逻辑一旦修改,修改注释是相当大的负担。
反例:

	// put elephant into fridge 
	put(elephant, fridge); 

  方法名 put,加上两个有意义的变量名 elephant 和 fridge,已经说明了这是在干什么,语义清晰的代
码不需要额外的注释。
11. 【参考】特殊注释标记,请注明标记人与标记时间。注意及时处理这些标记,通过标记扫
描,经常清理此类标记。线上故障有时候就是来源于这些标记处的代码。
  ① 待办事宜(//TODO):(标记人,标记时间,[预计处理时间])
表示需要实现,但目前还未实现的功能。这实际上是一个 Javadoc 的标签,目前的 Javadoc 还没
有实现,但已经被广泛使用。只能应用于类,接口和方法(因为它是一个 Javadoc 标签)。
  ② 错误,不能工作(//FIXME):(标记人,标记时间,[预计处理时间])
在注释中用 FIXME 标记某代码是错误的,而且不能工作,需要及时纠正的情况。


4 关键字

  • 概述:
    • 被Java语言赋予特定含义的单词
  • 特点:
    • 组成关键字的字母全部小写
    • 常用的代码编辑器,针对关键字有特殊的颜色标记,非常直观,所以我们不需要去死记硬背,在今后的学习中重要的关键字也会不断的出来。

在这里插入图片描述

在这里插入图片描述


案例代码一

package com.itheima;
/** eclipse快捷键
 * 内容辅助键:alt+/
 * main方法:main,然后alt+/,回车
 * 输出语句:syso,然后alt+/,回车
 * 
 * 关键字:被Java语言赋予了特定含义的单词。
 * 
 * 特点:
 * 		A:组成关键字的字母全部小写
 * 		B:常见的代码编辑器,对关键字有特殊的颜色标记
 */
public class KeyWordDemo {
	public static void main(String[] args) {
		System.out.println("HelloWorld");
	}

5 常量

  • 概述
    • 在程序执行的过程中,其值不可以发生改变的量
  • 分类
    • 字符串常量 用双引号括起来的内容(“HelloWorld”)
    • 整数常量 所有整数(12,-23)
    • 小数常量 所有小数(12.34)
    • 字符常量 用单引号括起来的内容(‘a’,’A’,’0’)
    • 布尔常量 较为特有,只有true和false
    • 空常量 null(数组部分讲解)


案例代码二

/**
	常量:在程序执行的过程中,其值不可以发生改变的量
	
	常量分类:
		A:字符串常量	"HelloWorld"
		B:整数常量		12,-23
		C:小数常量		12.34
		D:字符常量		'a','0'
		E:布尔常量		true,false
		F:空常量		null(后面讲解)
*/
public class ChangLiang {
	public static void main(String[] args) {
		//字符串常量
		System.out.println("HelloWorld");
		
		//整数常量
		System.out.println(12);
		System.out.println(-23);
		
		//小数常量
		System.out.println(12.34);
		
		//字符常量
		System.out.println('a');
		System.out.println('0');
		
		//布尔常量
		System.out.println(true);
		System.out.println(false);
	}
}		


案例代码三

package com.itheima;
/*
 * 变量的注意事项:
 * 		A:变量未赋值,不能直接使用
 * 		B:变量只在它所属的范围内有效
 * 			变量属于它所在的那对大括号
 * 		C:一行上可以定义多个变量,但是不建议
 */
public class VariableDemo2 {
	public static void main(String[] args) {
		//定义一个变量
		int a = 10;
		System.out.println(a);
		
		int b;
		b = 20;
		System.out.println(b);
		
		{
			//代码块
			int c = 30;
			System.out.println(c);
		}
		//System.out.println(c);
		System.out.println(b);
		
		
		/*
		int aa,bb;
		aa = 10;
		bb = 20;
		System.out.println(aa);
		System.out.println(bb);
		*/
		int aa = 10;
		int bb = 20;
		System.out.println(aa);
		System.out.println(bb);
	}
}

6 变量


6.1 变量概述

  • 概述
    • 在程序执行的过程中,在某个范围内其值可以发生改变的量
    • 从本质上讲,变量其实是内存中的一小块区域
  • 变量定义格式
    • 数据类型 变量名 = 初始化值;
      • byte b = 127;
    • 数据类型 变量名1,变量名2,…
      • byte b1,b2,b3;
    • 注意:格式是固定的,记住格式,以不变应万变
  • 变量图解
    在这里插入图片描述
  • 基本数据类型:
    • byte,short,int,long,float,double,char,boolean
  • 注意:
    • 整数默认是int类型,定义long类型的数据时,要在数据后面加L。
      • Long = 12L;
    • 浮点数默认是double类型,定义float类型的数据时,要在数据后面加F。
      • Float f = 12.34F;

6.2 ++,+=

  • ++
    • 对于数值类型(byte,short,int,long,float,double),变量值+1
  • += n
    • 对于数值类型(byte,short,int,long,float,double),变量值+n
  • ++ 和 += 都隐含了强制转换,byte和short类型进行计算时,会默认转为int类型
    • 例如 byte b = 0; b = b + 1;
    • 在进行+运算的时候,会被提升为int 整形,然后再赋值给byte 的时候就是类型不匹配了。这时就需要强制转换
    • b = (byte)(b+1);
  • ---=+++= 用法类似
    public static void main(String[] args) {
    	//定义byte类型变量b
        byte b = 127;
        //方式1  ++
        b++;
        System.out.println("b1:" + b);
        //方式2 +=  (自动强制转换)
        b += 1;
        System.out.println("b2:" + b);
        //方式三
        b = (byte)(b+1);
        System.out.println("b3:" + b);
    }

7 数据类型


7.1 计算机存储单元

  变量是内存中的小容器,用来存储数据。那么计算机内存是怎么存储数据的呢?无论是内存还是硬盘,计算机存储设备的最小信息单元叫“位(bit)”,我们又称之为“比特位”,通常用小写的字母b表示。而计算机最小的存储单元叫“字节(byte)”,通常用大写字母B表示,字节是由连续的8个位组成。
  除了字节外还有一些常用的存储单位,大家可能比较熟悉,我们一起来看看:

1B(字节) = 8bit(位)
1KB = 1024B
1MB = 1024KB
1GB = 1024MB
1TB = 1024GB

  关于字节和位的原理可以看一下寄存器和触发器相关知识。


7.2 数据类型概述、分类

  • A:为什么有数据类型
    • Java语言是强类型语言,对于每一种数据都定义了明确的具体数据类型,在内存中分配了不同大小的内存空间
  • B:Java中数据类型的分类
    • 基本数据类型
    • 引用数据类型
      • 面向对象部分讲解

在这里插入图片描述


7.3 基本数据类型(4类8种)

在这里插入图片描述

  • 注:数值类型取值范围计算方法为 -2(字节数*8)%2 ~ -2(字节数*8)%2-1
    • 举例: byte为1字节 则 -2(1*8)%2 ~ -2(1*8)%2-1= -128~127
    • 原理:(参看7.5 - 补码)
      • 1个字节有8位,而二进制每一位有(0,1)两种取值,按照排列组合原理,8位共有28=256 种可能取值。
      • 其中由于正负数原因,第一位要用于判断正负号,不用于计算二进制实际值,所以要%2。
      • 其中0归到正数范围中,所以正数取值范围要去掉0这个数,所以要-1。
        • 0 转二进制 => 0000 0000
        • -128转二进制 => 1000 0000
      • 同理 int类型
        • 最小值:Integer.MIN_VALUE= -2147483648 (-2的31次方)
        • 最大值:Integer.MAX_VALUE= 2147483647 (2的31次方-1)

byte

8位、有符号的以二进制补码表示的整数
min :  -128(-2^7)
max:   127(2^7-1)
default: 0
对应包装类:Byte

short

16位、有符号的以二进制补码表示的整数
min :  -32768(-2^15)
max:   32767(2^15 - 1)
default: 0
对应包装类:Short

int  默认整数类型

32位、有符号的以二进制补码表示的整数
min :  -2,147,483,648(-2^31)
max:   2,147,483,647(2^31 - 1)
default: 0
对应包装类:Integer

long

64位、有符号的以二进制补码表示的整数
min :  -9,223,372,036,854,775,808(-2^63)
max:   9,223,372,036,854,775,807(2^63 -1)
default: 0
对应的包装类:Long

float

单精度、32位、符合IEEE 754标准的浮点数
float 在储存大型浮点数组的时候可节省内存空间
浮点数不能用来表示精确的值,如货币
default: 0.0f
对应的包装类:Float

double  默认浮点类型

双精度、64位、符合IEEE 754标准的浮点数
浮点数的默认类型为double类型
double类型同样不能表示精确的值,如货币
default: 0.0d
对应的包装类:Double

char

char类型是一个单一的 16 位 Unicode 字符
最小值是 \u0000(即为0)
最大值是 \uffff(即为65,535)
char 数据类型可以储存任何字符
对应的包装类:Character

boolean

boolean数据类型表示一位的信息
只有两个取值:true 和 false
这种类型只作为一种标志来记录 true/false 情况
对应的包装类:Boolean


案例代码四

package com.itheima;
/*
 * 变量的定义格式:
 * 		数据类型 变量名 = 初始化值;
 * 
 * 基本数据类型:
 * 		byte,short,int,long,float,double,char,boolean
 * 
 * 注意事项:
 * 		A:整数默认是int类型,定义long类型变量的时候,建议加L或l。
 * 		B:浮点数默认是double类型,定义float类型变量的时候,建议加F或f。
 */
public class VariableDemo {
	public static void main(String[] args) {
		//byte类型的变量
		byte b = 10;
		System.out.println(10);
		System.out.println(b);
		
		//short类型的变量
		short s = 100;
		System.out.println(s);
		
		//int类型的变量
		int i = 1000;
		System.out.println(i);
		
		//long类型的变量
		//long l = 10000;
		//System.out.println(l);
		long l = 10000000000L;
		System.out.println(l);
		
		//float类型的变量
		float f = 12.34F;
		System.out.println(f);
		
		//double类型的变量
		double d = 12.34;
		System.out.println(d);
		
		//char类型的变量
		char ch = 'a';
		System.out.println(ch);
		
		//boolean类型的变量
		boolean bb = true;
		System.out.println(bb);
	}
}		//定义boolean类型的变量
		boolean bb = false;
		System.out.println(bb);
	}
}		

7.4 机位数 真值

  • 机位数
    • 一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机用一个数的最高位存放符号, 正数为0, 负数为1.
    • 比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就是 10000011 。
    • 那么,这里的 00000011 和 10000011 就是机器数。
  • 真值
    • 0000 0001的真值 = +000 0001 = +1,1000 0001的真值 = –000 0001 = –1

7.5 原码 反码 补码

  • 概念
    • 对于一个数, 计算机要使用一定的编码方式进行存储。 原码反码补码是机器存储一个具体数字的编码方式。
    • 补码比源码和反码能多表示一位,是因为原码和反码中,1000 0000 表示-0,没有实际意义,补码中将其利用了起来。

原码

  • 作用:用于计算机识别
  • 原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:
    • [+1]原 = 0000 0001
    • [-1]原 = 1000 0001
  • 第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:
    • [1111 1111 , 0111 1111]
    • [-127 , 127]
      在这里插入图片描述

反码

  • 作用:
  • 正数的反码是其本身
  • 负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.
    • [+1] = [00000001]原 = [00000001]反
    • [-1] = [10000001]原 = [11111110]反
  • 可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计算.

补码

  • 正数的补码就是其本身
  • 负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
    • [+1] = [00000001]原 = [00000001]反 = [00000001]补
    • [-1] = [10000001]原 = [11111110]反 = [11111111]补
  • 对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.

7.6 数学证明 【反码、补码、同余、取模】

==> 原码、补码、反码的关系


7.7 溢出问题【数值类型】

  • 以byte类型为例:
    • 在java中 byte 127 再加1等于-128,已知byte的范围为-128~127
    • 字节长度为8位,最左边的是符号位,而127的二进制为:0111 1111,所以执行++a时,0111 111变为1000 0000。最高位存放符号, 正数为0, 负数为1。
    • 在一些数据库中(没有完全测试),数值类型达到最大后再+1会溢出报错,而一些数据库会像java一样循环变为负数。
  • 测试代码 (用了三种方式对b+1)
    public static void main(String[] args) {
    	//不可以直接给byte类型赋值一个溢出值,会报错	
   		//byte b1=130;
       // 127 二进制取值为 0111 1111
        byte b = 127;
        // 0111 1111 + 0000 0001 = 1000 0000 = -128
        b++;
        System.out.println("a:" + b);
        // 1000 0000 + 0000 0001 = 1000 0001 = -127
        b += 1;
        System.out.println("b:" + b);
        // 1000 0001 + 0000 0001 = 1000 0010 = -126
        b = (byte)(b+1);
        System.out.println("c:" + b);
    }

8 标识符

  • 作用

    • 给包,类,方法,变量等起名字
  • 组成规则

    • 由字符,下划线_,美元符$组成
      • 这里的字符采用的是unicode字符集,所以包括英文大小写字母,中文字符,数字字符等。
    • 注意事项
    • 不能以数字开头
    • 不能是Java中的关键字
  • 命名原则:见名知意

      • 最好是域名倒过来,要求所有的字母小写
        • 举例: com.itcast
    • 类或者接口
      • 如果是一个单词首字母大写
        • 举例:User
      • 如果是多个单词每个单词首字母大写(驼峰标识)
        • 举例:UserOrder
    • 方法或者变量
      • 如果是一个单词全部小写
      • 如果是多个单词,从第二个单词首字母大写
    • 常量
      • 如果是一个单词,所有字母大写
      • 如果是多个单词,所有的单词大写,用下划线区分每个单词


案例代码五

package com.itheima;
/**
 * 标识符:就是用来给包,类,变量,方法等起名字的符号。
 * 
 * 组成规则:
 * 		A:unicode字符
 * 			数字字符,英文大小写字母,汉字(不建议使用汉字)
 * 		B:下划线_
 * 		C:美元符$
 * 
 * 注意事项:
 * 		A:不能以数字开头
 * 		B:不能是java中的关键字
 */
public class IdentifierDemo {
	public static void main(String[] args) {
		//数据类型 变量名 = 初始化值;
		int age = 20;
		
	//不能以数字开头
		
		//正确写法
		//int b2 = 30;
		
		//错误写法
		//int 2b = 30;
		
		//不能是java中的关键字
		//int class = 40;
	}
}

9 类型转换

  • 由小到大隐式转换,由大到小强制转换
  • 精度由小到大顺序:byte,short,char -> int -> long -> float -> double
  • 转换类型
    • 9.1 隐式转换 小 - - - - - - - - - - - - - - - - - - - - -> 大 (自动升级)
      • byte,short,char < int < long < float < double
    • 9.2 强制转换 大 - - - - - - - - - - - - - - - - - - - - -> 小 (手动降级)
      • double > float > long > int > byte,short,char
      • 缺点: 损失精度 丢失数据

9.1 隐式转换

  取值范围小的数据类型与取值范围大的数据类型进行运算,会先将小的数据类型提升为大的,再运算


案例代码六

package com.itheima;
/*
 * +:做加法的符号。
 * 
 * 类型转换:
 * 		隐式转换
 * 		强制转换
 * 
 * 隐式转换:
 * 		byte,short,char -- int -- long -- float -- double
 * 
 * 		boolean类型不参与这样的运算。
 */
public class ConversionDemo {
	public static void main(String[] args) {
		//定义两个int类型的变量
		int a = 10;
		int b = 20;
		System.out.println(a + b);
		//我可以把a+b的结果进行输出,说明这个计算的结果是没有问题的
		//那么,我应该也可以把这个结果接收一下。
		int c = a + b;
		System.out.println(c);
		System.out.println("-----------------");
		
		//定义两个变量,一个int类型,一个byte类型
		int aa = 10;
		byte bb = 20;
		System.out.println(aa + bb);
		//下面这种写法报错了
		//byte cc = aa+bb;
		int cc = aa + bb;
		System.out.println(cc);
	}
}

9.2 强制转换


案例代码七

  • 强制转换
package com.itheima;
/*
 * 强制转换:
 * 		目标类型 变量名= (目标类型)(被转换的数据);
 * 
 * 		虽然可以做强制转换,但是不建议。因为强制转换可能会有数据的丢失。
 */
public class ConversionDemo2 {
	public static void main(String[] args) {
		//定义两个变量,一个int类型,一个byte类型
		int a = 10;
		byte b = 20;
		int c = a + b;
		System.out.println(c);
		
		byte d = 30;
		byte e = (byte)(a + b);
		System.out.println(e);
	}
}

9.3 特殊转换 【字符 - 数值】


案例代码八

  • 字符类型与数值类型的转换
package com.itheima;
    /** 隐式转换
     *    char 隐式转换为 int时,只是将该字符的 Unicode 序号作为int值,然后输出
     * 强制转换:
     *    把 int 数做 char 强制转化时,只是转化成其在 Unicode 上的字符,然后输出
     */
public class ConversionDemo3 {
	public static void main(String[] args) {
        //定义四个变量
        char c = '6';
        int i = 54;

        //隐式转换: '6' 的unicode序号为54,得出 i1 = 54
        int i1 = c;
        //强制转换: 54 在Unicode中表示字符'6',得出c1 = '6'
        char c1 = (char) i;
        System.out.println("=====int与char的转换======");        
        System.out.println("i1:" + i1);
        System.out.println("c1:" + c1);

        //byte与char的转换
        byte b = 44;
        //强制转换: '54' 的unicode序号为54,得出 b1 = 54
        byte b1 = (byte) c;
        //强制转换: 44 在Unicode中表示字符',',得出c1 = ','
        c1 = (char) b;
        System.out.println("=====byte与char的转换======");
        System.out.println("b1:" + b1);
        System.out.println("c1:" + c1);

        //short与char的转换
        short s = 34;
        //强制转换+隐式转换: '54' 的unicode序号为54,得出 s1 = (byte)54
        //byte 向 short 为隐式转换 所以 s1 = 54
        short s1 = (byte) c;
        //强制转换: '54' 的unicode序号为54,得出 s1 = 54
        short s2 = (short) c;
        //强制转换: 44 在Unicode中表示字符'"',得出c1 = '"'
        c1 = (char) s;
        System.out.println("=====short与char的转换======");
        System.out.println("s1:" + s1);
        System.out.println("s2:" + s2);
        System.out.println("c1:" + c1);
        
        //string与int的转换
        //st = "54" =  String.valueOf(c) 
        String st = "54";
        int in = 54;
        //stringC = Integer.toString(54) = "54";
        String stingC = Integer.toString(i);
        //inti = Integer.valueof("54") = 54;
        int inti = Integer.valueOf(st);
        System.out.println("=====int与string的转换======");
        System.out.println("inti:" + inti);
        System.out.println("stingc:" + stingC);
	}
}

21/01/26

M

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值