JDK、JRE、JVM及JDK版本特性

本文详细介绍了Java开发环境中的关键组件JDK、JRE和JVM之间的关系与区别。JVM是Java实现跨平台的核心,负责解释执行字节码。JRE包含了JVM和必要的类库,供Java程序运行。JDK则包含了JRE以及开发所需的工具,如Java编译器。此外,文章还讨论了JDK不同版本的特性,如JDK 9的模块化、JDK 8的Lambda表达式和时间日期API,以及JDK 11的本地变量类型推断等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Java程序是运行在JVM(Java虚拟机)上的,在开发程序之前都要配置Java开发环境,其中首先要做的就是JDK的安装和配置,那么JDK、JVM、JRE到底有何联系和区别呢?想必并不是每一个程序员都能说得清楚的,本文接下来将带你了解它们之间的关系。
在这里插入图片描述
一、JVM
JVM(Java Virtual Mechinal),Java虚拟机,是JRE的一部分。它是整个java实现跨平台的最核心的部分,负责解释执行字节码文件,是可运行java字节码文件的虚拟计算机。所有平台的上的JVM向编译器提供相同的接口,而编译器只需要面向虚拟机,生成虚拟机能识别的代码,然后由虚拟机来解释执行。

当使用Java编译器编译Java程序时,生成的是与平台无关的字节码,这些字节码只面向JVM。不同平台的JVM都是不同的,但它们都提供了相同的接口。JVM是Java程序跨平台的关键部分,只要为不同平台实现了相应的虚拟机,编译后的Java字节码就可以在该平台上运行。
Java虚拟机在执行字节码时,把字节码解释成具体平台上的机器指令执行。这就是Java的能够“一次编译,到处运行”的原因。

二、JRE
JRE( Java Runtime Environment) 、Java运行环境,用于解释执行Java的字节码文件。普通用户而只需要安装 JRE(Java Runtime Environment)来运行 Java 程序。而程序开发者必须安装JDK来编译、调试程序。

下图是JRE的安装目录:里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib和起来就称为jre。
在这里插入图片描述
三、JDK
JDK(Java SE Development Kit),Java标准开发包,它提供了编译、运行Java程序所需的各种工具和资源,包括Java编译器、Java运行时环境,以及常用的Java类库等。总的来说JDK是用于java程序的开发,而jre则是只能运行class而没有编译的功能。

下图是JDK的安装目录:
在这里插入图片描述
四、三者联系和区别
JVM不能单独搞定class的执行,解释class的时候JVM需要调用解释所需要的类库lib。在JDK下面的的jre目录里面有两个文件夹bin和lib,在这里可以认为bin里的就是jvm,lib中则是jvm工作所需要的类库,而jvm和 lib和起来就称为jre。JVM+Lib=JRE。总体来说就是,我们利用JDK(调用JAVA API)开发了属于我们自己的JAVA程序后,通过JDK中的编译程序(javac)将我们的文本java文件编译成JAVA字节码,在JRE上运行这些JAVA字节码,JVM解析这些字节码,映射到CPU指令集或OS的系统调用。

JDK和JRE区别:在bin文件夹下会发现,JDK有javac.exe而JRE里面没有,javac指令是用来将java文件编译成class文件的,这是开发者需要的,而用户(只需要运行的人)是不需要的。JDK还有jar.exe, javadoc.exe等等用于开发的可执行指令文件。这也证实了一个是开发环境,一个是运行环境。
JRE和JVM区别:JVM并不代表就可以执行class了,JVM执行.class还需要JRE下的lib类库的支持,尤其是rt.jar。

五、JDK,JRE版本说明
JDK从9开始,Oracle版本用于商业开始收费了,你应该避免使用oracle jdk而应该使用open jdk,去openjdk.java.net上下载,而不是java.com上下载,因为oracle jdk顾名思义,是oracle的版权产品,open jdk免费开源的真jdk。
JDK从9开始,已经模块化了,模块化之后,就不再区分jvm,jre和jdk了,过去jvm是jre的子集,jre对比jvm多了rt.jar标准包的内容。而jre是jdk的子集,jdk对比jre多了javac等工具。那么9的jigsaw之后,所有这些,都被拆成了一个又一个jmod模块,比如java.base.jmod,jdk.javac.jmod等。那用户可以根据自身需要,自由组合出自己的runtime,而这个runtime可能是jdk,也可能是jre+jdk的一部分,也可能是jre的一部分+jdk的一部分,或者干脆就只有jvm的一部分。而且用户可以添加第三方提供的native扩展,比如常见的两个扩展是javafx(gui)和graal(多语言)扩展,graal 19.3多语言扩展将会在2019的11月19日发布,到时候你可以利用该工具扩展出支持javascript,python,ruby,r等语言的运行时(runtime),甚至java提供了jaotc可以将整个runtime精简,做成binary二进制机器码,就跟c等语言一样了。所以这个时候再提供jre就毫无意义了,因为这跟以前你拿一个jar出来,然后所有有jre的地方都能运行不一样了。如果你的jar依赖的jmod不在你自己做的runtime里面,那还是运行不了。所以就不再提供jre了,你需要的话,用jlink自己制作runtime。

JDK从1.5开始,发展到如今14.0(Open JDK GA 2020/03/17),每个版本都有新特性,下面分别列举各处版本的特性。

v1.5 特性(Tiger,于2004-09-30发行)

  1. 泛型(Generic)
    在JDK1.5之前一个集合可以放任何类型的对象,相应地从集合里面拿对象的时候我们也不得不对他们进行强制的类型转换。引入了泛型之后,它允许指定集合里元素的类型,这样在编译阶段就会对对象进行类型检查。
  2. for-each循环(Enhanced for loop)
  3. 自动拆装箱(Autoboxing/unboxing) 自动拆装箱大大方便了基本类型数据和它们包装类的使用
    自动装箱:基本类型自动转为包装类(int >> Integer) 自动拆箱:包装类自动转为基本类型(Integer >> int)
    在JDK1.5之前,我们总是对集合不能存放基本类型而耿耿于怀,现在自动转换机制能解决我们的问题
  4. 类型安全的枚举(Type safe enums)
    JDK1.5加入了一个全新的“类”–枚举类型。为此JDK1.5引入了一个新关键字enum
  5. 可变参数(Var args)
    可变参数使程序员可以声明一个接受可变数目参数的方法。注意,可变参数必须是函数生命中的最后一个参数。
  6. 静态导入(static import)
    要使用静态成员(方法和变量)我们给出提供这个方法的类。使用静态导入可以使被导入类的所有静态变量和静态方法在当前类直接可见,使用这些静态成员无需再给出他们的类名
    import static java.lang.Math.*;
r = sin(PI * 2);//无需再写 r = Math.sin(Math.PI * 2);

release notes:
https://docs.oracle.com/javase/1.5.0/docs/relnotes/features.html
其他参考:
https://segmentfault.com/a/1190000004417288#articleHeader1

v1.6 特性

  1. Desktop类和SystemTray
  2. 使用JAXB2来实现对象与XML之间的映射
  3. 理解StAX
  4. 使用Compiler API
  5. 轻量级Http Server API
  6. 插入式注解处理API(Pluggable Annotation Processing API)
  7. 用Console开发控制台程序
  8. 对脚本语言的支持
  9. Common Annotations

release notes:
http://www.oracle.com/technetwork/java/javase/features-141434.html
其他参考:
https://segmentfault.com/a/1190000004417536
https://www.ibm.com/developerworks/cn/java/j-lo-jse6/
https://www.ibm.com/developerworks/cn/java/j-lo-jse61/index.html
https://www.ibm.com/developerworks/cn/java/j-lo-jse62/index.html
https://www.ibm.com/developerworks/cn/java/j-lo-jse63/index.html
https://www.ibm.com/developerworks/cn/java/j-lo-jse65/index.html
https://www.ibm.com/developerworks/cn/java/j-lo-jse66/index.html
https://www.ibm.com/developerworks/cn/java/j-lo-jse67/index.html

v1.7 特性

  1. switch语句支持字符串变量

    switch 语句比较表达式中的String对象和每个case标签关联的表达式,就好像它是在使用String.equals方法一样;因此,switch语句中 String对象的比较是大小写敏感的。相比于链式的if-then-else语句,Java编译器通常会从使用String对象的switch语句中生成更高效的字节码。

  2. 泛型实例化类型自动推断

ArrayList<String> al1 = new ArrayList<String>();    // Old
ArrayList<String> al2 = new ArrayList<>();           // New
  1. 支持二进制数字字面量
    从JDK1.7开始,可以用二进制来表示整数(byte,short,int和long)。使用二进制字面量的好处是,可以是代码更容易被理解。语法非常简单,只要在二进制数值前面加 0b或者0B。
byte nByte = (byte)0b0001;  
short nShort = (short)0B0010;  
int nInt = 0b0011;  
long nLong = 0b0100L;  
  1. 数字字面量可以出现下划线

    用下划线连接整数提升其可读性,自身无含义,不可用在数字的起始和末尾。

    Java编码语言对给数值型的字面值加下划线有严格的规定。如上所述,你只能在数字之间用下划线。你不能用把一个数字用下划线开头,或者已下划线结尾。这里有一些其它的不能在数值型字面值上用下划线的地方:
    在数字的开始或结尾
    对浮点型数字的小数点附件
    F或L下标的前面
    该数值型字面值是字符串类型的时候

int a2 = 5_2; // 有效
int a9 = 0_52; // 有效的(8进制数)
int a10 = 05_2; // 有效的(8进制数)
int a4 = 5_______2; // 有效的
int a7 = 0x5_2; // 有效的 (16进制数字)
int a1 = _52; // 这是一个下划线开头的标识符,不是个数字
int a3 = 52_; // 无效的,不能以下划线结尾
int a5 = 0_x52; // 无效,不能在0x之间有下划线
int a6 = 0x_52; // 无效的,不能在数字开头有下划线
int a8 = 0x52_; // 无效的,不能以下划线结尾
int a11 = 052_; // 无效的,不能以下划线结尾
float pi1 = 3_.1415F; // 无效的; 不能在小数点之前有下划线
float pi2 = 3._1415F; // 无效的; 不能在小数点之后有下划线
long socialSecurityNumber1=999_99_9999_L;//无效的,不能在L下标之前加下划线
  1. 单个catch中捕获多个异常

    在Java 7中,catch代码块得到了升级,用以在单个catch块中处理多个异常。如果你要捕获多个异常并且它们包含相似的代码,使用这一特性将会减少代码重复度。下面用一个例子来理解。

catch(IOException | SQLException | Exception ex){
    logger.error(ex);
    throw new MyException(ex.getMessage());
}
  1. try-with-resources语句

    try-with-resources语句是一个声明一个或多个资源的try语句。一个资源作为一个对象,必须在程序结束之后关闭。try-with-resources语句确保在语句的最后每个资源都被关闭,任何实现了Java.lang.AutoCloseable和java.io.Closeable的对象都可以使用try-with-resource来实现异常处理和关闭资源。

 try (BufferedReader br = new BufferedReader(new FileReader(path))) {  
        return br.readLine();  
    }  

release notes:
http://www.oracle.com/technetwork/java/javase/jdk7-relnotes-418459.html
http://www.oracle.com/technetwork/java/javase/7u-relnotes-515228.html
其他参考:
https://www.ibm.com/developerworks/cn/java/j-lo-jdk7-1/index.html
https://segmentfault.com/a/1190000004417830

v1.8 特性

  1. 接口的默认方法
    Java 8允许我们给接口添加一个非抽象的方法实现,只需要使用 default关键字即可,这个特征又叫做扩展方法,示例如下:
public interface Formula {  
    double calculate(int a);  
  
    // jdk8能给接口添加一个非抽象的方法实现  
    default double sqrt(int a){  
        return Math.sqrt(a);  
    }  
}  
  1. Lambda表达式
    什么是λ表达式
    λ表达式本质上是一个匿名方法。让我们来看下面这个例子:
    public int add(int x, int y) {
    return x + y;
    }
    转成λ表达式后是这个样子:
    (int x, int y) -> x + y;
    参数类型也可以省略,Java编译器会根据上下文推断出来:
    (x, y) -> x + y; //返回两数之和
    或者
    (x, y) -> { return x + y; } //显式指明返回值
    可见λ表达式有三部分组成:参数列表,箭头(->),以及一个表达式或语句块。
    下面这个例子里的λ表达式没有参数,也没有返回值(相当于一个方法接受0个参数,返回void,其实就是Runnable里run方法的一个实现):
    () -> { System.out.println(“Hello Lambda!”); }
    如果只有一个参数且可以被Java推断出类型,那么参数列表的括号也可以省略:
    c -> { return c.size(); }
    lambda包含3个部分:
    (1)括弧包起来的参数
    (2)一个箭头
    (3)方法体,可以是单个语句,也可以是语句块
    参数可以写类型,也可以不写,jvm很智能的,它能自己推算出来
    方法可以有返回,也可以无返回,如果有多个语句,还要返回值,需要加上return 。
@Test  
public void test2() {  
    // 如果用Lambda表达式,一定要写明泛型  
    List<String> list = Arrays.asList("peter","anna","make");  
  
    // ①.老版本的Java中是这样排列字符串的  
      Collections.sort(list, new Comparator<String>() {  
        @Override  
        public int compare(String a, String b) {  
            return a.compareTo(b);  
        }  
    });  
  
    // ②.Java 8提供了更简洁的语法,lambda表达式:  
    /*  
    Collections.sort(list ,(String a,String b) -> {  
        return a.compareTo(b);  
    });  
  
    // ③.还可以写得更短  
    Collections.sort(list, (String a, String b) -> a.compareTo(b));  
  
    // ④.还可以这么写  
      Collections.sort(list, String::compareTo);  
  
    System.out.println(Collections.singletonList(list));  
}  
  1. 函数式接口
    (1) 是一个接口
    (2) 只有一个待实现的方法 !!!
    因JDK1.8开始,接口可以有default方法,所以,函数式接口也是可以有default方法的,但是,只能有一个未实现的方法。
    与此对应,新引入了一个注解: @FunctionalInterface。这个注解只是起文档的作用,说明这个接口是函数式接口,编译器并不会使用这个注解来决定一个接口是不是函数式接口。不管加不加@FunctionalInterface这个注解,下面的接口都是函数式接口:
    interface Something {
    public String doit(Integer i);
    }
    Lambda表达式是如何在java的类型系统中表示的呢?每一个lambda表达式都对应一个类型,通常是接口类型。而“函数式接口”是指仅仅只包含一个抽象方法的接口,每一个该类型的lambda表达式都会被匹配到这个抽象方法。因为默认方法
    不算抽象方法,所以你也可以给你的函数式接口添加默认方法。我们可以将lambda表达式当作任意只包含一个抽象方法的接口类型,确保你的接口一定达到这个要求,你只需要给你的接口添加
    @FunctionalInterface 注解,编译器如果发现你标注了这个注解的接口有多于一个抽象方法的时候会报错的。

  2. 方法引用
    通常与Lambda表达式联合使用,可以直接引用已有Java类或对象的方法。一般有四种不同的方法引用:构造器引用。语法是Class::new,或者更一般的Class< T >::new,要求构造器方法是没有参数;静态方法引用。语法是Class::static_method,要求接受一个Class类型的参数;特定类的任意对象方法引用。它的语法是Class::method。要求方法是没有参数的;特定对象的方法引用,它的语法是instance::method。要求方法接受一个参数,与3不同的地方在于,3是在列表元素上分别调用方法,而4是在某个对象上调用方法,将列表元素作为参数传入;

  3. 重复注解

    在Java 5中使用注解有一个限制,即相同的注解在同一位置只能声明一次。Java 8引入重复注解,这样相同的注解在同一地方也可以声明多次。重复注解机制本身需要用@Repeatable注解。Java 8在编译器层做了优化,相同注解会以集合的方式保存,因此底层的原理并没有变化。

  4. 扩展注解的支持
    Java 8扩展了注解的上下文,几乎可以为任何东西添加注解,包括局部变量、泛型类、父类与接口的实现,连方法的异常也能添加注解。

  5. Optional

    Java 8引入Optional类来防止空指针异常,Optional类最先是由Google的Guava项目引入的。Optional类实际上是个容器:它可以保存类型T的值,或者保存null。使用Optional类我们就不用显式进行空指针检查了。

  6. Stream

    Stream API是把真正的函数式编程风格引入到Java中。其实简单来说可以把Stream理解为MapReduce,当然Google的MapReduce的灵感也是来自函数式编程。她其实是一连串支持连续、并行聚集操作的元素。从语法上看,也很像linux的管道、或者链式编程,代码写起来简洁明了,非常酷帅!

  7. Date/Time API (JSR 310)
    Java 8新的Date-Time API (JSR 310)受Joda-Time的影响,提供了新的java.time包,可以用来替代 java.util.Date和java.util.Calendar。一般会用到Clock、LocaleDate、LocalTime、LocaleDateTime、ZonedDateTime、Duration这些类,对于时间日期的改进还是非常不错的。

  8. JavaScript引擎Nashorn
    Nashorn允许在JVM上开发运行JavaScript应用,允许Java与JavaScript相互调用。

  9. Base64
    在Java 8中,Base64编码成为了Java类库的标准。Base64类同时还提供了对URL、MIME友好的编码器与解码器。

release notes:
http://www.oracle.com/technetwork/java/javase/8u-relnotes-2225394.html
http://www.oracle.com/technetwork/java/javase/8-whats-new-2157071.html
其他参考:
https://www.ibm.com/developerworks/cn/java/j-lo-jdk8newfeature/index.html
https://segmentfault.com/a/1190000004419611

v1.9 特性
Java平台级模块系统
响应式编程模型Reactive
Linking
JShell:交互式Java REPL
改进的Javadoc
集合工厂方法
改进的Stream API
私有接口方法
HTTP/2
多版本兼容JAR

release notes:
http://www.oracle.com/technetwork/java/javase/9u-relnotes-3704429.html
其他参考:
https://www.ibm.com/developerworks/cn/java/the-new-features-of-Java-9/index.html
https://segmentfault.com/a/1190000013620826

v10 特性
局部变量类型推断应用类数据共享(CDS)额外的 Unicode 语言标签扩展基于时间的版本控制根证书并行全垃圾回收器 G1移除 Native-Header 自动生成工具垃圾回收器接口线程-局部变量管控在备用存储装置上的堆分配试验性的基于 Java 的 JIT 编译器合并 JDK 多个代码仓库到一个单独的储存库中
release notes:

http://www.oracle.com/technetwork/java/javase/10u-relnotes-4108739.html

其他参考:

https://www.ibm.com/developerworks/cn/java/the-new-features-of-Java-10/index.html

https://segmentfault.com/a/1190000014076481

v11 特性
1、本地变量类型推断
2、字符串加强
3、集合加强
4、Stream 加强
5、Optional 加强
6、InputStream 加强
7、HTTP Client API
8、化繁为简,一个命令编译运行源代码
https://my.oschina.net/mdxlcj/blog/3010342

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值