Java校招120道面试题目合集及答案
一、Java基础
1. Java语言有哪些特点?
答案:
- 简单性:Java语法简洁,去除了C++中一些复杂和容易出错的特性,如指针、多重继承等。例如定义一个简单的类:
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello, World!");
}
}
- 面向对象:支持封装、继承和多态等面向对象特性。以封装为例,将数据和操作数据的方法封装在类中,提高了代码的安全性和可维护性。
class Person {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
- 平台无关性:通过Java虚拟机(JVM)实现“一次编写,到处运行”。Java源文件(.java)被编译器编译成字节码文件(.class),不同平台的JVM可以将相同的字节码文件解释成该平台所需的机器码。
- 可靠性:具有自动垃圾回收机制,减少了程序员手动管理内存的负担,降低了内存泄漏和悬空指针等错误的发生概率。例如,当一个对象不再被引用时,垃圾回收器会自动回收其占用的内存。
- 安全性:Java提供了安全管理器,严格限制程序对系统资源的访问。在网络应用中,能有效防止恶意代码的攻击。
2. 什么是Java虚拟机(JVM)?它的作用是什么?
答案:Java虚拟机(Java Virtual Machine)是执行字节码文件的虚拟机进程。它的主要作用是:
- 执行字节码:将Java编译器生成的字节码文件(.class)解释或编译成机器码,以便在不同的硬件和操作系统平台上运行。例如,在Windows系统上,JVM将字节码解释成适用于x86架构的机器码;在Linux系统上,JVM将字节码解释成适用于相应Linux内核和硬件架构的机器码。
- 提供运行时环境:为Java程序提供内存管理、线程管理、安全检查等运行时支持。比如,JVM负责分配和回收堆内存,管理线程的生命周期和调度。
- 实现平台无关性:不同的平台装有不同的JVM,它们能够将相同的.class文件解释成不同平台所需的机器码,使得Java程序能够在各种平台上运行,实现“一次编写,到处运行”。
3. “static”关键字是什么意思?
答案:“static”关键字在Java中有多种用途:
- 修饰成员变量:被static修饰的成员变量属于类,而不是类的某个实例。该变量在内存中只有一份,被所有实例共享。例如:
class Student {
private static int studentCount = 0;
private String name;
public Student(String name) {
this.name = name;
studentCount++;
}
public static int getStudentCount() {
return studentCount;
}
}
在上述代码中,studentCount
是一个静态成员变量,记录学生的数量。每创建一个Student
对象,studentCount
就会自增1。可以通过Student.getStudentCount()
来获取学生总数。
- 修饰成员方法:静态方法同样属于类,可通过类名直接调用,无需创建类的实例。静态方法只能访问静态成员变量和其他静态方法,不能访问非静态成员。例如:
class MathUtils {
public static int add(int a, int b) {
return a + b;
}
}
调用时可使用MathUtils.add(3, 5)
。
- 静态代码块:使用
static
关键字定义的代码块,在类加载时执行,且只执行一次。常用于初始化静态成员变量或执行一些一次性的操作。例如:
class Database {
private static Connection connection;
static {
try {
connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/mydb", "username", "password");
} catch (SQLException e) {
e.printStackTrace();
}
}
public static Connection getConnection() {
return connection;
}
}
上述代码中,静态代码块在Database
类加载时尝试建立数据库连接,后续可通过Database.getConnection()
获取连接。
4. Java支持的数据类型有哪些?
答案:Java支持两种数据类型:
- 基本数据类型:共8种,包括
byte
(1字节)、short
(2字节)、int
(4字节)、long
(8字节)、float
(4字节)、double
(8字节)、boolean
(1位,具体实现可能不同)、char
(2字节,用于表示Unicode字符)。例如:
byte b = 10;
short s = 100;
int i = 1000;
long l = 10000000000L;
float f = 3.14f;
double d = 3.1415926;
boolean flag = true;
char c = 'A';
- 引用数据类型:包括类、接口、数组等。引用数据类型的变量存储的是对象在堆内存中的地址。例如:
String str = "Hello";
int[] array = {
1, 2, 3};
在上述代码中,str
是String
类的引用,array
是int
类型数组的引用。
5. Java中的方法覆盖(Overriding)和方法重载(Overload)是什么意思?
答案:
- 方法覆盖(Overriding):
- 发生在子类与父类之间,当子类继承父类后,子类可以重新定义父类中已有的方法。
- 方法覆盖要求子类方法与父类被覆盖方法具有相同的方法名、参数列表和返回类型(返回类型可以是父类被覆盖方法返回类型的子类,这是Java 5.0引入的协变返回类型特性)。
- 子类方法不能比父类被覆盖方法有更严格的访问权限(例如,父类方法是
public
,子类覆盖方法不能是protected
或private
)。例如:
class Animal {
public void makeSound() {
System.out.println("Animal makes a sound");
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("Dog barks");
}
}
在上述代码中,Dog
类覆盖了Animal
类的makeSound
方法。
- 方法重载(Overload):
- 发生在同一个类中,多个方法可以具有相同的方法名,但参数列表必须不同(参数个数、参数类型或参数顺序不同)。
- 方法重载与返回类型无关,即返回类型可以相同也可以不同。例如:
class Calculator {
public int add(int a, int b) {
return a + b;
}
public double add(double a, double b) {
return a + b;
}
public int add(int a, int b, int c) {
return a + b + c;
}
}
在上述Calculator
类中,定义了三个add
方法,通过不同的参数列表实现了方法重载。
6. Java中,什么是构造方法?
答案:构造方法是一种特殊的方法,用于创建对象并初始化对象的成员变量。其特点如下:
- 方法名与类名相同:例如,对于类
Person
,其构造方法为Person
。
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
- 没有返回类型:包括
void
也不能有。 - 在创建对象时自动调用:通过
new
关键字创建对象时,会调用相应的构造方法。例如:
Person person = new Person("John", 25);
在上述代码中,创建Person
对象时,会调用参数为String
和int
的构造方法,将name
初始化为"John"
,age
初始化为25
。
- 可以有多个构造方法:通过方法重载实现,以满足不同的初始化需求。例如:
class Person {
private String name;
private int age;
public Person() {
// 无参构造方法,可进行默认初始化
name = "Unknown";
age = 0;
}
public Person(String name) {
this.name = name;
age = 0;
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
}
在上述Person
类中,定义了三个构造方法,分别用于不同的初始化场景。
7. Java支持多继承么?
答案:Java类不支持多继承,即一个类不能同时继承多个父类。这是为了避免多继承带来的菱形继承问题(当一个类从多个父类继承相同的属性或方法时,可能会导致冲突和不确定性)。例如:
// 以下代码会报错,因为Java类不支持多继承
class A {
}
class B {
}
class C extends A, B {
}
然而,Java通过接口(interface)实现了类似多继承的功能。一个类可以实现多个接口,从而获取多个接口的行为和规范。例如:
interface Flyable {
void fly();
}
interface Swimmable {
void swim();
}
class Duck implements Flyable, Swimmable {
@Override
public void fly() {
System.out.println("Duck is flying");
}
@Override
public void swim() {
System.out.println("Duck is swimming");
}
}
在上述代码中,Duck
类实现了Flyable
和Swimmable
两个接口,具备了飞行和游泳的行为。
8. 什么是值传递和引用传递?
答案:
- 值传递:在方法调用时,实际参数将其值传递给对应的形式参数,方法对形式参数的修改不会影响实际参数的值。例如:
public class ValueTransfer {
public static void main(String[] args) {
int num = 10;
System.out.println("Before method call: num = " + num);
changeValue(num);
System.out.println("After method call: num = " + num);
}
public static void changeValue(int n) {
n = 20;
}
}
在上述代码中,main
方法中的num
值为10,调用changeValue
方法时,将num
的值10传递给n
,在changeValue
方法中修改n
的值为20,但这并不会影响main
方法中num
的值,最终输出Before method call: num = 10
和After method call: num = 10
。
- 引用传递:在方法调用时,实际参数的引用(对象在堆内存中的地址)被传递给形式参数。此时方法中对形式参数所指向对象的修改,会影响到实际参数所指向的对象。例如:
class Person {
String name;
public Person(String name) {
this.name = name;
}
}
public class ReferenceTransfer {
public static void main(String[] args) {
Person person = new Person("John");
System.out.println("Before method call: person.name = " + person.name);
changeName(person);
System.out.println("After method call: person.name = " + person.name);
}
public static void changeName(Person p) {
p.name = "Jane";
}
}
在上述代码中,main
方法创建了一个Person
对象,name
为"John"
,调用changeName
方法时,将person
的引用传递给p
,在changeName
方法中修改p
所指向对象的name
为"Jane"
,由于p
和person
指向同一个对象,所以main
方法中person
的name
也被修改为"Jane"
,最终输出Before method call: person.name = John
和After method call: person.name = Jane
。需要注意的是,在Java中,对象的传递本质上是引用传递,但基本数据类型的传递是值传递。
9. 进程和线程的区别是什么?
答案:
- 定义:
- 进程:是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位。每个进程都有自己独立的内存空间、系统资源(如文件描述符、内存空间等)。例如,当我们运行一个Java程序时,操作系统会为其创建一个进程,该进程拥有独立的堆内存、栈内存等资源。
- 线程:是进程中的一个执行单元,是程序执行的最小单位。一个进程可以包含多个线程,这些线程共享进程的资源,如内存空间、文件描述符等。例如,在一个Java Web服务器进程中,可以有多个线程同时处理不同客户端的请求,这些线程共享服务器进程的内存和其他资源。
- 资源分配:
- 进程:拥有独立的资源,进程之间的资源相互隔离。不同进程之间要进行通信和数据共享,需要使用进程间通信(IPC)机制,如管道、消息队列、共享内存等。
- 线程:共享所属进程的资源,同一进程内的线程之间通信和数据共享更为方便,通过共享内存即可实现。但也正因如此,多线程编程需要注意线程安全问题,避免多个线程同时访问和修改共享资源导致数据不一致。
- 调度:
- 进程:进程的调度由操作系统负责,进程上下文切换的开销较大,因为需要切换内存空间、寄存器等资源。
- 线程:线程的调度也由操作系统负责,但线程上下文切换的开销相对较小,因为线程共享进程的资源,不需要切换内存空间,只需切换少量的寄存器等资源。
- 并发性能:
- 进程:进程之间的并发是真正的并发,因为每个进程都有自己独立的执行流。但由于进程上下文切换开销大,创建和销毁进程的成本也较高,所以在高并发场景下,使用进程来实现并发可能会导致性能问题。
- 线程:线程之间也能实现并发,而且由于其轻量级的特性,更适合用于高并发场景。通过多线程编程,可以充分利用CPU的多核特性,提高程序的执行效率。但多线程编程也面临着线程安全、死锁等问题,需要谨慎处理。
10. 创建线程有几种不同的方式?
答案:有4种方式可以用来创建线程:
- 继承Thread类:
- 定义一个类继承自
Thread
类。 - 重写
run
方法,在run
方法中编写线程执行的代码。 - 创建该类的实例,并调用
start
方法启动线程。例如:
- 定义一个类继承自
class MyThread extends Thread {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
}
}
}
public class ThreadCreationExample {
public static void main(String[] args) {
MyThread myThread = new MyThread();
myThread.start();
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName() + " : " + i);
}
}
}
在上述代码中,MyThread
类继承自Thread
类,重写了run
方法。在main
方法中创建MyThread
实例并调用start
方法启动线程,同时main
方法本身也是一个线程,两个线程并发执行。
- 实现Runnable接口:
- 定义一个类实现
Runnable
接口。 - 实现
run
方法,编写线程执行的代码。 - 创建该类的实例,并将其作为参数传递给
Thread
类的构造函数,然后调用Thread
实例的start
方法启动线程。例如:
- 定义一个类实现
```java
class MyRunnable implements Runnable {
@Override
public void run() {
for (int i = 0; i < 5; i++) {
System.out.println
``` ...
Java, 校招面试,面试题目,题目合集,答案详解,Java 面试,校招面试题,Java 校招,面试题答案,编程面试,Java 编程,求职面试,校招求职,面试攻略,Java 知识点
资源地址:
https://pan.quark.cn/s/14fcf913bae6