当前位置: 首页 > news >正文

Java 核心技术与框架实战十八问

1、java基本数据类型以及长度 (语言类)

整数类型

用于存储整数数值,以二进制补码形式表示。

类型长度(字节)取值范围默认值
byte1-128 至 1270
short2-32768 至 327670
int4-2^31 至 2^31-1(约 - 21 亿至 21 亿)0
long8-2^63 至 2^63-1(约 ±9.2×10^18)0L

浮点数类型

用于存储带小数的数值,遵循 IEEE 754 标准。

类型长度(字节)精度默认值
float4单精度(约 6~7 位有效数字)0.0f
double8双精度(约 15~17 位有效数字)0.0d

字符类型

用于存储单个字符,采用 Unicode 编码(16 位无符号)。

类型长度(字节)取值范围默认值
char20 至 65535('\u0000' 至 '\uffff')'\u0000'

布尔类型

用于表示逻辑值(真 / 假)。

类型长度(字节)取值范围默认值
boolean1(规范未明确规定,实际取决于 JVM 实现)true 或 falsefalse
2、ArrayList存储原理以及长度和扩容规则 (语言类)

ArrayList基于动态数组实现的;长度是实际存储的元素个数,通过size()方法获取;初始默认容量是10(jdk8+);当数组长度大于容量时触发扩容,扩容为原来的1.5倍。

3、HashMap存储原理以及扩容规则 (语言类)

HashMap基于哈希表(数组 + 链表 / 红黑树)实现,JDK 8+ 引入红黑树优化链表过长问题(当链表长度超过 8 且数组长度超过 64 时,链表转换为红黑树(时间复杂度从 O(n) 优化到 O(log n)));HashMap初始默认容量为16,负载因子为0.75,阈值=初始默认容量*负载因子,当元素数量超过阈值时触发扩容,扩容为原来的两倍。

4、SpringBoot常见的注解 (框架类)
核心注解
@SpringBootApplication
作用:标记主类,等价于 @Configuration + @EnableAutoConfiguration + @ComponentScan@RestController
作用:标记控制器,等价于 @Controller + @ResponseBody,返回 JSON/XML 格式数据@Autowired
作用:自动注入依赖(基于类型)
请求映射注解
@RequestMapping:通用请求映射
@GetMapping:处理 GET 请求(等价于 @RequestMapping(method = RequestMethod.GET))
@PostMapping:处理 POST 请求
@PutMapping:处理 PUT 请求
@DeleteMapping:处理 DELETE 请求
组件扫描注解
@Component:通用组件标记
@Service:标记业务层组件
@Repository:标记数据访问层组件(自动处理数据访问异常)
@Controller:标记控制器组件
配置注解
@Configuration:标记配置类,等价于 XML 配置文件
@Bean:声明 Bean,相当于 XML 中的 <bean> 标签
@PropertySource:加载外部配置文件(如 .properties)
@Value:注入配置值(如 @Value("${app.name}"))
条件注解
@ConditionalOnClass:当类路径下存在指定类时生效
@ConditionalOnMissingBean:当容器中不存在指定 Bean 时生效
@Profile:根据环境(如 dev、prod)激活配置
测试注解
@SpringBootTest:集成测试注解,启动完整 Spring 应用上下文
@WebMvcTest:仅测试 Web 层组件
@MockBean:模拟 Bean(如 Mock 服务层)
5、ArrayList,HashSet,HashMap是否线程安全,如何线程安全 (语言类)
  • ArrayList非线程安全。多个线程同时操作(如添加、删除元素)可能导致数据不一致或抛出 ConcurrentModificationException
  • HashSet非线程安全。基于 HashMap 实现,多线程操作会有线程安全问题。
  • HashMap非线程安全。多线程下可能出现死循环(JDK 7 及以前)或数据丢失。

线程安全的替代方法: 

1.使用同步包装类

List list = Collections.synchronizedList(new ArrayList<>());
Set set = Collections.synchronizedSet(new HashSet<>());
Map map = Collections.synchronizedMap(new HashMap<>());
  • 原理:通过synchronized关键字对所有方法加锁,保证线程安全。
  • 缺点:性能较低,所有操作串行执行。

 2.使用并发集合类

import java.util.concurrent.*;List list = new CopyOnWriteArrayList<>();
Set set = new CopyOnWriteArraySet<>(); // 基于CopyOnWriteArrayList
Map map = new ConcurrentHashMap<>();
  • CopyOnWriteArrayList/Set
    • 读写分离,写操作(如add)时复制数组,读操作无需加锁。
    • 适用于读多写少的场景,写操作多时性能较差。
  • ConcurrentHashMap
    • JDK 7:分段锁(Segment),不同段可并行读写。
    • JDK 8:CAS + synchronized,锁粒度更小(锁槽位而非整个表)。
    • 推荐使用,性能优于synchronizedMap

总结

  • 线程安全:优先使用ConcurrentHashMapCopyOnWriteArrayList,避免synchronized包装类的性能损耗。
6、多线程的4种创建方式 (语言类)

1.继承thread类

public class MyThread extends Thread {@Overridepublic void run() {System.out.println("Thread running");}public static void main(String[] args) {MyThread thread = new MyThread();thread.start(); // 启动新线程}
}
  • 缺点:Java 单继承,继承Thread后无法继承其他类。

 2.实现Runnable接口

public class MyRunnable implements Runnable {@Overridepublic void run() {System.out.println("Runnable running");}public static void main(String[] args) {Thread thread = new Thread(new MyRunnable());thread.start();}
}
  • 优点:避免单继承限制,更灵活。

 3.实现Callable接口(带返回值)

import java.util.concurrent.*;public class MyCallable implements Callable<String> {@Overridepublic String call() throws Exception {return "Result from Callable";}public static void main(String[] args) throws ExecutionException, InterruptedException {ExecutorService executor = Executors.newSingleThreadExecutor();Future<String> future = executor.submit(new MyCallable());String result = future.get(); // 获取返回值(阻塞)System.out.println(result);executor.shutdown();}
}
  • 特点
    • call()方法可返回结果,通过Future获取。
    • 支持抛出异常。

 4. 使用线程池(推荐)

import java.util.concurrent.*;public class ThreadPoolExample {public static void main(String[] args) {// 创建固定大小的线程池ExecutorService executor = Executors.newFixedThreadPool(5);// 提交任务for (int i = 0; i < 10; i++) {final int taskId = i;executor.submit(() -> {System.out.println("Task " + taskId + " executed by " + Thread.currentThread().getName());});}// 关闭线程池executor.shutdown();}
}
  • 线程池优势

    • 复用线程,减少创建 / 销毁开销。
    • 控制最大并发数,避免资源耗尽。
    • 提供任务管理机制(如定时任务、拒绝策略)。

常见线程池工厂方法

Executors.newFixedThreadPool(5);      // 固定大小线程池
Executors.newCachedThreadPool();      // 缓存线程池(按需创建)
Executors.newSingleThreadExecutor();  // 单线程池
Executors.newScheduledThreadPool(5);  // 定时任务线程池

 手动创建线程池(推荐)

ThreadPoolExecutor executor = new ThreadPoolExecutor(2,                    // 核心线程数5,                    // 最大线程数60,                   // 空闲线程超时时间TimeUnit.SECONDS,new LinkedBlockingQueue<>(10),  // 任务队列Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy()  // 拒绝策略
);

 总结:多线程创建推荐使用线程池(如Executors或手动创建ThreadPoolExecutor),提升性能和可管理性。

7、JVM中的5大组成部分以及每一部分的作用 (语言类)

  1. 类加载器(ClassLoader)

    • 作用:加载 .class 文件到内存,生成对应的 Class 对象。

    • 流程:加载 → 验证 → 准备 → 解析 → 初始化。

    • 分类

      • 启动类加载器(Bootstrap ClassLoader):加载 JRE/lib 目录下的核心类(如 java.lang.*)。

      • 扩展类加载器(Extension ClassLoader):加载 JRE/lib/ext 目录下的扩展类。

      • 应用类加载器(Application ClassLoader):加载用户路径(classpath)下的类。

      • 自定义类加载器:继承 ClassLoader 实现特殊加载逻辑。

  2. 运行时数据区(Runtime Data Area)

    • 方法区(Method Area)
      存储类信息、常量、静态变量等,是所有线程共享的内存区域。
      JDK 8 后,方法区被元空间(Metaspace)取代,使用本地内存而非堆内存。

    • 堆(Heap)
      所有对象实例和数组分配的内存区域,垃圾回收的主要区域。
      分为新生代(Eden、Survivor)和老年代。

    • 虚拟机栈(VM Stack)
      每个线程私有的内存区域,存储局部变量表、操作数栈、动态链接等。
      每个方法执行时创建一个栈帧,方法结束后栈帧弹出。

    • 本地方法栈(Native Method Stack)
      与虚拟机栈类似,但为本地方法(如 native 修饰的方法)服务。

    • 程序计数器(Program Counter Register)
      记录当前线程执行的字节码行号,线程私有。

  3. 执行引擎(Execution Engine)

    • 解释器(Interpreter):逐条解释字节码为机器码执行。

    • 即时编译器(JIT Compiler):将热点代码(频繁执行的代码)编译为本地机器码,提升执行效率。

    • 垃圾回收器(Garbage Collector):回收不再使用的对象,释放内存。

  4. 本地方法接口(Native Interface)

    • 与本地方法库(如 C/C++ 库)交互的接口,通过 native 关键字调用。

  5. 本地方法库(Native Libraries)

    • 提供本地方法实现的库,如 java.lang.System 类中的 arraycopy() 方法。

8、常见的垃圾回收器有哪些? (语言类)

  1. 新生代回收器

    • Serial:单线程,STW(Stop The World),适合小型应用。
    • ParNew:Serial 的多线程版本,配合 CMS 使用。
    • Parallel Scavenge:多线程,关注吞吐量(运行用户代码时间 / 总时间)。
  2. 老年代回收器

    • Serial Old:单线程,适合客户端模式。
    • Parallel Old:Parallel Scavenge 的老年代版本,多线程。
    • CMS(Concurrent Mark Sweep)
      以获取最短回收停顿时间为目标,分初始标记、并发标记、重新标记、并发清除四个阶段。
      缺点:产生内存碎片,并发阶段占用 CPU 资源。
  3. 整堆回收器

    • G1(Garbage-First)
      分代收集,将堆划分为多个 Region,优先回收垃圾最多的区域。
      适合大内存、多 CPU 的服务器。
    • ZGC(Z Garbage Collector)
      超低延迟,支持 TB 级内存,使用染色指针和读屏障技术。
      JDK 11 引入,JDK 15+ 正式支持。
  4. 最新回收器

    • Shenandoah:与 G1 类似,但并发阶段更多,延迟更低。
    • Epsilon:实验性回收器,仅分配内存,不执行垃圾回收(用于性能测试)。
9、什么是双亲委派策略,有何作用 (语言类)

双亲委派机制:当类加载器需要加载类时,先委托给父类加载器尝试加载,直到启动类加载器。只有父类无法加载时,才由当前类加载器自己加载。

作用:

  1. 避免类重复加载:确保同一个类只被加载一次。
  2. 保证安全性:防止恶意替换核心类(如 java.lang.Object)。
    若用户自定义一个 java.lang.Object,通过双亲委派机制会优先加载 JDK 中的 Object,避免风险。
10、什么是新生代,老年代,永久存储区? (语言类)

JVM 内存分代模型

  1. 新生代(Young Generation)

    • 作用:存储新创建的对象。
    • 分区
      • Eden 区:对象初始分配的区域。
      • Survivor 区(S0、S1):Eden 区满时,存活的对象被复制到 Survivor 区。
    • Minor GC:新生代垃圾回收,频繁触发,速度快。
    • 对象晋升:多次 GC 后仍存活的对象会被移至老年代。
  2. 老年代(Old Generation)

    • 作用:存储长期存活的对象(如静态变量、单例对象)。
    • Major GC/Full GC:老年代垃圾回收,耗时较长,可能触发 STW。
  3. 永久代(Permanent Generation)与元空间(Metaspace)

    • 永久代(JDK 7 及以前)
      存储类元数据、常量池等,属于堆内存的一部分,大小通过 -XX:MaxPermSize 限制。
    • 元空间(JDK 8+)
      取代永久代,使用本地内存(Native Memory)存储类元数据,避免永久代 OOM。
      大小通过 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 控制。
11、ThreadLocal 以及底层实现原理 (语言类)

  • 作用:为每个使用该变量的线程都提供一个独立的变量副本,每个线程都可以独立地改变自己的副本,而不会影响其他线程。
  • 底层原理
    1. ThreadLocalMap:每个Thread对象内部都维护一个ThreadLocalMap,其键为ThreadLocal实例(弱引用),值为线程变量副本。
    2. 弱引用机制:若外部无强引用指向ThreadLocal,GC 时会回收键,但值仍可能存在(强引用),需手动调用remove()避免内存泄漏。
12、HashMap和Hashtable的区别 (语言类)

对比项HashMapHashtable
线程安全非线程安全线程安全(所有方法synchronized
null 支持允许一个null键和多个null不允许null键 / 值(抛 NPE)
初始容量1611
扩容机制2 倍2*oldCapacity+1
数据结构数组 + 链表 + 红黑树(JDK8+)数组 + 链表
迭代器Iterator(支持 fail-fast)Enumeration(不支持)
13、Spring 的 IOC 和 AOP (框架类)

  • IOC(控制反转)
    • 将对象的创建和依赖关系管理交给 Spring 容器,而非手动 new 对象。
    • 实现方式:依赖注入(DI,如构造器注入、Setter 注入)。
  • AOP(面向切面编程)
    • 将横切关注点(如日志、事务)与业务逻辑分离,通过动态代理增强代码。
    • 核心概念:切面(Aspect)、通知(Advice)、切入点(Pointcut)。
14、添加索引的规则,索引的数据结构(B+树)(数据库类)

  • 索引添加规则
    1. WHEREJOINORDER BY频繁出现的字段上建索引。
    2. 选择高区分度字段(如用户 ID,避免性别字段)。
    3. 避免冗余索引(如已有复合索引(a,b),无需单独为a建索引)。
  • B + 树结构
    • 所有数据存储在叶子节点,非叶子节点仅存索引键和指针。
    • 叶子节点通过指针相连,支持范围查询,高度平衡(通常 3-4 层)。
15、mysql 优化 (数据库类)

  1. 索引优化
    • 为高频查询字段添加复合索引。
    • 避免在索引字段上使用函数或表达式(如WHERE YEAR(create_time)=2023)。
  2. 查询优化
    • 避免SELECT *,仅查询需要的字段。
    • JOIN替代子查询,优化分页(如WHERE id >= (SELECT id FROM t LIMIT 100000,1))。
  3. 配置优化
    • 调整innodb_buffer_pool_size(建议物理内存的 50%-75%)。
    • 优化innodb_log_file_size(日志文件大小)。
16、explain 关键字 分析 慢查询 (数据库类)
  • 作用:分析 SQL 执行计划,查看索引使用、扫描行数、连接类型等。
  • 关键字段
    • type:访问类型(system>const>ref>range>index>allall表示全表扫描)。
    • rows:预估扫描行数,值越大性能越差。
    • Extra:额外信息(如Using filesortUsing temporary表示需优化)。
17、mybatis 的一级缓存和二级缓存 (框架类)
  • 一级缓存
    • 作用域SqlSession级别,默认开启。
    • 生命周期:会话结束时清除,同一会话内重复查询相同 SQL 会复用缓存。
  • 二级缓存
    • 作用域namespace级别(全局缓存),需手动配置。
    • 特点:多个SqlSession共享,可跨会话复用缓存。
18、mybatis 中的一对一,一对多,多对对如何处理 (框架类)
  • 一对一
    • 方式<association>标签,嵌套查询或结果映射。
    • 示例:用户(User)关联账户(Account)。
  • 一对多
    • 方式<collection>标签,嵌套结果或嵌套查询。
    • 示例:订单(Order)包含多个商品(Product)。
  • 多对多
    • 实现:通过中间表,使用<collection>+ 联合查询。
    • 示例:学生(Student)与课程(Course)通过选课表关联。
http://www.dtcms.com/a/265838.html

相关文章:

  • 专题:2025即时零售与各类人群消费行为洞察报告|附400+份报告PDF、原数据表汇总下载
  • 模拟IC设计提高系列6-Library导入与新建Library
  • 微信小程序41~50
  • 区块链(私有链搭建和实现)
  • 【C++】访问者模式
  • PHP语法基础篇(八):超全局变量
  • 鸿蒙应用开发:从网络获取数据
  • UE5中的AnimNotify
  • KDD 2025 | 地理定位中的群体智能:一个多智能体大型视觉语言模型协同框架
  • rabbitmq 与 Erlang 的版本对照表 win10 安装方法
  • SPLADE 在稀疏向量搜索中的原理与应用详解
  • MCP 传输机制(Streamable HTTP)
  • 多线程知识
  • 21、MQ常见问题梳理
  • 映射阿里云OSS(对象存储服务)
  • [创业之路-467]:企业经营层 - 《营销管理》的主要内容、核心思想以及对创业者的启示
  • 【Spring boot】tomcat Jetty Undertow对比,以及应用场景
  • Qt 事件
  • 医科+AI!和鲸支持南京医科大学医学数据挖掘课程实践教学落地
  • CCLinkIE转EtherCAT:食品产线测厚仪的“精准心跳”如何跳动?
  • 重学React(二):添加交互
  • 运维服务部中级服务工程师面试试题
  • 【Spring篇09】:制作自己的spring-boot-starter依赖1
  • 服务器如何配置防火墙规则开放/关闭端口?
  • ROS2---话题重映射
  • 能生成二维码的浏览器插件来了
  • 模型训练复习
  • RabbitMQ 高级特性之发送方确认
  • 12、jvm运行期优化
  • .Net Core 中RabbitMQ基本使用