一、JDK 1.8 也被称为 Java 8,有许多重要的新特性:
1、Lambda 表达式:
它允许把函数作为一个方法的参数(函数作为值传递),可以用更紧凑的方式来表示匿名内部类了例如:
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello from a thread!");
}
}).start();
使用 Lambda 表达式后,可以简化为:
new Thread(() -> System.out.println("Hello from a thread!")).start();
优点:Lambda 表达式使代码更加简洁、易读,在处理集合操作如(forEach、map
、filter
等方法)时非常方便。它大大减少了匿名内部类带来的代码冗余,让程序员能够更专注于业务逻辑的实现。
2、Stream流:
提供了一种对集合进行操作的新方式,支持对集合中的元素进行过滤、映射、排序、汇总等操作,采用链式编程,进行多个中间操作,例如filter
、map
、sorted
等操作都是中间操作。
优点:让代码更简洁高效,将复杂的集合操作通过链式调用的方式表达出来,减少了循环和条件判断的嵌套。在处理大量数据集合时,它可以显著提高代码的性能和可读性,使得数据处理操作更加直观。
3、接口的默认方法和静态方法 :
在 JDK 1.8 之前,接口中只能有抽象方法。这意味着如果一个接口需要添加新的方法,所有实现该接口的类都必须实现这个新方法。JDK 1.8 引入了默认方法和静态方法,默认方法允许在接口中提供方法的默认实现,实现类可以选择重写或者直接继承这个默认实现;静态方法则是直接属于接口,可以通过接口名直接调用。
优点:增强了接口的扩展性,在不破坏现有实现类的情况下,可以向接口添加新的方法。
3、新的日期和时间API :
解决了旧版 Date 类的设计缺陷。
4.optional类
Optional
是 Java 8 中引入的一个容器类,用于解决空指针异常(NullPointerException
)的问题。在 Java 程序中,空指针异常是一个非常常见的错误,当尝试访问一个为null
的对象的方法或属性时就会发生。Optional
类的设计目的是提供一种更安全的方式来处理可能为null
的值。
可以把Optional
想象成一个盒子,这个盒子里面要么装着一个实际的值(非null
),要么就是空的(表示没有值)
二、jvm内存结构:
1.程序计数器:
是一块较小的内存空间,生命周期与线程相同。
每个线程都有自己的程序计数器,用于记录当前线程所执行的字节码指令的位置。如果线程正在执行的是一个Java方法,程序计数器会保存指向该方法字节码的下一条指令的地址;如果是本地方法,则程序计数器值为undefined
。
2.java虚拟机栈:
它以帧的形式存储方法调用的状态,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中从入栈到出栈的过程。
一个栈帧主要包括局部变量表、操作数栈、动态连接、方法返回地址等部分
局部变量表:用于存放方法参数和方法内部定义的局部变量。
操作数栈:主要用于在方法执行过程中进行算术运算和方法调用等操作。
3.本地方法栈:
本地方法栈与 Java 虚拟机栈类似,它们的区别在于虚拟机栈为 Java 方法服务,而本地方法栈是为本地方法(Native Method)服务的。本地方法是指用非 Java 语言(如 C 或 C++)编写的方法
4.堆空间:
所有线程共享的一块内存区域,用于存放对象实例和数组。几乎所有的对象实例都在这里分配内存。
是垃圾收集管理的主要区域。因为对象在使用过程中会不断地被创建和销毁,垃圾收集器会负责回收那些不再被使用的对象所占用的内存,以避免内存泄漏。
5.方法区:
用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译后的代码等数据。
6.运行时常量池:
方法区的一部分,用于存放编译期生成的各种字面量和符号引用,这部分内容将在类加载后进入方法区的运行时常量池存放。
具有动态性,运行期间也可能将新的常量放入池中,例如String类的intern()
方法。
三、垃圾回收:
1.如何判断对象是否为垃圾
可达性分析法:
通过一系列被称为 “GC Roots” 的对象作为起始点,从这些节点开始向下搜索,搜索所走过的路径称为引用链。当一个对象到 GC Roots 没有任何引用链相连(即不可达)时,则证明这个对象是可以被回收的。
2.垃圾回收算法:
2.1.标记-清除算法:
标记阶段:首先,垃圾回收器会从 GC Roots 开始,对所有可达的对象进行标记。这个过程会遍历对象图,标记出所有存活的对象。
清除阶段:在标记完成后,回收器会清理掉那些没有被标记的对象,即将它们所占用的内存空间回收。
缺点:这种算法会产生内存碎片。因为清除后的内存空间是不连续的,当需要分配一个较大的对象时,可能没有足够大的连续空间,尽管总的空闲内存可能是足够的。
2.2.复制:
原理:它将内存划分为大小相等的两块,每次只使用其中一块。当进行垃圾回收时,会将存活的对象复制到另一块内存区域中,然后把原来使用的那块内存全部清除。
优点:这种算法不会产生内存碎片,因为每次回收后,内存都是连续的。而且复制操作相对简单,效率较高。
缺点:它的缺点是浪费了一半的内存空间。而且如果对象存活率较高,复制的成本也会比较高。这种算法通常用于新生代的垃圾回收,因为新生代中的对象大部分是朝生暮死的,存活率较低。
2.3.标记-整理算法:
标记阶段:和标记 - 清除算法类似,先标记出所有存活的对象。
整理阶段:在标记完成后,不是直接清除不可达对象,而是将所有存活的对象向一端移动,然后清理掉边界以外的内存空间。
优点:解决了标记 - 清除算法产生内存碎片的问题,同时不需要像复制算法那样浪费一半的内存空间。这种算法适用于老年代的垃圾回收,因为老年代中的对象存活率较高。
3。分代收集设计:
根据对象的存活周期将内存划分为不同代,一般分为新生代和老年代,还有的会细分出永久代(在 Java 8 之后被元数据区替代)或元数据区。