Java应届生面试题

30 Mar 2025 | 15 分钟阅读

在本教程中,我们将讨论针对初级候选人的面试问题。这些面试问题有助于通过 Java 面试的技术轮次。

1) 讨论 JVM、JRE、JDK

JVM (Java 虚拟机): JVM 充当运行 Java 应用程序的运行时引擎。是 JVM 调用 main 方法。JVM 是 JRE(Java 运行时环境)的一部分。

JRE (Java 运行时环境): JRE 是字节码可以执行的运行时环境。它实现了 JVM(Java 虚拟机),并提供了 JVM 在运行时使用的所有类库和其他支持文件。因此,JRE 是满足运行/执行 Java 程序所需内容的软件包。

JDK (Java Development Kit): 它是编译、文档和打包 Java 程序所需的工具。JDK 完全包含 JRE,其中包含 Java 程序员的工具。Java Development Kit 是免费提供的。除了 JRE,它还包括一个解释器/加载器、一个编译器(javac)、一个存档器(jar)、一个文档生成器(Javadoc)以及 Java 开发所需的其他工具。总之,它包含 JRE + 开发工具。


2) 讨论 public static void main(String args[])

public: Public 是一个访问修饰符。由于 main 方法是 public 的,任何类都可以访问它。

static: 这是一个 Java 关键字,表示一个类级别的对象,可以在不先创建类的实例的情况下进行访问。我们使用 static 是因为我们希望 main() 方法也能在没有实例的情况下运行。

void: 这是 main 方法的返回类型。Void 表示 main() 方法不返回任何值。

main: 这是方法的名称,在本例中是 main()。它是 JVM 执行的第一个方法。


3) 定义类和对象。请用 Java 示例进行解释。

类: 用户定义的类充当创建对象的模板或原型。它代表了特定类型的所有对象共享的属性或操作的集合。通常,这些元素可以在类声明的以下顺序中找到。

对象: 它是面向对象编程的基本单元,代表现实世界的实体。典型的 Java 程序会创建许多对象,这些对象通过调用方法进行交互。对象由以下几部分组成:

状态: 由对象的属性表示。此外,它反映了对象的特征。

行为: 由对象的方法表示。它通过对象的方法表示。它还显示了一个对象如何与其他对象交互。

标识: 它为事物提供了一个特殊的名称,并使得一个对象可以与另一个对象进行通信。

例如,学生是一个类的例子。一个具有唯一标识的特定学生是一个对象的例子。

Student 的对象之一称为 'studObj'


4) 什么是方法?提供几种方法的签名。

Java 方法是一组用于执行任务的语句。方法放置在一个类中。

方法签名:方法的名称、返回类型和参数数量构成了方法签名。

方法在其签名中可以包含以下元素

访问说明符 - public、private、protected 等。(非必需)

访问修饰符 - static、synchronized 等。(非必需)

返回类型 - void、int、String 等。(必需)

方法名称 - show()(必需)

带或不带参数 - (int number, String name);(括号是必需的)


5) 为什么 Java 不是纯粹的面向对象的?

这是因为该语言支持原始数据类型,如 boolean、byte、char、int、float、double、long 和 short。因此,Java 不被认为是完全面向对象的。


6) 解释实例变量和类变量之间的区别。

每个对象或实例都独有的变量称为实例变量。这意味着每个实例都只存在一次。每个类只有一个副本的变量称为类变量。类变量在对象中不会有副本。


7) Java 中的构造函数是什么?

构造函数是用于在 Java 中初始化对象的代码段。它必须与类同名。此外,它在创建对象时自动调用,并且没有返回类型。

如果类没有显式定义任何构造函数,Java 编译器会自动生成一个无参数构造函数,也称为默认构造函数。

当一个类没有其他父类时,默认构造函数会调用类父类的无参数构造函数(因为它只有一条语句 super());或者调用 Object 类构造函数(因为 Object 类是所有类的直接或间接父类)。

构造函数有两种类型:

  1. 参数化构造函数
  2. 默认构造函数

8) 在 Java 中创建对象的不同方法是什么?

以下是在 Java 中创建对象的不同方法。

  • 使用 new 关键字
  • 使用 new 实例
  • 使用 clone() 方法
  • 使用反序列化
  • 使用 Constructor 类的 newInstance() 方法

9) 静态方法和静态变量的目的是什么?

当我们希望将一个方法或变量在类的所有对象之间共享,而不是为每个对象创建单独的副本时,我们使用 static 关键字来使该方法或变量成为共享的。

静态变量: 静态变量的另一个名称是类变量。

这些变量的声明方式与实例变量类似,不同之处在于静态变量在类中声明,不在任何方法、构造函数或块中使用 static 关键字。

无论我们创建多少个对象,每个类最多只能有一个静态变量的实例。

静态变量在程序执行开始时生成,并在程序执行结束时立即删除。

我们不需要创建该类的对象就可以访问静态变量。

静态方法: 您无需创建任何对象即可调用静态方法。只需键入类名即可访问该方法。静态方法只能访问静态变量,而不能访问局部或全局非静态变量。

文件名: ClassMain.java

输出

Static Method can be accessed directly using the class name!

10) 为什么静态方法无法访问非静态变量或方法?

这是因为静态方法可以在不实例化类的情况下使用。如果类未实例化,则变量未初始化,无法从静态方法访问。因此,静态方法无法访问非静态变量或方法。


11) 什么是静态类?

如果类的所有变量和方法都是静态的,并且构造函数是私有的,那么该类就称为静态类。如果构造函数是私有的,则无法实例化该类。因此,只能通过类名来访问。


12) 详细讨论 Java 中的变量类型。

Java 中的变量类型如下:

  • 局部变量
  • 实例变量
  • 静态变量

局部变量: 当一个变量定义在方法、块或构造函数内时,该变量称为局部变量。当控制进入方法或块时,这些变量就会出现。局部变量在退出块后或控制从方法返回时被销毁。这些局部变量的作用域仅限于声明变量的块内。也就是说,我们只能在该块内访问这些变量。我们永远不能为局部变量使用访问说明符。

文件名: LocVariable.java

输出

The value of the local variable is: 1

解释: 在上面的程序中,locVar 变量是 getLocalVariableValue() 方法的局部变量。如果我们使用变量 locVar 在 getLocalVariableValue() 方法之外,编译器会报错。以下程序显示了相同的内容。

文件名: LocVariable1.java

输出

/LocVariable1.java:14: error: cannot find symbol
     System.out.println("Accessing the local variable outside of the method" + locVar);
                                                                               ^
  symbol:   variable locVar
  location: class LocVariable1
1 error

实例变量: 非静态变量是实例变量。这些变量在类的任何构造函数、方法或块之外声明。由于实例变量是在类内声明的,因此当类被实例化时,这些变量就会出现。当类的对象被销毁时,这些变量也会被销毁。与局部变量不同,我们可以对实例变量应用访问说明符。当不应用访问说明符时,将使用默认访问说明符。

文件名: VariableInstance.java

输出

Displaying the first object: 
instanceVarId = 1
instanceVarName = InstVariable1
Displaying the second object: 
instanceVarId = 2
instanceVarName = InstVariable2

在上述程序中,实例变量是 instVarId 和 instVarName。在程序中创建了两个对象,每个对象都有自己的实例变量副本。在上述程序中,每个对象都有自己的实例变量副本,输出也反映了这一点。

静态变量: 类变量也称为静态变量。

  • 静态变量的声明方式与实例变量类似。区别在于实例变量不带 static 关键字。相反,静态变量使用 static 关键字在类中声明,在任何块或构造函数之外。
  • 与实例变量不同,无论我们创建该类的多少个对象,静态变量只有一个副本。
  • 静态变量在程序执行开始时创建,并在执行结束时自动销毁。

要访问静态变量,不需要创建该类的对象。可以使用类名访问静态变量。Static 关键字在单例设计模式的实现中起着关键作用。其说明在以下程序中显示。

文件名: VarStatic.java

输出

Static count for the object stVarOb1: 2
NonStatic count for the object stVarOb1: 1
Static count for the object stVarOb2: 2
NonStatic count for the object stVarOb2: 1

在上述程序中,stVarOb1stVarOb2 共享静态变量 cnt 的同一个实例。因此,如果其中一个对象增加了该值,则增加的值会反映在 stVarObj1stVarObj2 两个对象上。这是因为只有静态变量的副本可用。


13) 区分 Java 中的 HashMap 和 HashTable。

观察 HashTable 和 HashMap 之间的以下区别。

HashTable 是同步的,因此它是线程安全的,并且可以轻松地与多个线程共享。另一方面,HashMap 是不同步的,并且不是线程安全的,因此不能(未经任何同步代码)在多个线程之间共享。

HashTable 不允许任何 null 值或键,而 HashMap 允许多个 null 值和一个 null 键。

如果需要线程同步,通常不推荐使用 HashTable 而使用 HashMap。

有关更多详细信息,请参阅 HashTableHashMap


14) Java 中的 main() 方法可以重载吗?

是的,我们可以重载 Java 中的 main() 方法。重载其他方法的方式也是重载 main() 方法的方式。为了启动程序,JVM(Java 虚拟机)会查找方法的签名。普通 main() 方法充当程序的入口点,由 JVM 调用。重载的 main() 方法必须显式调用。观察以下内容。

文件名: OverloadMain.java

输出

Main method with the array of String as the argument.
Main method with integer as the argument.

我们看到带有 int 作为参数的重载 main() 方法已显式调用。


15) 解释 Java 中的同步。

同步确保一次只有一个代码块被访问。如果多个线程访问同一代码块,则存在产生错误结果的风险。我们可以为敏感的代码块提供同步来解决这个问题。术语“同步”表明一个线程需要一个密钥才能访问同步代码。所有 Java 对象都有锁。一个锁只有一个密钥。线程只能在能够获取被锁对象的密钥时才能访问同步方法。锁定是按对象进行的。


16) Java 中的 Collections 是什么意思?

Collections 是一个用于存储对象和编辑对象存储主题的框架。

可以使用集合执行以下操作:

  • 排序
  • 搜索
  • 插入
  • 操纵
  • 删除

一组对象称为集合。集合的所有接口和类都位于 java.util 包中。


17) 提及同步的缺点。

不建议在所有方法的实现中使用同步。因为其中一个线程访问同步代码,然后另一个线程必须等待。因此,这会导致性能下降。


18) 在 Java 中,不使用指针。为什么?

Java 中不使用指针是因为它们增加了程序的复杂性,而且它们也不安全。由于简洁性是 Java 语言最受欢迎的特性之一,添加与指针相关的概念与语言的简洁性相悖。此外,在 Java 中,JVM 负责隐式内存分配。因此,为了避免用户直接访问内存,Java 中不鼓励使用指针。


19) 什么是继承?

继承是对象继承属于不同类的另一个对象的所有特征和动作的机制。它用于代码重用和方法覆盖。Java 中的继承概念是可以在旧类之上构建新类。从现有类继承时,可以使用父类的属性和方法。您还可以为现有类添加方法和附加字段。继承表示父子关系,也称为 IS-A 关系。

Java 中有五种不同类型的继承:

  • 单级继承
  • 多重继承(使用 Java 接口)
  • 多层继承
  • 混合继承
  • 层次继承

20) 接口与抽象类有何不同?

Java 中的接口和抽象类之间有许多区别。

组成部分 - 接口只能包含常量,而抽象类包含实例变量。

构造函数和实例化 - 抽象类可以包含一个默认构造函数,在创建子类对象时调用该构造函数,而接口永远不包含构造函数,并且无法创建接口的对象。

方法实现 - 实现接口的所有类都必须为接口中的所有方法提供实现。然而,扩展抽象类的类不需要为抽象类中的所有方法提供实现。只需要实现抽象类中的抽象方法。

方法类型 - 抽象类同时拥有:非抽象方法和抽象方法。另一方面,在接口的情况下,我们只看到抽象方法。


21) 解释 Java 中线程的生命周期?

线程的生命周期有以下状态并遵循以下顺序:

新建 - 在线程的生命周期中,这是第一个状态。创建了线程的实例,并且尚未调用 start() 方法。现在,该线程被认为是活动的。

可运行 - 在调用 start() 方法之后,但在调用 run() 方法之前,线程处于可运行状态。线程也可能从睡眠或等待状态返回到可运行状态。

运行 - 调用 run() 方法后,线程进入运行状态。此时线程开始执行。

不可运行 - 即使线程处于活动状态,它也无法运行。通常,它会在一段时间后返回到可运行状态。

终止 - 当 run() 方法完成其执行时,线程进入终止状态。现在,线程不再处于活动状态。


22) 区分栈内存和堆内存。

栈内存

  • 用于保存局部变量和方法的执行顺序。
  • 当栈内存填满时,会返回 java.lan.StackOverFlowError。
  • 访问栈内存比访问堆内存更快。
  • 当前正在运行的方法使用栈空间。

堆内存

  • 堆内存用于存储对象。
  • 当堆内存填满时,会返回 java.lang.OutOfMemoryError。
  • 访问堆内存比访问栈内存慢。
  • 在整个应用程序中,使用堆空间。

23) 在子类中重写父类方法时,能否修改 throws 子句?

是的,可以在子类中重写父类方法时修改其 throws 子句。但在异常处理的重写情况下,需要考虑一些规则。

  • 如果父类的方法不声明异常,则子类重写的方法不能声明已检查异常,但可以声明未检查异常。
  • 如果父类的方法声明了异常,则子类重写的方法可以声明相同的子类异常或不声明任何异常,但不能声明父类异常。

24) 是否可以更改子类中重写的方法的作用域?

是的,在 Java 中,可以更改子类中重写的方法的作用域。但是,应注意不能减少方法的访问权限。在更改方法访问权限时,应考虑以下几点:

  • private 访问说明符可以更改为 public、protected 或 default。
  • protected 访问说明符可以更改为 default 或 public。
  • default 访问说明符可以更改为 public。
  • public 访问说明符不能更改为任何其他访问说明符。它将始终保持 public。

25) 在方法中传递 'this' 而不是当前类对象本身有什么好处?

我们知道 'this' 指的是当前类的对象。因此,它应该与当前类的对象相同。但是,在传递“this”而不是当前类对象方面,有两个主要好处。

  1. “this”是一个 final 变量。因此,“this”不能被赋值为任何新值,而当前类的对象可能不是 final 的,并且可以被更改。
  2. 在同步块中,可以使用“this”。