面试 Java 基础八股文十问十答第二十五期
作者:程序员小白条,个人博客
相信看了本文后,对你的面试是有一定帮助的!关注专栏后就能收到持续更新!
⭐点赞⭐收藏⭐不迷路!⭐
1)如何判断对象可以被回收?
Java 中的对象通常由垃圾收集器(Garbage Collector)来管理其生命周期。垃圾收集器会在程序运行时检查对象,并判断它们是否可以被回收。对象可以被回收的条件通常包括以下几种情况:
- 引用计数法:对象被创建时,为其分配一个引用计数器。每当有一个新的引用指向该对象时,计数器加一;当引用被销毁时,计数器减一。当计数器为零时,表示该对象没有任何引用指向它,可以被回收。
- 可达性分析算法:Java 中主要采用的是可达性分析算法。该算法的核心思想是从一组称为“GC Roots”的根对象开始,通过对象之间的引用关系,逐步追踪到所有被根对象直接或间接引用的对象,而无法从根对象访问到的对象则被判定为不可达,可以被回收。
2)JVM的永久代中会发生垃圾回收么?
在 Java 8 及之前的版本中,永久代(Permanent Generation)是 HotSpot 虚拟机中用于存放类信息、方法信息等元数据的内存区域。然而,永久代并不会进行普通的垃圾回收,因为永久代中的对象通常具有固定的生命周期,例如类的定义、方法的定义等,这些对象的生命周期通常伴随着应用程序的整个生命周期。
但是,永久代内存空间的垃圾回收工作仍然是必要的。Java 8 引入了元空间(Metaspace)来替代永久代,元空间位于堆外内存,它的大小并不受到 JVM 内存限制的影响,因此不再会出现永久代内存溢出的情况。对于元空间,会存在垃圾回收的概念,但具体的实现和机制与传统的堆内存回收不同。
3)垃圾收集算法
垃圾收集算法是指在垃圾回收过程中用于识别和回收垃圾对象的算法。常见的垃圾收集算法包括:
- 标记-清除算法(Mark and Sweep):该算法通过两个阶段实现垃圾回收。首先,标记阶段遍历所有可达对象,并标记它们。然后,清除阶段会遍历堆中所有对象,清除未被标记的对象。该算法的缺点是会产生内存碎片。
- 复制算法(Copying):该算法将堆内存划分为两个区域,通常称为“From”区和“To”区。在垃圾回收过程中,将所有存活的对象从一个区域复制到另一个区域,然后清除原区域中的所有对象。这样可以避免内存碎片化,但是需要额外的内存空间来存储对象。
- 标记-整理算法(Mark and Compact):该算法结合了标记-清除和复制算法的优点。首先,标记出所有存活的对象,并将它们向一端移动。然后,清理掉边界外的对象,使得所有存活的对象连续存放,从而解决了内存碎片化的问题。
除了上述常见的垃圾收集算法,还有许多其他算法和变种,如分代垃圾收集算法、增量式垃圾收集算法等,它们都在不同的场景和需求下发挥着作用。4)调优命令有哪些?
5)调优工具
在 Java 应用程序开发和调优过程中,有许多工具可用于监视、分析和优化应用程序的性能。一些常用的 Java 调优工具包括:
- JConsole:Java 监视与管理控制台,是 Java Development Kit(JDK)自带的一个图形化监视工具,用于监视 Java 虚拟机的运行状态、性能指标以及管理 Java 应用程序。
- VisualVM:VisualVM 是一个用于分析 Java 应用程序性能的图形化工具,可以通过插件进行扩展,提供了诸如垃圾回收、线程分析、堆内存分析等功能。
- Java Mission Control:Java Mission Control 是 Java 开发工具包的一部分,提供了性能监视、故障诊断、代码分析等功能,适用于生产环境的性能调优。
- Heap Profiling工具:如MAT(Memory Analyzer Tool)、YourKit 等,用于分析 Java 堆内存的使用情况,帮助发现内存泄漏和优化内存使用。
- 性能测试工具:如JMH(Java Microbenchmark Harness)、Apache JMeter 等,用于进行性能测试和基准测试,评估程序的性能表现。
6)Minor GC与Full GC分别在什么时候发生?
- Minor GC:Minor GC(年轻代GC)发生在年轻代内存区域。年轻代通常分为 Eden 区和两个 Survivor 区。当 Eden 区满时,触发 Minor GC。Minor GC 主要回收年轻代中的无用对象,将存活的对象移动到另一个 Survivor 区或者老年代。
- Full GC:Full GC(老年代GC)发生在整个堆内存区域。Full GC 会同时清理年轻代和老年代中的无用对象,包括 Perm 区(在 Java 8 及之前版本中,现已改为 Metaspace)。Full GC 的触发条件包括老年代空间不足、永久代(或 Metaspace)空间不足、频繁的 Minor GC 等。
7)在一个静态方法内调用一个非静态成员为什么是非法的?
在 Java 中,静态方法和非静态方法有着不同的调用方式和作用域。静态方法属于类级别,可以直接通过类名调用,而非静态方法则属于对象级别,需要通过对象实例调用。
在静态方法内部,无法直接访问非静态成员(例如非静态字段或者非静态方法),因为在静态方法调用时,并没有对象实例与之关联,而非静态成员属于对象的状态和行为,需要通过对象实例才能访问。
如果在静态方法内部尝试调用非静态成员,编译器会报错,因为在静态方法内部无法确定要访问的对象实例。要在静态方法内部调用非静态成员,需要创建对象实例,并通过该实例来调用非静态成员。
8)接口和抽象类的区别是什么?
接口(Interface)和抽象类(Abstract Class)是 Java 中用于实现多态性和封装性的两种机制,它们有以下区别:
- 定义:
- 接口:接口是一种完全抽象的类型,其中所有的方法都是抽象的,并且没有实例变量。接口定义了一组方法签名,实现类必须提供这些方法的具体实现。
- 抽象类:抽象类是一种部分实现的类,其中可以包含抽象方法(没有方法体的方法)和具体方法(有方法体的方法),也可以包含实例变量。抽象类可以有构造方法,但不能被实例化。
- 实现:
- 接口:类通过实现接口来获得接口中定义的行为。一个类可以实现多个接口。
- 抽象类:子类通过继承抽象类来获得部分实现。一个类只能继承一个抽象类。
- 成员变量:
- 接口:接口中不能包含实例变量,只能包含常量(即 static final 变量)。
- 抽象类:抽象类可以包含实例变量。
- 构造方法:
- 接口:接口不能包含构造方法。
- 抽象类:抽象类可以包含构造方法,用于初始化实例变量。
- 多继承:
- 接口:Java 支持多继承,一个类可以实现多个接口。
- 抽象类:Java 不支持多继承,一个类只能继承一个抽象类。
9)一个类没有声明构造方法会有什么后果
如果一个类没有声明任何构造方法,Java 会为该类提供一个默认的无参构造方法。这个默认构造方法会执行一些默认的操作,比如初始化实例变量。
但是,如果类中已经声明了构造方法(无论是无参构造方法还是有参构造方法),Java 将不会提供默认的无参构造方法。这意味着如果你在类中定义了构造方法,而没有提供无参构造方法,当你尝试使用无参构造方法创建对象时,编译器会报错。
如果一个类没有声明任何构造方法,并且在实例化对象时也没有提供任何参数,那么会默认调用无参构造方法(如果存在)。如果类中没有提供任何构造方法,Java 编译器会自动为其生成一个无参构造方法,但是如果你手动提供了构造方法,编译器就不会自动生成了。因此,最好的做法是在需要时显式地提供构造方法,以避免不必要的错误。
10)方法返回值在类的方法里的作用是什么?JVM 哪个内存区域存储?
方法返回值在类的方法里的作用是指定该方法调用后返回的结果。返回值可以是任何合法的 Java 数据类型,包括基本数据类型、对象类型、数组类型等。
返回值的作用包括:
- 提供方法的执行结果给调用者使用。
- 允许方法在执行完后向调用者返回信息或数据。
- 通过返回值可以实现方法之间的数据传递和交互。
在 JVM 中,方法返回值通常存储在方法调用栈帧的操作数栈中。当方法执行完毕并返回结果时,该结果会被压入调用者方法的操作数栈中,以便调用者方法可以使用它。
开源项目地址:https://gitee.com/falle22222n-leaves/vue_-book-manage-system
前后端总计已经 900+ Star,1.5W+ 访问!
⭐点赞⭐收藏⭐不迷路!⭐