Java 基础面试全攻略,持续更新
本文系统梳理了Java基础面试的核心知识点,包括对象比较(equals与==)、final关键字、方法重载与重写、字符串处理(String/StringBuffer/StringBuilder)、I/O模型(BIO/NIO/AIO)等关键技术点。同时涵盖了数据类型、异常处理、多线程同步、集合框架、JVM内存模型、设计模式等进阶内容,并对比了常见技术方案的选择标准(如金额计算使用BigDecimal
在 Java 开发领域,扎实的基础知识是成功面试的关键。本文将围绕一系列 Java 基础面试问题进行详细解答,涵盖多个重要方面,帮助你更好地准备面试。
1. equals 与 = 的区别
- equals 方法用于比较两个对象的内容是否相等。在 Java 中,对于一些类如 String 、 Integer 等, equals 方法已经被重写,以比较对象的值而不是引用。而 = 是用于比较两个引用是否指向同一个对象。
2. final、finally、finalize 的区别
- final :可以修饰类、方法和变量。修饰类表示该类不能被继承;修饰方法表示该方法不能被重写;修饰变量表示该变量一旦被初始化就不能被改变。
- finally :用于 try-catch-finally 语句块中,表示无论是否发生异常,finally 块中的代码一定会被执行。
- finalize :是 Object 类中的一个方法,在垃圾回收器确定对象没有被引用时,会调用该对象的 finalize 方法进行一些清理操作。但这个方法不建议主动调用,并且不能保证一定会被执行。
3. 重载和重写的区别
- 重载(Overloading):是在同一个类中,方法名相同,但参数列表不同(参数个数、类型、顺序不同)。重载主要是为了让方法具有相同的功能但适用于不同的输入情况。
- 重写(Overriding):发生在子类和父类之间,子类重写父类的方法。方法名、参数列表和返回类型必须与父类中被重写的方法相同。重写的目的是为了实现多态,让子类可以根据自己的需求实现父类的方法。
4. String、StringBuffer、StringBuilder 的区别
- String :是不可变的字符序列,一旦创建,其内容不能被修改。每次对 String 的操作都会创建一个新的 String 对象,这可能会导致性能问题。
- StringBuffer :是可变的字符序列,线程安全。在进行字符串操作时,会对自身进行修改而不是创建新的对象,适用于多线程环境下的字符串操作。
- StringBuilder :也是可变的字符序列,与 StringBuffer 类似,但不是线程安全的。在单线程环境下,性能比 StringBuffer 更好。
5. BIO、NIO 的区别
- BIO(Blocking I/O):传统的阻塞式 I/O,在进行 I/O 操作时,线程会被阻塞,直到操作完成。适用于连接数较少的场景。
- NIO(Non-blocking I/O):非阻塞式 I/O,通过选择器(Selector)可以同时管理多个通道(Channel),当通道没有数据可读或可写时,线程不会被阻塞,可以继续执行其他任务。适用于连接数较多且连接时间较长的场景。
- AIO(Asynchronous I/O):异步 I/O,当进行 I/O 操作时,线程立即返回,由操作系统在后台完成 I/O 操作,并在操作完成后通知应用程序。适用于对响应时间要求较高的场景。
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处即可-免费获取】
https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1ho
二、Java 数据类型
1. Java 中的基本数据类型有哪些
Java 中的基本数据类型包括:
- 整数类型: byte 、 short 、 int 、 long 。
- 浮点类型: float 、 double 。
- 字符类型: char 。
- 布尔类型: boolean 。
2. Comparator 与 Comparable 的区别
- Comparable :是一个接口,实现该接口的类需要实现 compareTo 方法,用于定义对象的自然排序顺序。
- Comparator :是一个函数式接口,用于定义比较两个对象的规则。可以在不修改原有类的情况下,通过实现 Comparator 接口来定义不同的比较策略。
3. String 类能被继承吗,为什么
String 类不能被继承。这是因为 String 类被 final 修饰, final 修饰的类不能被继承。这样设计的目的是为了保证 String 对象的安全性和不可变性。
三、Java 变量和常量
1. Java 中变量和常量有什么区别
- 变量:在程序运行过程中,其值可以被改变的量。变量需要声明类型,并可以在程序的不同位置进行赋值和修改。
- 常量:在程序运行过程中,其值不能被改变的量。常量通常使用 final 关键字修饰,并且在声明时必须进行初始化。
2. int 和 Integer 的区别
- int 是基本数据类型,直接存储数值。
- Integer 是包装类,对象中存储的是对基本类型 int 的引用。 Integer 提供了一些方法,如 parseInt 、 toString 等,方便对整数进行操作。在自动装箱和自动拆拆箱的机制下, int 和 Integer 可以自动转换。
3. 说说你对 Integer 缓存的理解
Java 中 Integer 类有一个缓存机制,在自动装箱时,如果值在 -128 到 127 之间,会从缓存中获取 Integer 对象,而不是创建新的对象。这样可以提高性能,减少对象的创建。
四、Java 异常处理机制
Java 中的异常处理机制是通过 try-catch-finally 语句块来实现的。当程序发生异常时,会抛出一个异常对象。可以在 try 块中放置可能发生异常的代码,在 catch 块中捕获并处理特定类型的异常, finally 块中的代码无论是否发生异常都会被执行。
五、Java 反射及实现原理
1. 说说反射用途及实现原理
- 用途:
- 在运行时动态地创建对象、调用方法、访问字段。
- 实现框架的扩展性,如 Spring 框架中通过反射实现依赖注入。
- 实现动态代理。
- 实现原理:Java 反射机制主要通过访问 Java 类的元数据来实现。在 Java 中,每个类都有一个对应的 Class 对象,该对象包含了类的名称、方法、字段等信息。通过 Class 对象,可以获取类的构造函数、方法和字段,并进行动态调用和访问。
六、Java 对象创建方式
Java 创建对象有以下几种方式:
- 使用 new 关键字创建对象。
- 使用反射机制创建对象,如 Class.forName("className").newInstance() 。
- 使用克克隆Clone)方法创建对象,需要实现 Cloneable 接口并重写 clone 方法。
- 使用反序列化创建对象,从字节流中恢复对象的状态。
七、Java 线程同步
1. 如何实现线程的同步
- 使用 synchronized 关键字修饰方法或代码块,实现线程的同步访问。
- 使用 ReentrantLock 类实现同步,它提供了比 synchronized 更灵活的锁机制。
2. 什么是守护线程?与普通线程的区别
- 守护线程(Daemon Thread)是一种在后台运行的线程,主要用于为其他线程提供服务。当所有的非守护线程结束时,守护线程会自动结束。
- 区别:普通线程在主线程结束后,如果自身还在运行,会继续执行直到完成。而守护线程在没有非守护线程运行时,会自动结束。
八、Java 集合框架
1. Java 中的集合框架有哪些核心接口
Java 集合框架的核心接口包括:
- Collection :表示一组对象的集合,分为 List 、 Set 和 Queue 三大类。
- Map :表示键值对的映射关系。
2. ArrayList 和 LinkedList 有什么区别
- ArrayList :基于数组实现,随机访问速度快,但在插入和删除元素时需要移动大量元素,效率较低。
- LinkedList :基于链表实现,插入和删除元素速度快,但随机访问需要遍历链表,效率较低。
3. HashMap 和 Hashtable 有什么区别
- HashMap :非线程安全,允许 null 键和 null 值。
- Hashtable :线程安全,不允许 null 键和 null 值。
九、Java 序列化
Java 的序列化是将对象转换为字节流的过程,以便在网络传输或存储到文件中。实现 Serializable 接口的类的对象可以被序列化。反序列化是将字节流转换回对象的过程。
十、Java 内部类理解
内部类是在一个类内部定义的类。内部类可以访问外部类的私有成员,并且可以实现更好的封装和代码组织。内部类分为成员内部类、局部内部类、匿名内部类和静态内部类。
十一、Java lambda 表达式理解
Java lambda 表达式是一种简洁的函数式编程方式,可以用来代替匿名内部类。它允许将函数作为方法的参数或返回值,提高了代码的可读性和简洁性。
十二、Java 泛型理解
泛型是一种在编译时进行类型检查的机制,可以提高代码的安全性和可重用性。通过使用泛型,可以在编译时检测类型不匹配的错误,避免在运行时出现 ClassCastException 。
十三、静态内部类与非静态内部类区别
- 静态内部类:可以直接访问外部类的静态成员,不能访问外部类的非静态成员。不需要外部类的实例就可以创建静态内部类的对象。
- 非静态内部类:可以访问外部类的所有成员。需要外部类的实例才能创建非静态内部类的对象。
十四、String 与 new String 区别
- String str = "abc" :创建一个字符串常量,存储在字符串常量池中。如果常量池中已经存在相同的字符串,直接返回该字符串的引用。
- String str = new String("abc") :创建一个新的 String 对象,存储在堆中。即使常量池中已经存在相同的字符串,也会创建新的对象。
十五、反射中 Class.forName 和 ClassLoader 的理解
- Class.forName() :不仅会加载类,还会对类进行初始化,即执行类的静态代码块。
- ClassLoader.loadClass() :只加载类,不进行初始化。
十六、JDK 动态代理与 CGLIB 实现的区别
- JDK 动态代理:基于接口实现代理,要求被代理的类必须实现一个或多个接口。
- CGLIB:基于继承实现代理,可以代理没有实现接口的类。CGLIB 通过生成被代理类的子类来实现代理功能。
十七、自定义注解的场景及实现
- 场景:用于代码的元数据标注,如标记方法的功能、参数的含义等。可以用于框架的扩展,如 Spring 的 @Autowired 注解用于自动装配。
- 实现:定义一个注解接口,使用 @interface 关键字。可以设置注解的属性和默认值。在使用注解时,可以通过反射获取注解的信息,并根据注解的内容进行相应的处理。
十八、设计模式的理解及分类
1. 说说你对设计模式的理解
设计模式是在软件开发过程中,针对反复出现的问题所总结出的通用解决方案。设计模式可以提高代码的可维护性、可扩展性和可重用性。
2. 设计模式是如何分类的
设计模式通常分为三大类:
- 创建型模式:用于对象的创建,如单例模式、工厂模式、抽象工厂模式等。
- 结构型模式:用于处理类或对象的,如代理模式、装饰器模式、适配器模式等。
- 行为型模式:用于处理对象之间的交互和职责分配,如观察者模式、策略模式、模板方法模式等。
十九、抽象工厂和工厂方法模式的区别
- 工厂方法模式:定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法模式把对象的创建延迟到子类中。
- 抽象工厂模式:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。抽象工厂模式通常用于创建一组相关的产品对象。
二十、值传递和引用传递的理解
- 值传递:在方法调用时,将实际参数的值复制一份传递给方法的形式参数。在方法内部对形式参数的修改不会影响实际参数的值。
- 引用传递:在方法调用时,将实际参数的引用(内存地址)传递给方法的形式参数。在方法内部对形式参数的修改会影响实际参数的值。
Java 中基本数据类型是值传递,对象类型是引用传递。
二十一、Java 支持多继承么,为什么
Java 不支持多继承,即一个类不能同时继承多个类。这是为了避免多继承带来的复杂性和二义性问题。例如,如果一个类同时继承了两个具有相同方法的父类,那么在调用这个方法时,编译器无法确定应该调用哪个父类的方法。
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处即可-免费获取】
https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1ho
二十二、构造器是否可被重写
构造器不能被重写。构造器是用于创建对象的特殊方法,它的名称与类名相同。重写是指子类重写父类的方法,而构造器不是方法,所以不能被重写。
二十三、char 型变量能存贮一个中文汉字吗
在 Java 中, char 类型占用 2 个字节,可以存储一个中文汉字。因为 Java 使用 Unicode 编码,一个汉字通常占用 2 个字节或更多的存储空间。
二十四、如何实现对象克隆
要实现对象克隆,需要实现 Cloneable 接口并重写 clone 方法。在 clone 方法中,可以调用 super.clone() 来实现浅克隆,即只复制对象的基本类型字段和引用的地址,而不复制引用指向的对象。如果需要实现深克隆,需要对引用指向的对象也进行克隆。
二十五、for-each 与常规 for 循环的效率区别
在大多数情况下, for-each 循环和常规 for 循环的效率是相似的。但在某些情况下,常规 for 循环可能会更高效,因为它可以在循环中进行更多的控制,如跳过某些元素或提前结束循环。而 for-each 循环更加简洁和易读,适用于遍历集合或数组的情况。
二十六、懒汉模式和饿汉模式的理解
- 懒汉模式:在第一次使用时才创建对象,实现了延迟加载。但在多线程环境下可能会出现线程安全问题,需要进行同步处理。
- 饿汉模式:在类加载时就创建对象,不存在线程安全问题,但可能会浪费资源,如果对象的创建成本较高,可能会影响程序的启动性能。
二十七、常见的运行时异常有哪些
常见的运行时异常包括:
- NullPointerException :空指针异常,当尝试访问一个 null 对象的成员时抛出。
- ArrayIndexOutOfBoundsException :数组下标越界异常,当访问数组时使用了超出数组范围的下标时抛出。
- ClassCastException :类型转换异常,当尝试将一个对象转换为不兼容的类型时抛出。
- ArithmeticException :算术异常,如除以零等算术错误时抛出。
二十八、synchronized 的实现原理及锁优化
synchronized 是通过对象的监视器(Monitor)实现的。当一个线程进入 synchronized 代码块时,会获取对象的监视器锁,其他线程试图进入该代码块时会被阻塞,直到持有锁的线程释放锁。
锁优化包括:
- 偏向锁:在没有竞争的情况下,将锁偏向于一个线程,避免每次获取锁都进行同步操作。
- 轻量级锁:当出现少量竞争时,使用轻量级锁进行同步,通过自旋(循环等待)的方式避免进入阻塞状态。
- 重量级锁:当竞争激烈时,升级为重量级锁,通过操作系统的互斥量实现同步。
二十九、ThreadLocal 的理解及应用场景
1. 讲讲你对 ThreadLocal 的理解
ThreadLocal 是一个线程本地变量工具类,它可以为每个线程提供独立的变量副本。每个线程都可以独立地修改和访问自己的变量副本,而不会影响其他线程。
2. ThreadLocal 有哪些应用场景
- 数据库连接管理:在多线程环境下,每个线程可以拥有自己独立的数据库连接,避免连接的共享和竞争。
- 用户会话管理:在 Web 应用中,可以使用 ThreadLocal 存储用户的会话信息,方便在不同的方法中访问。
- 事务管理:在事务处理中,可以使用 ThreadLocal 存储事务的上下文信息,如事务的开始时间、状态等。
三十、CountDownLatch 的理解
CountDownLatch 是一个同步工具类,它允许一个或多个线程等待其他线程完成操作。它的主要方法是 await 和 countDown 。线程调用 await 方法会被阻塞,直到 CountDownLatch 的计数器变为零。其他线程可以调用 countDown 方法减少计数器的值。
三十一、CyclicBarrier 的理解
CyclicBarrier 是一个同步工具类,它允许一组线程互相等待,直到所有线程都到达一个共同的屏障点。它的主要方法是 await 。当所有线程都调用了 await 方法后, CyclicBarrier 会触发一个可选的 Runnable 任务,然后所有线程继续执行。
三十二、金额使用 Long 还是 BigDecimal
对于金额等精确数值的计算,应该使用 BigDecimal 。因为 long 是整数类型,无法精确表示小数金额。而 double 和 float 是浮点类型,在进行数值计算时可能会出现精度丢失的问题。 BigDecimal 可以精确地表示和计算小数,并且提供了丰富的方法来进行数值运算和舍入控制。
三十三、日期格式化用 yyyy 还是 YYYY
在日期格式化中,应该使用 yyyy 而不是 YYYY 。 yyyy 表示四位的年份,符合常用的年份表示方式。而 YYYY 在某些情况下可能会导致意外的结果,特别是在跨年的时候。例如,在 2024 年 12 月 31 日使用 YYYY 格式化可能会得到 2025 年,因为 YYYY 表示的是基于周的年份,可能与实际的日历年份不一致。
三十四、并发编程相关知识点
并发编程是 Java 中一个重要的领域,涉及到多线程、线程安全、同步机制、并发集合等方面。一些关键的知识点包括:
1. 线程安全
当多个线程同时访问一个共享资源时,如果不会导致数据不一致或其他错误,那么这个资源就是线程安全的。实现线程安全的方法包括使用同步机制(如 synchronized 、 ReentrantLock )、使用不可变对象、使用线程安全的集合类等。
2. 线程间通信
线程间可以通过共享变量和同步机制进行通信。常见的通信方式包括等待/通知机制(使用 wait 、 notify 和 notifyAll 方法)、 CountDownLatch 、 CyclicBarrier 、 Semaphore 等。
3. 并发集合
Java 提供了一些专门用于并发环境的集合类,如 ConcurrentHashMap 、 CopyOnWriteArrayList 、 ConcurrentLinkedQueue 等。这些集合类在多线程环境下提供了更高的性能和线程安全保证。
4. 线程池
线程池是一种管理线程的方式,可以重复利用线程,减少线程创建和销毁的开销。 java.util.concurrent.Executors 类提供了一些创建线程池的方法,如 newFixedThreadPool 、 newCachedThreadPool 、 newScheduledThreadPool 等。
三十五、JVM 相关知识点
JVM(Java Virtual Machine)是 Java 程序的运行环境,了解 JVM 的相关知识对于优化 Java 程序和解决性能问题非常重要。一些关键的知识点包括:
1. 内存模型
JVM 的内存模型包括堆、栈、方法区、程序计数器等。堆用于存储对象实例,栈用于存储方法调用的栈帧,方法区用于存储类信息、常量、静态变量等。了解内存模型可以帮助理解对象的生命周期、垃圾回收机制以及内存泄漏的原因。
2. 垃圾回收
JVM 自动管理内存,通过垃圾回收机制回收不再使用的对象占用的内存。垃圾回收算法包括标记-清除、标记-整理、复制算法等。了解垃圾回收机制可以帮助优化程序的内存使用,减少垃圾回收的次数和时间。
3. 类加载机制
JVM 通过类加载器将类的字节码加载到内存中,并进行链接和初始化。类加载器分为启动类加载器、扩展类加载器和应用程序类加载器。了解类加载机制可以帮助理解类的加载过程、动态加载和热部署等技术。
4. JVM 调优
可以通过调整 JVM 的参数来优化程序的性能,如调整堆大小、设置垃圾回收算法、调整线程栈大小等。了解 JVM 的调优参数和方法可以帮助提高程序的性能和稳定性。
三十六、Mysql 相关知识点
MySQL 是一种广泛使用的关系型数据库管理系统,了解 MySQL 的相关知识对于开发和管理数据库应用非常重要。一些关键的知识点包括:
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafka 面试专题
需要全套面试笔记【点击此处即可-免费获取】
https://docs.qq.com/doc/DQXdYWE9LZ2ZHZ1ho
1. 数据库设计
合理的数据库设计可以提高数据的存储效率、查询性能和数据的完整性。数据库设计包括表结构设计、索引设计、数据类型选择、范式等方面。
2. SQL 语句
掌握 SQL 语句是使用 MySQL 的基础,包括查询语句、插入语句、更新语句、删除语句、事务处理等。了解 SQL 的优化技巧可以提高查询性能,减少数据库的负载。
3. 索引优化
索引可以提高查询性能,但过多或不合理的索引也会影响数据库的性能。了解索引的类型、创建方法和优化技巧可以帮助提高数据库的查询性能。
4. 存储引擎
MySQL 支持多种存储引擎,如 InnoDB、MyISAM、Memory 等。不同的存储引擎具有不同的特点和适用场景,了解存储引擎的区别可以帮助选择合适的存储引擎。
5. 数据库备份和恢复
定期备份数据库可以防止数据丢失,了解数据库备份和恢复的方法可以帮助在数据丢失或损坏时快速恢复数据。
三十七、English 相关知识点(此点可能指面试中可能涉及的英语能力考察)
在 Java 面试中,可能会涉及到一些英语能力的考察,如阅读英文文档、理解英文技术术语、用英语进行交流等。以下是一些建议:
1. 提高英语阅读能力
阅读 Java 相关的英文文档、技术博客、书籍等,可以帮助提高英语阅读能力和技术水平。可以从简单的文档开始,逐渐提高阅读难度。
2. 学习英语技术术语
掌握 Java 相关的英语技术术语,如 class、interface、method、variable、exception 等,可以帮助理解和交流技术问题。可以通过阅读英文文档、参加技术交流等方式学习英语技术术语。
3. 练习英语交流
如果面试中可能需要用英语进行交流,可以提前练习英语交流能力。可以找英语母语者或英语水平较高的人进行交流练习,提高口语表达和听力理解能力。
总之,Java 基础面试涵盖了多个方面的知识,需要全面准备。通过深入理解每个知识点,并结合实际项目经验进行思考和总结,可以提高面试的成功率。同时,不断学习和提升自己的技术水平,才能在 Java 开发领域中取得更好的发展。
更多推荐
所有评论(0)