前言
世界上并没有完美的程序,因为写程序本来就是一个不断追求完美的过程。同样没有一门语言在一诞生就是完美的,不变的唯有变化。Java诞生至今已经不仅仅是一门语言,背后所涵盖的是一个庞大的技术体系。
网上每隔一段时间就能见到几条“未来X语言将会取代Java”的新闻,此处“X”可以用Kotlin、Golang、Dart、JavaScript、Python等各种编程语言来代入。这大概就是长期占据编程语言榜单第一位的烦恼,天下第一总避免不了挑战者相伴。
在过去二十年Java的发展是孤独求败的,在未来,Java也在迎接着各种挑战,这种挑战来自云原生、容器化、也来自其他设计更完善的语言,相信身怀各种绝技的Java会焕发出更加夺目的光彩,重新攀登另一个高峰。
接下来的内容主要围绕Java、java的版本、java的特性与运行机制进行介绍。
发展历史
Java是在1991年由SUN公司的James Gosling(Java之父)及其团队所研发的一种编程语言,第一个版本耗时18个月,最开始命名为Oak(一种橡树)。Java现在广泛应用于各种大型互联网应用,其设计的最初动机主要是平台独立(即体系结构中立)语言的需要,可以嵌入到各种消费类电子设备(家用电器等),但市场反应不佳。
随着1990年代互联网的发展,SUN公司看到了Oak在互联网上的应用场景,在1995年更名为Java(印度尼西亚爪哇岛的英文名称,因盛产咖啡而闻名),随着互联网的崛起,Java逐渐称为重要的Web应用开发语言。Java的发展可以主要看JavaWeb的发展,Java也见证了互联网的发展过程。
发展至今,Java不仅是一门编程语言,还是一个由一系列计算机软件和规范组成的技术体系,Java 是几乎所有类型的网络应用程序的基础,也是开发和提供嵌入式和移动应用程序、游戏、基于 Web 的内容和企业软件的全球标准。
从笔记本电脑到数据中心,从游戏控制台到科学超级计算机,从手机到互联网,Java 无处不在!
- 97% 的企业桌面运行 Java
- 美国有 89% 的桌面(或计算机)运行 Java
- 全球有 900 万 Java 开发人员
- 开发人员的头号选择
- 排名第一的部署平台
- 有 30 亿部移动电话运行 Java
- 100% 的蓝光盘播放器附带了 Java
- 有 50 亿张 Java 卡在使用
- 1.25 亿台 TV 设备运行 Java
- 前 5 个原始设备制造商均提供了 Java ME
数据来源:https://www.java.com/zh-CN/about/
说到Java自然离不开JDK、JVM、JRE,三者有什么关系。
- JDK(Java Development Kit)Java开发工具包,包含Java语言、Java虚拟机、Java类库,是支持Java程序开发的最小环境。
- JVM(Java Virtual Machine)Java虚拟机,运行于各种操作系统Linux,Windows,Solaris等之上,执行编译好的Java字节码class文件。
- JRE(Java Runtime Environment)Java运行时环境,包含JavaSE中核心类库API和Java虚拟机,简单理解为JVM+核心类库API。
接下来主要围绕JDK的发展,和JVM中常见的GC收集器及算法描述。
1.1 JDK发展史
- 1991年4月,Java之父James Gosling带领绿色计划(Green Project)项目启动,定位于消费电子产品(机顶盒、冰箱、收音机)运行架构的Oak语言诞生,这也是Java的前身,但是市场反响一般。
- 1995年5月23日,随着互联网浪潮在1995年兴起,Oak迅速蜕,Java语言诞生,在SunWorld大会上发布Java1.0,第一次提出Write Once,Run Anywhere的口号。
- 1996年1月23日,JDK1.0发布,纯解释型的Java虚拟机(Sun Classic VM)、Applet、AWT等诞生。
- 1996年4月,十个最主要的操作系统和计算机供应商声明将在其产品中嵌入Java技术,
- 1996年5月底,Sun于美国旧金山举行了首届JavaOne大会,从此JavaOne成为全世界数百万Java开发者每年一度的技术盛会。
- 1996年9月,已有大约8.3万个网页应用了Java技术来制作。
- 1997年2月19日,Sun公司发布了JDK1.1,代表技术:JAR文件格式、JDBC、JavaBeans、RMI等,Java语法也进行了增强,内部类(Inner Class)和反射(Reflection)出现。
- 1998年12月4日,JDK1.2发布,这是一个里程碑式的重要版本,工程代号为Playground(竞技场),这个版本代表性技术非常多,如EJB、JavaPlug-in、Swing、JavaIDL等,还有使用极为频繁的Collections体系工具类等,并且这个版本中Java虚拟机第一次内置了JIT(Just In Time)即时编译器,后续还发布了JDK1.2.1和JDK1.2.2两个小版本升级。在JDK1.2中曾经共存过ClassicVM、HotSpotVM、ExactVM三个虚拟机,其中HotSpot是作为附加程序提供。也是在这个版本中Sun开始拆分对应的Java产品线,Sun在这个版本中把Java技术体系拆分为三个方向:
- 分别是面向桌面应用开发的J2SE(Java 2 Platform,Standard Edition)
- 面向企业级开发的J2EE(Java 2 Platform,Enterprise Edition)
- 面向手机等移动终端开发的J2ME(Java 2 Platform,Micro Edition)
- 1999年4月27日,HotSpot虚拟机诞生,HotSpot最初由Longview Techno-logies公司研发,后来在1997年被Sun公司收购,后来它成为JDK 1.3及之后所有JDK版本的默认Java虚拟机。
- 2000年5月8日,工程代号为Kestrel(美洲红隼)的JDK 1.3发布。JDK 1.3的改进主要体现在Java类库上(如数学运算和新的Timer API等),此外一直作为扩展服务的JNDI服务也开始作为一项平台级服务被提供,还有基于CORBA IIOP协议来实现通信段RMI也出现了。
- 2001年5月17日,JDK1.3的修订版JDK1.3.1发布,工程代号Ladybird(瓢虫)。从JDK1.3开始,Sun公司维持着稳定的开发节奏,大概每个两年发布一个主要版本,期间发布的各个修订版本以昆虫作为工程代号。
- 2002年2月13日,JDK 1.4发布,工程代号为Merlin(灰背隼)。JDK 1.4是标志着Java真正走向成熟的一个版本。Compaq、SAS、Fujitsu、Symbian、IBM等一众大公司参与功能规划,甚至实现自己的独立发行版本。哪怕在二十年后的今天一些主流功能也可以在JDK1.4上运行,这个版本的主要代表技术包含正则表达式、异常链、NIO、日志类、XML解析器和XSLT转换器等等。
- 2002年9月16日,工程代号为Grasshopper(蚱蜢)的JDK1.4.1修订版发布。在这一年前后微软平台的.NET Framework发布,至此Java平台和.NET平台的竞争开始拉开了序幕。但似乎Java的开源策略更胜一筹,终于在2014 年 11 月 12 日,微软正式宣布了.NET Core 的开源。
- 2003年6月26日,工程代号为Mantis(螳螂)的JDK1.4.2修订版发布。
- 2004年9月30日,JDK 5发布,工程代号为Tiger(老虎),Sun公司从这个版本开始放弃JDK 1.x的命名方式,将产品版本号修改成了JDK x,JDK1.2以来Java语言在语法上的改动都不大,该版本在语法易用性上做出了非常大的改进,如自动装箱、泛型、动态注解、枚举、可变长参数、foreach等。此外改进了Java的内存模型(Java Memory Model,JMM)、提供了java.util.concurrent并发包(由Doug Lea大师带Java进入了并发时代)等,JDK 5是官方声明可以支持Windows 9x操作系统的最后一个版本。
- 2006年11月13日,JavaOne大会上,Sun公司宣布计划要把Java开源,随后在一年多的时间内,陆续的将JDK各部分在GPL V2协议下公开源码,随后并建立了OpenJDK组织对这些源码进行独立管理,除了极少部分的产权代码,OpenJDK几乎拥有了SunJDK 7中的全部代码。
- 2006年12月11日,JDK6发布,工程代号为Mustang(野马)。在这个版本中,Sun公司终结了从JDK 1.2开始已经有八年历史的J2EE、J2SE、J2ME的产品线命名方式,启用Java EE 6、Java SE 6、Java ME 6的新命名来代替。在JDK 6中提供了众多改进,如通过Mozilla JavaScript Rhino引擎提供初步动态语言支持,提供编译器注解处理器(Annotation Processor这也是Lombok的原理,通过注解生成模板代码)和微型HTTP服务器API,以及对虚拟机内部锁、同垃圾收集、类加载机制等方面进行了大量优化改动。在JDK 6发布以后由于代码的复杂化,Java开源、开发JavaFx、世界经济危机以及Oracle对Sun的收购提案等原因,Sun公司内忧外患自顾不暇,原本稳定的开发进度也受到了很大的影响,使得JDK 6的生命周期也持续了很久,一共发布了211个更新补丁,最终版本为Java SE 6 Update 211,于2018年10月18日发布。
- 2009年2月19日,工程代号为Dolphin(海豚)的JDK 7发布,这是其第一个里程碑版本,按照规划,共有十个里程碑版本发布,最后一个里程碑版本发布与2010年9月9日,由于各种原因JDK 7没有按照原计划完成。JDK 7开发阶段Sun公司在技术竞争和商业竞争中都深陷泥潭,已经无力推动开发进展,为了尽快完成JDK 7的发布,因此裁掉了大部分原定的功能,对于原定的Lambdax项目、Jigsaw项目、动态语言支持、Gabage-First垃圾收集器、Coin项目只匆匆交付了处于Experimental状态的G1垃圾收集器(直到2012年4月的Update 4中才开始正式商用),其余项目延期到JDK 8中。Oracle从JDK 7开始进行接手,迅速展现出了其极具商业化的处世风格,面对Java中使用最广泛的Java SE免费产品线,定义了一套新的商业版产品Java SE Support ,此外JDK 7计划维护到2022年,已经面向付费用户发布了211个补丁,最新版本为JDK 7 Update 211。
- 2009年4月20日,Oracle宣布正式以74亿美元的价格收SUN公司,一代巨头由此没落,Java商标正式划归Oracle所有,Java语言本身并不属于哪间公司所有,它由JCP组织进行管理。此外Oracle还收购了BEA公司,JavaEE服务器Weblogic就是该公司的产品。
- 2011年7月28日,JDK7发布,做出的改进:提供新的G1收集器、加强对非Java语言的调用支持、可并行的类加载架构等。
- 2014年3月18日,Oracle公司发布JDK 8,从此使用JEP(JDK Enhancement Proposals)来定义和管理纳入新版JDK发布范围的功能特性,JDK 8中实现了JDK7中定义并且未完成的功能,其中也有被延期到JDK 9的Jigsaw模块化功能。
- JEP 126 Lambda函数表达式支持
- JEP 104 内置Nashorn JavaScript引擎
- JEP 150 新的时间日期API
- JEP 122 移除HotSpt永久代
- 2017年9月21日,Oracle公司发表 JDK 9,这其中较为显著的功能就是在JDK 7时期已经规划的Jigsaw模块化功能,为何屡次发布都未能如约而至,前期可能是技术埋坑,后面遭到了以IBM和RedHat联合的等JCP委员抵抗,否决模块化提案,这种做法无疑是革了模块化支持本身就比较好的IBM的命,面对如此抵抗,Oracle丝毫没有退让,宁愿摒弃JSR独立研发,也要推行Jigsaw的发展,如果成真,想必Java也会面临如Python2和Python3的巨大不同,好在最终达成一直协议,Java还是那个完整的Java。JDK 9还提供了JS Shell、JLink、JHSDB等增强。JDK 9之后,Java也以更加敏捷的交付方式如期而至,每年的3月和9月发布一个版本,美6个月发布一个版本,每三年一个LTS版本,目的是避免众多功能交付在一个捆绑JDK的风险,并且提出了孵化器模块(Incubator)和预览特性(Preview)两个概念。也是在这个版本中CMS开始被废弃。
- 2018年3月20日,Oracle公司发布JDK 10,主要对内部进行重构,统一源仓库,统一垃圾收集器接口,统一即时编译器接口(引入Graal几时编译器,这里也埋下一个伏笔),这些改进对于用户并不明显,但对后期的版本打下了良好的基础。
- 2018年3月,同样发生了比较重要的一件事,Oracle正式宣布Java EE成为历史名称,曾经拥有着无数光辉的Java EE产品线(至今仍使用较为广泛的JDBC、JMS、Servlet等组件)被Oracle扫地出门,全部打包赠送给Eclipse基金会,并且不能使用Java商标,并且更名为Jakarta EE。
- 2018年10月,自1996年以来每年一度的已经举办了22年的JavaOne大会,没有人预测到这也是最后一届,同年6月Java Mission Control的开发团队也被Oracle解散。
- 2018年9月25日,JDK 11发布,这也是一个LTS(long-term support)版本,包含17个JEP,同时被引入的还有ZGC这样革命性的垃圾收集器,好比G1的诞生,比G1又更具神秘感。同时Oracle也调整了JDK的授权许可证,把以前的商业许可证授权给OpenJDK,官方宣布同时发布两个JDK,一个是Oracle OpenJDK,一个是OracleJDK,共享大部分源码近乎一致,个人均可免费使用,OpenJDK有半年的更新支持,OracleJDK商用必须付费,且支持三年的更新。因此Java收费纯属谣言,商业用户如果想使用最新的版本支持就必须付费。
- 2019年3月20日,JDK 12发布,RedHat接手了OpenJDK 8和OpenJDk 11的管理和维护权。在JDK 12中包含了8个JEP,主要有Switch表达式和JMH测试套件,最引人注目的就是Shenandoah垃圾收集器,作为首个在JDK 7以后非Oracle开发的垃圾收集器,其目标与ZGC一致,这种竞争关系,立马得到了Oracle的抵制,在OracleJDK中剔除代码,因此Oracle JDK和OpenJDK的隔离性又如历史在JDK9中开始重演,至于后续Java的发展,以及迎接的挑战也是任重而道远,这取决于Oracle的产品线的定制和JCP的决策了。
- 2019年在9月17日,JDK 13发布,这个版本主要通过改善Java SE平台和JDK的性能,稳定性和安全性来提高开发人员的生产力。共包含了5个JEPs和一个Unicode 12.1的支持总共6大主要新特性。
- Support for Unicode 12.1 java.lang.Character支持Unicode Character12.1库,相比12.0库新增554个字符。
- JEP 351: ZGC Uncommit Unused Memory ZGC增强了对未使用堆内存返还操作系统的能力,ZGC对堆内存的控制能力也从4TB提升至16TB,这个版本对ZGC进行了性能的增强。
- JEP 350: Dynamic CDS Archiving 动态归档能力,HostSpotVM对AppCDS的一个增强。
- JEP 354: Switch Expressions (Preview)switch表达式的引入,在后面的JDK 17中又继续对其功能进行了增强。
- JEP 355: Text Blocks (Preview)增加了Java语言对文本块的支持,但这只是作为一个预览性质的功能,通过""" """来放置多行代码。
- JEP 353: Reimplement the Legacy Socket API 重新实现了java.net.Socket and java.net.ServerSocket 类提供的APIs。
- 2020年3月17日,JDK 14发布,这个版本主要是对JDK历史版本的一些增强,也引入了一些新增的功能.
- JEP 359: Records (Preview) 新增了java.lang.Record类,Record是一种轻量级的class,可以看做是数据结构体。Java作为面向对象的语言诞生以来,在大型项目中的优势就体现出来了,但是也有一点不好,过于繁琐,一个POJO JavaBean必须包含get、set等方法,Record主要就是解决这类问题的,类似于Lombok的功能。
- JEP 365: ZGC on Windows
- JEP 364: ZGC on macOS
- JEP 345: NUMA-Aware Memory Allocation for G1 G1的NUMA感知内存分配。这样可以提高使用非均匀内存体系结构(NUMA)的大型计算机的性能。
- JEP 349: JFR Event Streaming 通过启用工具以异步方式订阅Java Flight Recorder事件,这可以对JVM进行更实时的监视。
- JEP 363: Remove the Concurrent Mark and Sweep (CMS) Garbage Collector,CMS作为一款主打老年代的并发垃圾收集器,虽然历任JDK中都没有被设置为默认的垃圾收集器,但是在解决STW问题时也是有着举足轻重的地位的,从JDK 7开始筹备到JDK 9作为默认的G1垃圾收集器,一度被认为CMS的升级版,在次CMS也开始走下历史舞台。
- JEP 366: Deprecate the ParallelScavenge + SerialOld GC Combination 随着每一代JDk中对垃圾收集器的升级以及新的垃圾收集器的引入,ParallelScavenge + SerialOld(Oracle指出很少有人使用)组合的GC也被弃用了,并在不久的将来被移除,完成了自己的历史使命。
- 2020年9月15日,JDK 15发布,按照规划路线,JDK 14也停止更新,JDK 15虽然不是LTS版本,但也引入了一些开创性的功能和对早期版本功能的一些优化。
- JEP 371: Hidden Classes,
- JEP 378: Text Blocks,在JDK 13已经发布的二次预览版本,对于文本块的支持非常友好。
- JEP 377: ZGC A Scalable Low-Latency Garbage Collector (Production),这个支持应该算是比较重要的,相比于JDK 11作为实验性质而引入的ZGC,在这两年中ZGC现在已准备好用于生产,不再标记为实验特征,可以直接使用 -XX:+UseZGC开启ZGC,不再需要XX:+UnlockExperimentalVMOptions额外的配置。需要注意的是在OracleJDK中使用的是ZGC,而在OpenJDK中使用的是Shenandoah GC,使用命令-XX:+UseShenandoahGC开启。
- 2021年3月16日,JDK 16发布,这部分依旧是一些功能的优化升级。
- JEP 389: Foreign Linker API (Incubator)提供静态键入的纯-java访问本机代码的API。
- JEP 393: Foreign-Memory Access API (Third Incubator)提供了操作外部内存能力的API。
- JEP 380: Unix domain sockets java.nio.channels, SocketChannel和ServerSocketChannel新增了对UNIX套接字的支持。
- JEP 338: Vector API (Incubator) 提供孵化器模块的初始迭代,JDK.INCUBATOR.Vector,以表达在运行时可靠地编译的向量计算到支持的CPU架构上的最佳矢量硬件指令,从而实现对等效标量计算的卓越性能。这一点在JDK 17上持续增强。
- JEP 376: ZGC Concurrent Stack Processing,ZGC的并发标记,不同于CMS的标记,ZGC的标记只有三个阶段,且每一个阶段的操作,无论是标记还是清理都是并发操作,大大降低了STW的时间,几乎零延时。这也算是Java在垃圾回收中比较开创性的变革。
- JEP 387: Elastic Metaspace,JDK16对元数据区切分为更小的内存块,并将不再使用的内存快速返还给操作系统,对于频繁加载和卸载类的应用来说这一优化可以产生大量的空闲内存,提升整个JVM的性能。
- JEP 397: Sealed Classes (Second Preview),对JDK内部方法提供强制的封装,在JDK 17依然进行了升级优化。
- JEP 395: Records,从JDK 14作为预览版被提供在,这里已经升级为正式版功能。
- JEP 392: Packaging Tool,新的打包工具,在JDK 14中通过JEP343被提案,在JDK 15中被孵化,在JDK 16中被提升为正式支持使用,通过jpackage命令支持native可执行程序打包。
- 2021年9月14日,JDK17发布,这也是在JDK 11之后的下一个LTS版本,JDK 17也是Java六个月发布节奏下的最新的长期支持(LTS)发布,主打安全、性能、稳定为特性,并且官方计划支持到2029年9月。在这个版本中包含了14个JEPs更新。
- JEP 356: Enhanced Pseudo-Random Number Generator 伪随机数增强器
- JEP 391: macOS AArch64 Port 新平台的支持
- JEP 410: Remove the Experimental AOT and JIT Compiler 移除了实验性质的AOT和JIT编译器
- JEP 411: Deprecate the Security Manager for Removal 弃用安全管理器
- JEP 406: Pattern Matching for switch (Preview) switch表达式,这可能是一个让switch翻身的功能。
- JEP 412: Foreign Function and Memory API (Incubator) 外函数和内存相关的API,在JDK 14和JDK 15中引入的孵化API,使Java程序能够与Java运行时之外的代码和数据互操作,通过有效地调用外部函数(即,JVM之外的代码),并通过安全访问异物,这些API使Java程序能够调用本机库并进入本机数据而不提供Java本机接口(JNI)的脆性和复杂性。
- JEP 414: Vector API (Second Incubator)允许表达在运行时可靠地编译的向量计算以支持的CPU架构上的优化矢量指令,从而实现优于等效标量计算的性能
更多JEP:JEPs 更多JDK版本变更信息:JDK Release Notes
1.2 JVM家族
- JDK 1.0,1996年引入Sun Classic VM,虚拟机鼻祖,世界上第一款商用Java虚拟机。
- JDK 1.2,Solaris平台发布Exact VM,已经初具现代高性能虚拟机雏形,出现热点探测、即时编译等。但是生命周期短暂,这一时期并存Sun Classic VM、Exact VM、HotSpot VM,可通过命令切换。
- JDK 1.3,HotSpot VM成为默认选择,Exact VM依然为备用选择。
- JDK 1.4,Classic VM才完全退出商用虚拟机的历史舞台,与Exact VM一起进入了Sun Labs Research VM之中。HotSpot继承了Sun公司两款虚拟机的优点,自此之后HotSpot VM也一直成为OracleJDK和OpenJDK中默认的虚拟机。得益于Sun和Oracle两大巨头在不同时期的影响力,HotSpot也成为了使用最为广泛的虚拟机。
- Mobile/Embedded VM,这是一款面向JavaME产品线的虚拟机。主打移动端和嵌入式设备市场。只留下了客户端编译器(C1),去掉了服务端编译器(C2);只保留Serial/Serial Old垃圾收集器,去掉了其他收集器等,是一款小家碧玉型产品。
- BEA JRockit,号称最快的虚拟机,天下武功唯快不破,当然也有可能每一家都这么宣传,后来BEA公司也被Oracle收购,由于其设计架构与HotSpot大相径庭,因此只有少部分监控相关的优势被吸纳进去,天下武功,九九归一。
- IBM J9,内部名称曾定义为IT4J(IBM Technology for Java Virtual Machine),太长的名字,因此也看出名字的重要性,至今仍然活跃,与之对应的是可以更好的兼容在IBM的小型机运行平台,模块化也是其显著的优势和特点,因此可以按需启用,消耗较小的资源,提供更大的优势。
- BEA LiquidVM/Azul VM 相比于大名鼎鼎的HotSpot、JRockit、J9等通用型的多平台兼容的JVM,还有一种与特定平台,硬件绑定的专有化虚拟机,BEA的Liquid VM不需要依托于其他操作系统,本身就已经系统化,直接运行在自家Hypervisor系统上。Azul VM是Azul Systems公司在HotSpot基础上进行大量改进,运行于自家专有硬件Vega上的虚拟机,可以管理大量的CPU和内存,使用的是有名的PGC和C4收集器。随着业务线的调整,2010年,Azul转型软件业务,把全部精力投入到Zing(以软件的方式达到接近Vega系统的虚拟机)的研发中,而HotSpot在JDK 11和JDK 12中的ZGC和Shenandoah也才达到同等目标,JVM的发展竞争也渐激烈。
Java虚拟机的发展也进入到一种百花齐放,百家争鸣的局面,除了大规模的服务器级别的虚拟机外,也存在一些小型的虚拟机平台。
- KVM,Android、IOS等智能手机操作系统出现前广泛使用的手机平台。
- JCVM,Java虚拟机的一个子集,如智能卡,SIM卡,信用卡等,通常用作加密模块。
- Squawk VM,由Sun开发曾用于Java Card的嵌入式虚拟机实现。
- JavaInJava,Sun公司开发的一个实验性质的虚拟机,通过元循环证明一门语言可以自举,通过Java来实现Java语言的运行环境,没有编译器,通过解释模式来运行。
- Maxine VM,一个类似于JavaInJava的产品,效率跟高,接近于HotSpot。
- Jikes RVM,由IBM研发的一个实验性质的项目,类似于JavaInJava。
- http://IKVM.NET,基于.NET平台实现的Java虚拟机,通过Mono实现了一定的跨平台能力。
Java经过了这么多年的发展,经历过公司更替,经历过组织割裂,沧海桑田,都使其走了过来,在互联网快速发展的今天,这是一个最好的时代,也是一个最坏的时代,挑战与机遇并存,Oracle公司推出的Graal VM也被官方称为Universal VM,这也是未来最有可能替代HotSpot VM的产品,也将承担起Java迎接更大的挑战。
java的版本各个版本介绍
JDK 各个版本下载:Archived OpenJDK GA Releases
自从 Oracle 调整了 Java 的版本发布节奏之后,Java 版本发布越来越快,虽然都说 Java 版本任他发,我用 Java 8,不过新版本的 Java 功能还是要学习一下的。
2.1 Java 8 新特性
Java 8 中最重要的应该就是 Ladmbda 表达式,Stream 流操作,函数接口,时间处理了。
Java 8 Lambda 表达式
Lambda名字来源于希腊字母表中排序第十一位的字母 λ,大写为 Λ,英语名称为Lambda。在 Java 中Lambda表达式(lambda expression)是一个匿名函数,在编写 Java 中的Lambda的时候,你也会发现Lambda不仅没有函数名称,有时候甚至连入参和返回都可以省略,这也让代码变得更加紧凑。
Java 8 Lambda 表达式介绍www.wdbyte.com/2019/11/jdk/jdk8-lambda/正在上传…重新上传取消
Java 8 Stream
Stream 不同于其他集合框架,它也不是某种数据结构,也不会保存数据,但是它负责相关计算,使用起来更像一个高级的迭代器。在之前的迭代器中,我们只能先遍历然后在执行业务操作,而现在只需要指定执行什么操作, Stream 就会隐式的遍历然后做出想要的操作。另外 Stream 和迭代器一样的只能单向处理,如同奔腾长江之水一去而不复返。
由于 Stream 流提供了惰性计算和并行处理的能力,在使用并行计算方式时数据会被自动分解成多段然后并行处理,最后将结果汇总。所以 Stream 操作可以让程序运行变得更加高效。
Java 8 Stream 流式操作www.wdbyte.com/2019/11/jdk/jdk8-stream/正在上传…重新上传取消
Java 8 Optional 介绍
如果你没有处理过空指针,那么你不是一位真正的 Java 程序员。
为了解决上面的问题,在 Java SE8 中引入了一个新类java.util.Optional,这个类可以缓解上面的问题。
Java 8 Optional 介绍www.wdbyte.com/2019/11/jdk/jdk8-optional/正在上传…重新上传取消
Java 8 LocalDate、LocalDateTime 时间处理介绍
Jdk8 带来了全新的时间处理工具类,用于代替之前存在缺陷的时间处理。新的时间处理相比之前更加简单好用。
Java 8 LocalDate、LocalDateTime 时间处理介绍www.wdbyte.com/2019/10/jdk/jdk8-time/正在上传…重新上传取消
Java 8 函数接口
只有一个抽象函数的接口,函数接口使用注解@FunctionalInterface进行声明(注解声明不是必须的,如果没有注解,也是只有一个抽象函数,依旧会被认为是函数接口)。多一个或者少一个抽象函数都不能定义为函数接口,如果使用了函数接口注解又不止一个抽象函数,那么编译器会拒绝编译。函数接口在使用时候可以隐式的转换成 Lambda 表达式。
Java 8 UnaryOperator 函数接口www.wdbyte.com/java8/java8-unaryoperaotr正在上传…重新上传取消
Java 8 BiPredicate 函数接口www.wdbyte.com/java8/java8-bipredicate正在上传…重新上传取消
Java 8 BiFunction 函数接口www.wdbyte.com/java8/java8-bifunction/正在上传…重新上传取消
Java 8 Supplier 函数接口www.wdbyte.com/java8/java8-supplier/正在上传…重新上传取消
Java 8 Predicate 函数接口www.wdbyte.com/java8/java8-predicate/正在上传…重新上传取消
Java 8 Function 函数接口www.wdbyte.com/java8/java8-function/正在上传…重新上传取消
Java 8 forEach 遍历
从 Java 8 开始,可以使用forEach来遍历List、Map、Set和Stream。forEach使用了函数接口进行实现,如果想对forEach的原理有所了解,可以浏览函数接口相关文章。
Java 8 forEach 遍历www.wdbyte.com/java8/java8-foreach/正在上传…重新上传取消
2.2 Java 9 新功能介绍
Java 9中最大的亮点是Java 平台模块化的引入,以及模块化 JDK。但是Java 9还有很多其他新功能,这篇文字会将重点介绍开发人员特别感兴趣的几种功能。
Java 9 新特性介绍www.wdbyte.com/2020/02/jdk/jdk9-feature/正在上传…重新上传取消
2.3 Java 10 新功能介绍
Java 10 为我们带来了基于时间的版本号,局部类型推断,基于 Java 的 JIT 编译器功能,增加了类数据共享以及 G1并行 GC 等特性。
Java 10 新特性介绍www.wdbyte.com/2020/02/jdk/jdk10-feature/正在上传…重新上传取消
2.4 Java 11 新功能介绍
有些人很关心 Java 11 是否收费,Oracle 表示除非你在生产中使用,否则可以不用收费。即使收费,免费的 Open JDK 不也很香吗。
Java 11 新特性介绍www.wdbyte.com/2020/03/jdk/jdk11-feature/正在上传…重新上传取消
2.5 Java 17 新功能介绍
JEP 306 | 恢复始终严格的浮点语义 |
JEP 356 | 增强的伪随机数生成器 |
JEP 382 | 使用新的 macOS 渲染库 |
JEP 391 | 支持 macOS/AArch64 架构 |
JEP 398 | 删除已启用的 Applet API |
JEP 403 | 更强的封装 JDK 内部封装 |
JEP 406 | Switch 模式匹配(预览) |
JEP 407 | 移除 RMI Activation |
JEP 409 | 密封类(Sealed Classes) |
JEP 410 | JEP 401:移除实验性的 AOT 和 JIT 编译器 |
JEP 411 | 弃用 Security Manager |
JEP 412 | 外部函数和内存 API(孵化器) |
JEP 414 | Vector API(第二孵化器) |
JEP 415 | 指定上下文的反序列化过滤器 |
Java 17 新功能介绍(LTS)www.wdbyte.com/java/java-17/正在上传…重新上传取消
java的语言特性
3.1 封装
封装的定义
封装(Encapsulation)是面向对象方法的重要原则,就是把对象的属性和操作(或服务)结合为一个独立的整体,并尽可能隐藏对象的内部实现细节。
封装的好处
- 良好的封装能够减少耦合。
- 类内部的结构可以自由修改。
- 可以对成员进行更精确的控制。
- 隐藏信息,实现细节。
3.2 继承
继承的定义
继承是面向对象最显著的一个特性。继承是从已有的类中派生出新的类,新的类能吸收已有类的数据属性和行为,并能扩展新的能力。关键字(extends)让类与类之间产生继承关系。
继承的特点
- 继承关系是传递的。若类C继承类B,类B继承类A(多层继承),则类C既有从类B那里继承下来的属性与方法,也有从类A那里继承下来的属性与方法,还可以有自己新定义的属性和方法。继承来的属性和方法尽管是隐式的,但仍是类C的属性和方法。继承是在一些比较一般的类的基础上构造、建立和扩充新类的最有效的手段。
- 提供多重继承机制。从理论上说,一个类可以是多个一般类的特殊类,它可以从多个一般类中继承属性与方法,这便是多重继承。Java出于安全性和可靠性的考虑,仅支持单重继承,而通过使用接口机制来实现多重继承。
- 提高代码的复用性。若类B继承类A,那么建立类B时只需要再描述与基类(类A)不同的少量特征(数据成员和成员方法)即可。这种做法能减小代码和数据的冗余度,大大增加程序的重用性。
- Java只支持单继承,不支持多继承。也就是一个类只能有一个父类,不可以有多个父类。
super和this的区别
- super(参数)是调用基类中的某一个构造函数(构造函数的第一条语句);this(参数)是调用本类中另一种形成的构造函数(构造函数中的第一条语句)
- super引用当前对象的直接父类中的成员(用来访问直接父类中被隐藏的父类中成员数据或者函数,基类与派生类中有相同成员定义时如:super.变量名 super.成员函数名(实参));this代表当前对象名(在程序中产生二义性之处,应使用this来指明当前对象;如果函数的形参与类中的成员数据同名,这时需要用this来指明成员变量名)
- 调用super()必须写在子类构造方法的第一行,否则编译不通过。每个子类构造方法的第一条语句,都是隐含地调用super(),如果父类没有这种形式的构造函数,那么在编译的时候就会报错。
- super()和this()类似,区别是,super()从子类中调用父类的构造方法,this()在同一类内调用其它方法。
- super()和this()均需放在构造方法内第一行。
- 尽管可以用this调用一个构造器,但却不能调用两个。
- this和super不能同时出现在一个构造函数里面,因为this必然会调用其它的构造函数,其它的构造函数必然也会有super语句的存在,所以在同一个构造函数里面有相同的语句,就失去了语句的意义,编译器也不会通过。
- this()和super()都指的是对象,所以,均不可以在static环境中使用。包括:static变量,static方法,static语句块。
- 从本质上讲,this是一个指向本对象的指针, 然而super是一个Java关键字。
内部类
将一个类定义在另一个类里面,里面的那个类就称为内部类。内部类的出现,再次打破了Java单继承的局限性。
访问特点:
- 内部类可以直接访问外部类的成员,包括私有成员。
- 外部类要访问内部类的成员,必须要建立内部类的对象。
内部类分类及共性:
1. 共性
- 内部类仍然是一个独立的类,在编译之后会内部类会被编译成独立的.class文件,但是前面冠以外部类的类名和$符号。
- 内部类不能用普通的方式访问。内部类是外部类的一个成员,因此内部类可以自由地访问外部类的成员变量,无论是否是private的。
2. 成员内部类
在外部类中有成员变量和成员方法,成员内部类就是把整个一个类作为了外部类的成员;
成员内部类是定义在类中方法外的类;
创建对象的格式为:外部类名.内部类名 对象名 = 外部类对象.内部类对象;
成员内部类之所以可以直接访问外部类的成员,那是因为内部类中都持有一个外部类对象的引用:外部类名.this;
成员内部类可以用的修饰符有final,abstract,public,private,protected,static.
3. 静态内部类
静态内部类就是成员内部类加上静态修饰符static,定义在类中方法外。
在外部类中访问静态内部类有两种场景:
- 在外部类中访问静态内部类中非静态成员:外部类名.内部类名 对象名 = 外部类名.内部对象,需要通过创建对象访问;
- 在外部类中访问静态内部类中的静态成员:同样可以使用上面的格式进行访问,也可以直接使用外部类名.内部类名.成员。
4. 局部内部类
局部内部类是定义在方法中的类。
- 方法内部类只能在定义该内部类的方法内实例化,不可以在此方法外对其实例化。
- 方法内部类对象不能使用该内部类所在方法的非final局部变量。
可以用于方法内部类的修饰符有final,abstract;
静态方法中的方法内部类只能访问外部的静态成员。
5. 匿名内部类
匿名内部类是内部类的简化写法,是建立一个带内容的外部类或者接口的子类匿名对象。
前提:
内部类可以继承或实现一个外部类或者接口。
格式:
- new 外部类名或者接口名(){重写方法};
- 通常在方法的形式参数是接口或者抽象类,并且该接口中的方法不超过三个时,可以将匿名内部类作为参数传递。
3.3 多态
多态的定义
对象在不同时刻表现出来的不同状态。
多态的注意事项
- 一定不能够将父类的对象转换成子类类型。
- 多态自始至终都是子类对象在变化。
- 父类的引用指向子类对象,该引用可以被提升,也可以被强制转换。
重写与重载
方法的重写Overriding和重载Overloading是Java多态性的不同表现。重写Overriding是父类与子类之间多态性的一种表现,重载Overloading是一个类中多态性的一种表现。
重写遵循以下规则:
- 参数列表必须完全和被重写方法的参数列表一致。
- 返回类型必须完全和被重写方法的返回类型一致。
- 访问修饰符的限制一定要大于被重写方法的访问修饰符(public>protected>default>private)。
- 重写的方法一定不能抛出新的检查异常或者比被重写方法声明更加宽泛的检测型异常。
重载的注意事项:
- 在使用重载时只能通过相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,不同的参数个数,不同的参数顺序(参数类型必须不一样)。
- 各个重载方法的参数列表必须不同。
- 各个重载方法的返回值类型可以相同也可以不同,但是仅仅返回值类型不同的不是重载。
- 不能通过仅仅通过访问权限、返回类型、抛出的异常的不同而进行重载
不同修饰符修饰的内容
类 成员变量 成员方法 构造方法
private Y Y Y
default Y Y Y Y
protected Y Y Y
public Y Y Y Y
abstract Y Y
static Y Y Y
final Y Y Y
注意,常见规则如下:
- 以后,所有的类都用public修饰。并且,在一个java文件中,只写一个类。
- 以后,所有的成员变量用private修饰。
- 以后,所有的成员方法用public修饰。
- 如果是抽象类或者接口:public abstract + …
- 以后,所有的构造方法用public修饰。
- 如果类是工具类或者单例类:构造用private修饰
java的运行机制
简单来说Java程序的运行机制分为编写、编译和运行三个步骤。
4.1 编写
编写是指在Java开发环境中进行程序代码的编辑,最终生成后缀名为“.java”的Java源文件。
4.2 编译
编译是指使用Java编译器对源文件进行错误排查的过程,编译后将生成后缀名为.class的字节码文件,该文件可以被Java虚拟机(JVM)的解释器正常读取。
4.3 运行
运行是指使用Java解释器将字节码文件翻译成机器代码,执行并显示结果。字节码文件是一种和任何具体机器环境及操作系统环境无关的中间代码,它是一种二进制文件,是Java源文件由Java编译器编译后生成的目标代码文件。编程人员和计算机都无法直接读懂字节码文件,它必须由专用的Java解释器来解释执行,因此Java是一种在编译基础上进行解释运行的语言。
在运行Java程序时,首先会启动JVM,然后由它来负责解释执行Java的字节码,并且Java字节码只能运行于JVM之上。这样利用JVM就可以把Java字节码程序和具体的硬件平台以及操作系统环境分隔开来,只要在不同的计算机上安装了针对于特定具体平台的JVM,Java程序就可以运行,而不用考虑当前具体的硬件平台及操作系统环境,也不用考虑字节码文件是在何种平台上生成的。JVM把这种不同软硬件平台的具体差别隐藏起来,从而实现了真正的二进制代码级的跨平台移植。JVM是Java平台无关的基础,Java的跨平台特性正是通过在JVM中运行Java程序实现的。
图中,从编写出来的Java源文件,到编译为字节码文件,再到通过JVM执行程序,然后将程序的运行结果展示给用户,这是一个完整的Java运行流程。