sealed
类和record
类的作用和区别? 答案:sealed
类:限制继承关系,通过permits
指定允许的子类。示例代码:public sealed class Shape permits Circle, Square { ... }
;record
类:不可变数据类,自动生成equals()
、hashCode()
和toString()
。示例代码:public record User(String name, int age) { }
String
、StringBuffer
和StringBuilder
的区别? 答案: | 类 | 可变性 | 线程安全 | 性能 | | --- | --- | --- | --- | | String
| 不可变 | 安全 | 低 | | StringBuffer
| 可变 | 安全 | 中(同步) | | StringBuilder
| 可变 | 不安全 | 高 |equals()
和==
的区别?如何重写equals()
? 答案:==
:比较对象内存地址(基本类型比较值)。equals()
:默认同==
,可重写为逻辑相等(如字符串内容)。重写需满足:自反性、对称性、传递性、一致性。始终重写hashCode()
以保证哈希一致性。JAVA SE
:主要用在客户端开发;JAVA EE
:主要用在web应用程序开发;JAVA ME
:主要用在嵌入式应用程序开发。byte
:Byte
;short
:Short
;int
:Integer
;long
:Long
;float
:Float
;double
:Double
;char
:Character
;boolean
:Boolean
。++i
:先赋值,后计算;i++
:先计算,后赋值。int[] a = new int[]{1,3,3}
;动态实例化:实例化数组的时候,只指定了数组程度,数组中所有元素都是数组类型的默认值。Byte
、short
、int
、long
默认是都是0;Boolean
默认值是false
;Char
类型的默认值是''
;Float
与double
类型的默认是0.0;对象类型的默认值是null
。Java.lang
、Java.io
、Java.sql
、Java.util
、Java.awt
、Java.net
、Java.math
。Object
。Equals
、Hashcode
、toString
、wait
、notify
、clone
、getClass
。try-catch-finally
语句块实现。try
块中放置可能抛出异常的代码,catch
块用于捕获并处理异常,finally
块则无论是否发生异常都会执行。List
、Set
、Queue
和Map
等主要接口,以及ArrayList
、LinkedList
、HashSet
、HashMap
等实现类。NEW
)、就绪(RUNNABLE
)、阻塞(BLOCKED
)、等待(WAITING
)、超时等待(TIMED_WAITING
)和终止(TERMINATED
)。synchronized
关键字或Lock
接口实现线程同步。Class
类实现。反射机制为Java程序提供了强大的动态性。通过反射,程序可以在运行时加载类、创建对象、调用方法等。这使得Java程序能够更加灵活地应对各种复杂场景,如框架设计、插件机制等。synchronized
和ReentrantLock
的底层实现差异? 答案:synchronized
:JVM层面通过monitorenter
和monitorexit
指令实现,依赖对象头中的Mark Word。ReentrantLock
:基于AQS(AbstractQueuedSynchronizer),通过CAS和CLH队列实现锁竞争,支持公平锁和非公平锁。ThreadLocal
的原理和内存泄漏问题如何避免? 答案:原理 :每个线程持有独立的ThreadLocalMap
,Key为弱引用的ThreadLocal
对象。内存泄漏 :Key被回收后,Value仍被强引用,需调用remove()
手动清理。Atomic
类(如AtomicInteger
)的CAS操作;基于Unsafe
类直接操作内存;JDK 8+的LongAdder
替代AtomicLong
,减少CAS竞争。Thread
类;实现Runnable
接口;ExecutorSenvice
、Callable
、Future
有返回值线程;基于线程池的方式。interrupt()
方法中断线程,但需要在线程内部处理中断信号;也可以通过设置标志位来控制线程的运行。notify()
和notifyAll()
有什么区别? 答案:notify()
随机唤醒一个在该对象上等待的线程;notifyAll()
唤醒所有在该对象上等待的线程。sleep()
和wait()
有什么区别? 答案:sleep()
是Thread
类的方法,会让当前线程暂停执行指定的时间,不会释放对象的锁;wait()
是Object
类的方法,会让当前线程进入等待状态,同时释放对象的锁,直到其他线程调用notify()
或notifyAll()
方法唤醒它。volatile
是什么?可以保证有序性吗? 答案:volatile
是一个关键字,用于修饰变量,保证变量的可见性,即当一个变量被声明为volatile
时,它会保证对该变量的写操作会立即刷新到主内存中,而读操作会从主内存中读取最新的值。volatile
不能保证变量操作的原子性和有序性。Thread
类中的start()
和run()
方法有什么区别? 答案:start()
方法用于启动一个新线程,它会调用run()
方法;run()
方法是线程的执行体,包含了线程要执行的代码。如果直接调用run()
方法,并不会启动新线程,而是在当前线程中执行run()
方法中的代码。wait
, notify
和notifyAll
这些方法不在thread
类里面? 答案:wait
, notify
和notifyAll
是Object
类的方法,因为这些方法是用于线程间的通信和同步,而对象是线程间共享的资源,所以这些方法定义在Object
类中,以便所有对象都可以使用。wait
和notify
方法要在同步块中调用? 答案:wait
和notify
方法用于线程间的同步和通信,必须在同步块中调用,因为在调用这些方法时,线程必须持有对象的锁。如果不在同步块中调用,会抛出IllegalMonitorStateException
异常。interrupted()
和isInterrupted()
方法的区别? 答案:interrupted()
是一个静态方法,它会检查当前线程的中断状态,并清除中断标志;isInterrupted()
是一个实例方法,它会检查调用该方法的线程的中断状态,但不会清除中断标志。synchronized
和ReentrantLock
有什么不同? 答案:synchronized
是Java的关键字,是JVM层面的实现,使用简单,自动释放锁;ReentrantLock
是一个类,是基于AQS实现的,功能更强大,如支持公平锁、可中断锁、条件变量等,但需要手动释放锁。join()
方法、CountDownLatch
、CyclicBarrier
等方式来保证线程的顺序执行。例如,使用join()
方法:public class ThreadOrder {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
System.out.println("T1");
});
Thread t2 = new Thread(() -> {
try {
t1.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T2");
});
Thread t3 = new Thread(() -> {
try {
t2.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("T3");
});
t1.start();
t2.start();
t3.start();
}
}
SynchronizedMap
和ConcurrentHashMap
有什么区别? 答案:SynchronizedMap
是Collections
类的静态方法返回的一个同步的Map
,它是通过在每个方法上使用synchronized
关键字来实现同步的,性能较低;ConcurrentHashMap
是Java并发包中的类,它采用分段锁或CAS等技术来实现并发访问,性能较高。Thread
类中的yield()
方法有什么作用? 答案:yield()
方法是Thread
类的静态方法,它会让当前线程放弃CPU的执行权,将CPU让给其他线程,但具体是否让出CPU由操作系统决定。submit()
和execute()
方法有什么区别? 答案:execute()
方法是Executor
接口的方法,用于执行Runnable
任务,没有返回值;submit()
方法是ExecutorService
接口的方法,它可以执行Runnable
或Callable
任务,并且会返回一个Future
对象,用于获取任务的执行结果。synchronized
关键字的了解 答案:synchronized
关键字是Java中用于实现线程同步的关键字,它可以修饰方法或代码块。当修饰方法时,称为同步方法,同一时间只有一个线程可以访问该方法;当修饰代码块时,称为同步代码块,同一时间只有一个线程可以执行该代码块。synchronized
关键字是基于对象的锁机制实现的,每个对象都有一个锁,线程在进入同步方法或同步代码块时需要获取对象的锁,执行完后释放锁。synchronized
关键字,在项目中用到了吗,synchronized
关键字最主要的三种使用方式? 答案:在项目中,synchronized
关键字常用于保护共享资源,避免多线程并发访问导致的数据不一致问题。synchronized
关键字最主要的三种使用方式:public synchronized void method() {
// 同步代码
}
public static synchronized void staticMethod() {
// 同步代码
}
public void method() {
synchronized (this) {
// 同步代码
}
}
volatile
的可见性、synchronized
的原子性)。硬件模型 :通过CPU缓存一致性协议(如MESI)实现内存可见性。-XX:+HeapDumpOnOutOfMemoryError
生成堆转储文件;通过MAT或VisualVM分析堆转储,定位大对象或内存泄漏;检查代码中的静态集合、未关闭资源、缓存策略。-Xms
:设置堆的初始大小。-Xmx
:设置堆的最大大小。-XX:+UseG1GC
:使用G1垃圾回收器。-XX:MetaspaceSize
:设置元空间的初始大小。-XX:MaxMetaspaceSize
:设置元空间的最大大小。jstat
、jmap
、VisualVM
、MAT
等工具来查看JVM的内存使用情况。例如,使用jstat
命令查看堆内存的使用情况:jstat -gc
,其中
是Java进程的ID,
是统计间隔时间(单位:毫秒),
是统计次数。StringBuilder
或StringBuffer
不断追加字符串,导致内存占用过大。ThreadLocal
使用不当,导致对象无法被回收。-Xms
和-Xmx
:设置堆的初始大小和最大大小,避免堆频繁扩容和收缩,提高性能。-XX:+UseG1GC
:使用G1垃圾回收器,G1是一种面向服务器端应用的垃圾回收器,具有较低的停顿时间和较高的吞吐量。-XX:MetaspaceSize
和-XX:MaxMetaspaceSize
:设置元空间的初始大小和最大大小,避免元空间频繁扩容。-XX:+HeapDumpOnOutOfMemoryError
:当发生内存溢出时,自动生成堆转储文件,方便后续分析。BeanNameAware
→ BeanFactoryAware
→ ApplicationContextAware
→ PostConstruct
→ InitializingBean
→ 自定义init
方法 → 使用 → PreDestroy
→ DisposableBean
→ 自定义destroy
方法。@EnableAutoConfiguration
加载META-INF/spring.factories
中的配置类;利用条件注解(如@ConditionalOnClass
)按需加载Bean。public
→ 事务注解不生效;自调用(同一类中调用带@Transactional
的方法)→ 代理失效;异常未被抛出或捕获后未回滚 → 需配置rollbackFor
。singleton
:单例模式,Spring容器中只会创建一个Bean实例。prototype
:原型模式,每次从Spring容器中获取Bean时,都会创建一个新的实例。request
:在一次HTTP请求中,只会创建一个Bean实例。session
:在一个HTTP会话中,只会创建一个Bean实例。global session
:在全局会话中,只会创建一个Bean实例。@SpringBootApplication
:是一个组合注解,包含了@SpringBootConfiguration
、@EnableAutoConfiguration
和@ComponentScan
,用于启动Spring Boot应用。@EnableAutoConfiguration
:启用Spring Boot的自动配置功能。@ComponentScan
:扫描指定包及其子包下的组件。@Configuration
:用于定义配置类,相当于传统的XML配置文件。@Bean
:用于在配置类中定义Bean。application.properties
或application.yml
配置文件,也可以通过@PropertySource
注解指定其他配置文件。配置文件的加载顺序如下:SPRING_APPLICATION_JSON
中的属性。ServletConfig
初始化参数。ServletContext
初始化参数。java:comp/env
)。System.getProperties()
)。RandomValuePropertySource
生成的random.*
属性。application.properties
或application.yml
文件。application.properties
或application.yml
文件。application-{profile}.properties
或application-{profile}.yml
文件。application-{profile}.properties
或application-{profile}.yml
文件。@PropertySource
注解指定的属性源。SpringApplication.setDefaultProperties
指定)。application.properties
或application.yml
配置文件中进行日志配置,也可以使用自定义的日志配置文件。例如,在application.properties
中配置日志级别:logging.level.root=INFO
。application.properties
或application.yml
配置文件中配置数据库连接信息,例如:spring.datasource.url=jdbc:mysql://localhost:3306/test
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
也可以使用@Configuration
注解和DataSource
Bean来进行数据库连接配置。 90. Spring Boot如何进行缓存配置? 答案:Spring Boot支持多种缓存技术,如Redis、Ehcache等。可以通过在application.properties
或application.yml
配置文件中配置缓存相关信息,也可以使用@EnableCaching
注解启用缓存功能,并使用@Cacheable
、@CachePut
、@CacheEvict
等注解来管理缓存。例如,使用Redis作为缓存:
spring.cache.type=redis
spring.redis.host=localhost
spring.redis.port=6379