禅与计算机 禅与计算机
首页
  • Java基础

    • 一文搞懂Java核心技术
    • Java面向对象知识点大总结,建议收藏
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
    • Java异常:从原理到实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
    • 探索JVM的隐秘角落:元空间详解
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 元认知

    • 摩擦感:AI时代的写作自省
    • 从断墨寻径浅谈程序员的元学习能力
    • AI时代专注力培养
    • 如何阅读一本书:技术书籍的读书笔记方法论
  • 开发工具

    • IDEA配置详解与高效使用指南
    • Windows环境下JDK安装与环境变量配置
    • Windows 10 下的 Maven 安装配置教程
    • Linux与macOS下Git安装及SSH配置教程
    • 打造高效mac终端:oh-my-zsh与插件配置
    • 详解AI时代下生产力最佳实践—Iterm2+zsh
    • 手把手用WSL在Windows上搭一个Linux开发环境(含MySQL实战)
    • 系统重装简记:从U盘启动盘到常用软件清单
    • AI时代,Windows开发者转Mac的快速上手指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
    • 重读 Redis SCAN 源码:那些当年没看懂的反向迭代细节
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • Elasticsearch核心原理与架构设计
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • AI时代的Go语言基础语法认知
    • AI时代视角下聊聊Go语言的编译过程
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发者的Go协程(goroutine)入门精讲
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
    • 基于 Claude Code 复刻 Redis 慢查询指令实践
    • mini-redis SCAN指令复刻:自底向上的工程方法论实践
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • AI时代不可替代的底层思维:位运算与逻辑运算实战
    • 对账核销场景设计与重构实践
    • 千万级交易流水慢查询综合治理实践
    • 记一次StarRocks源码级排错和既有架构优化实践
    • 基于快照合并修复Seata AT回滚补偿与Flink批攒导致StarRocks数据不一致最佳实践
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
    • 从一次线上事故到底层算法复刻与监控落地,我用MiniMax M3跑通了完整闭环
  • AI工具链

    • Claude Code 实战指南:从安装配置到企业级开发流程
    • 一次 Claude Code 启动失败的 AI 辅助排查复盘
    • 基于提示词工程与KITE框架的Redis签到功能开发实践
    • Claude Code 记忆管理:CLAUDE.md 最佳实践
    • Claude Code 规则管理:Rules 拆分编排与迭代实践(文末送书)
    • VSCode与Claude Code后端开发环境搭建与AI编程工作流实践
    • AI 写的企业级组件不敢用?我替你验过了
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

sharkchili

计算机禅修者
首页
  • Java基础

    • 一文搞懂Java核心技术
    • Java面向对象知识点大总结,建议收藏
    • 聊聊Java中的异常
    • 聊聊Java中的常用类String
    • 万字长文带你细聊Java注解本质
    • 来聊聊Java的反射机制
    • 深入解析Java泛型的魅力与机制
    • Java集合框架深度解析与面试指南
    • Java常用集合类HashMap深度解析
    • LinkedHashMap源码到面试题的全解析
    • 深入解析CopyOnWriteArrayList的工作机制
    • Java基础IO总结
    • Java三大IO模型小结
    • Java BIO NIO AIO详解
    • Java进阶NIO之IO多路复用详解
    • Java8流式编程入门
    • 一文速通lambda与函数式编程
    • Java8函数式方法引用最佳实践
    • Java异常:从原理到实践
  • Java并发编程

    • Java并发编程基础小结
    • 深入理解Java中的final关键字
    • 浅谈Java并发安全发布技术
    • 浅谈Java并发编程中断的哲学
    • Java线程池知识点小结
    • 浅谈Java线程池中拒绝策略与流控的艺术
    • synchronized关键字使用指南
    • 深入源码解析synchronized关键字
    • 详解JUC包下的锁
    • 详解并发编程中的CAS原子类
    • LongAdder源码分析
    • AQS源码解析
    • 深入剖析Java并发编程中的死锁问题
    • Java并发容器总结
    • 详解Java并发编程volatile关键字
    • 并发编程ThreadLocal必知必会
    • CompletableFuture基础实践小结
    • CompletableFuture异步多任务最佳实践
    • 硬核详解FutureTask设计与实现
    • 线程池大小设置的底层逻辑与场景化方案
    • 来聊一个有趣的限流器RateLimiter
  • JVM相关

    • 从零开始掌握 JVM
    • JVM核心知识点小结
    • JVM指令集概览:基础与应用
    • JVM类加载器深度解析
    • JVM方法区深度解析
    • Java内存模型JMM详解
    • Java对象大小的精确计算方法
    • 逃逸分析在Java中的应用与优化
    • 从零开始理解JVM的JIT编译机制
    • G1垃圾回收器:原理详解与调优指南
    • JVM故障排查实战指南
    • JVM内存问题排错最佳实践
    • JVM内存溢出排查指南
    • 简明的Arthas使用教程
    • 简明的Arthas配置及基础运维教程
    • 基于Arthas Idea的JVM故障排查与指令生成
    • 基于arthas量化监控诊断java应用方法论与实践
    • 深入剖析arthas技术原理
    • 探索JVM的隐秘角落:元空间详解
  • 深入理解Spring框架

    • Spring 核心知识点全面解析
    • Spring核心功能IOC详解
    • Spring AOP 深度剖析与实践
    • Spring 三级缓存机制深度解析
    • 深入 Spring 源码,剖析设计模式的落地实践
    • 探索 Spring 事务的奥秘
    • 深入解析Spring Bean的生命周期管理
    • 解读 Spring Boot 核心知识点
    • Spring Boot 启动优化实战:1分钟到13秒的排查与优化之路
    • Spring Boot自动装配原理及实践
    • 一文快速上手Sharding-JDBC
    • sharding-jdbc如何实现分页查询
    • 基于DynamicDataSource整合分库分表框架Shardingsphere
  • 计算机组成原理

    • 计算机硬件知识小结
    • CPU核心知识点小结
    • 浅谈CPU流水线的艺术
    • 从Java程序员视角聊聊CPU缓存
    • CPU任务调度和伪共享问题小结
    • CPU MESI缓存一致性协议
    • CPU内存管理机制
    • 内存深度解析
    • 磁盘存储原理
    • 详解计算机启动步骤
    • CPU南北桥架构与发展史
    • CPU中断机制与硬件交互详解
  • 操作系统

    • 如何实现一个高性能服务器
    • Linux文件结构与文件权限
    • Linux常见压缩指令小结
    • Linux核心系统调用详解
    • Linux进程管理
    • Linux线程管理
    • 进程与线程深度解析
    • Linux进程间通信机制
    • 零拷贝技术原理与实践
    • CPU缓存一致性问题深度解析
    • IO任务与CPU调度艺术
  • 计算机网络

    • 网卡通信原理详解
    • 网卡数据包处理指南
    • 基于抓包详解TCP协议
  • 编码最佳实践

    • 浅谈现代软件工程TDD最佳实践
    • 浅谈TDD模式下并发程序设计与实现
    • 面向AI编程新范式Trae后端开发环境搭建与实践
    • 基于Vibe Coding的Redis分页查询实现
    • 告别AI无效对话:资深工程师的提示词设计最佳实践
  • 实用技巧与配置

    • Mac常用快捷键与效率插件指南
    • Keynote技术科普短视频制作全攻略
  • 元认知

    • 摩擦感:AI时代的写作自省
    • 从断墨寻径浅谈程序员的元学习能力
    • AI时代专注力培养
    • 如何阅读一本书:技术书籍的读书笔记方法论
  • 开发工具

    • IDEA配置详解与高效使用指南
    • Windows环境下JDK安装与环境变量配置
    • Windows 10 下的 Maven 安装配置教程
    • Linux与macOS下Git安装及SSH配置教程
    • 打造高效mac终端:oh-my-zsh与插件配置
    • 详解AI时代下生产力最佳实践—Iterm2+zsh
    • 手把手用WSL在Windows上搭一个Linux开发环境(含MySQL实战)
    • 系统重装简记:从U盘启动盘到常用软件清单
    • AI时代,Windows开发者转Mac的快速上手指南
  • Nodejs
  • 博客搭建
  • Redis

    • Redis核心知识小结
    • 解锁Redis发布订阅模式
    • 掌握Redis事务
    • Redis主从复制技术
    • Redis的哨兵模式详解
    • 深度剖析Redisson分布式锁
    • 详解redis单线程设计思路
    • 来聊聊Redis所实现的Reactor模型
    • Redis RDB持久化源码深度解析
    • 来聊聊redis的AOF写入
    • 来聊聊Redis持久化AOF管道通信的设计
    • 来聊聊redis集群数据迁移
    • Redis SDS动态字符串深度解析
    • 高效索引的秘密:redis跳表设计与实现
    • 聊聊redis中的字典设计与实现
    • 重读 Redis SCAN 源码:那些当年没看懂的反向迭代细节
  • MySQL

    • MySQL基础知识点小结
    • 解读MySQL 索引基础
    • MySQL 索引进阶指南
    • 解读MySQL Explain关键字
    • 探秘 MySQL 锁:原理与实践
    • 详解MySQL重做日志redolog
    • 详解undoLog在MySQL MVCC中的运用
    • MySQL二进制日志binlog核心知识点
    • MySQL高效插入数据的最佳实践
    • MySQL分页查询优化指南
    • MySQL流式查询的奥秘与应用解析
    • 来聊聊分库分表
    • 来聊聊大厂常用的分布式ID生成方案
  • ElasticSearch

    • Elasticsearch核心原理与架构设计
    • ES 基础使用指南
    • ElasticSearch如何写入一篇文档
    • 深入剖析Elasticsearch文档读取原理
    • 聊聊ElasticSearch性能调优
    • Spring借助Easy-Es操作ES
  • Netty

    • 一文快速了解高性能网络通信框架Netty
    • Netty网络传输简记
    • 来聊聊Netty的ByteBuf
    • 来聊聊Netty消息发送的那些事
    • 解密Netty高性能之谜:NioEventLoop线程池阻塞分析
    • 详解Netty中的责任链Pipeline如何管理ChannelHandler
    • Netty Reactor模型常见知识点小结
    • Netty如何驾驭TCP流式传输?粘包拆包问题全解
    • Netty解码器源码解析
  • 消息队列

    • 一文快速入门消息队列
    • 消息队列RocketMQ入门指南
    • 基于RocketMQ实现分布式事务
    • RocketMQ容器化最佳实践
    • RocketMQ常见问题与深度解析
    • Kafka快速安装与使用指南
  • Nginx

    • Linux下的nginx安装
    • Nginx基础入门总结
    • Nginx核心指令小结
    • Nginx进程结构与核心模块初探
    • Nginx应用进阶HTTP核心模块配置
    • Nginx缓存及HTTPS配置小记
    • nginx高可用实践简记
    • Nginx性能优化
  • 微服务基础

    • 微服务基础知识小结
    • 分布式事务核心概念小结
    • OpenFeign核心知识小结
    • 微服务组件Gateway核心使用小结
    • 分布式事务Seata实践
    • 用 Docker Compose 完成 Seata 的整合部署
  • Nacos

    • Nacos服务注册原理全解析
    • Nacos服务订阅流程全解析
    • Nacos服务变更推送流程全解析
    • 深入解析SpringCloud负载均衡器Loadbalancer
    • Nacos源码环境搭建与调试指南
  • Seata

    • 深度剖析Seata源码
  • Docker部署

    • 一文快速掌握docker的理念和基本使用
    • 使用docker编排容器
    • 基于docker-compose部署微服务基本环境
    • 基于docker容器化部署微服务
    • Gateway全局异常处理及请求响应监控
    • Docker图形化界面工具Portainer最佳实践
  • Go基础

    • AI时代的Go语言基础语法认知
    • AI时代视角下聊聊Go语言的编译过程
    • 一文快速掌握Go语言切片
    • 来聊聊go语言的hashMap
    • 一文速通go语言类型系统
    • 浅谈Go语言中的面向对象
    • go语言是如何实现协程的
    • 聊聊go语言中的GMP模型
    • 极简的go语言channel入门
    • 聊聊go语言基于epoll的网络并发实现
    • 写给Java开发者的Go协程(goroutine)入门精讲
  • mini-redis实战

    • 来聊聊我用go手写redis这件事
    • mini-redis如何解析处理客户端请求
    • 实现mini-redis字符串操作
    • 硬核复刻redis底层双向链表核心实现
    • 动手复刻redis之go语言下的字典的设计与落地
    • Go 语言下的 Redis 跳表设计与实现
    • Go 语言版 Redis 有序集合指令复刻探索
    • 基于 Claude Code 复刻 Redis 慢查询指令实践
    • mini-redis SCAN指令复刻:自底向上的工程方法论实践
  • 项目编排

    • Spring脚手架创建简记
    • Spring脚手架集成分页插件
    • Spring脚手架集成校验框架
    • maven父子模块两种搭建方式简记
    • SpringBoot+Vue3前后端快速整合入门
    • 来聊聊Java项目分层规范
  • 场景设计

    • Java实现文件分片上传
    • 基于时间缓存优化浏览器轮询阻塞问题
    • 基于EasyExcel实现高效导出
    • 10亿数据高效插入MySQL最佳方案
    • AI时代不可替代的底层思维:位运算与逻辑运算实战
    • 对账核销场景设计与重构实践
    • 千万级交易流水慢查询综合治理实践
    • 记一次StarRocks源码级排错和既有架构优化实践
    • 基于快照合并修复Seata AT回滚补偿与Flink批攒导致StarRocks数据不一致最佳实践
  • CI/CD

    • 基于NETAPP实现内网穿透
    • 基于Gitee实现Jenkins自动化部署SpringBoot项目
    • Jenkins离线安装部署教程简记
    • 基于Nexus搭建Maven私服基础入门
    • 基于内网的Jenkins整合gitlab综合方案简记
  • 监控方法论

    • SpringBoot集成Prometheus与Grafana监控
    • Java监控度量Micrometer全解析
    • 从 micrometer计量器角度快速上手promQL
    • 硬核安利一个监控告警开源项目Nightingale
  • Spring AI

    • Spring AI Alibaba深度实战:一文掌握智能体开发全流程
    • Spring AI Alibaba实战:JVM监控诊断Arthas Agent的工程化构建与最佳实践
  • 大模型评测

    • M2.7 真能打!我用两个真实场景测了测,结果有点意外
    • Qoder JetBrains插件评测:祖传代码重构与接口优化实战
    • 从一次线上事故到底层算法复刻与监控落地,我用MiniMax M3跑通了完整闭环
  • AI工具链

    • Claude Code 实战指南:从安装配置到企业级开发流程
    • 一次 Claude Code 启动失败的 AI 辅助排查复盘
    • 基于提示词工程与KITE框架的Redis签到功能开发实践
    • Claude Code 记忆管理:CLAUDE.md 最佳实践
    • Claude Code 规则管理:Rules 拆分编排与迭代实践(文末送书)
    • VSCode与Claude Code后端开发环境搭建与AI编程工作流实践
    • AI 写的企业级组件不敢用?我替你验过了
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • Go基础

  • mini-redis实战

  • Go面试题

    • Go语言常见面试题解析(上)语言基础与核心概念
    • go面向对象与集合
      • 写在文章开头
      • 详解面向对象相关面试题
        • 非接口的任意类型 T() 都能够调用 *T 的方法吗?反过来呢?
        • 如何知道一个对象是分配在栈上还是堆上?
        • new和make的区别?有哪些需要注意的
        • 走查一段AI写的代码:它有什么问题?
        • 请你讲一下Go面向对象是如何实现的?
        • go语言继承有哪些特点
        • go的interface怎么实现的?
        • go的reflect 底层实现
        • go里用过哪些设计模式 ?
      • 详解集合面试题
        • go slice是怎么扩容的?
        • 空 struct{} 的用途
        • 无缓冲的 channel 和有缓冲的 channel 的区别
        • map的底层实现
        • select的实现原理?
      • 小结
      • 参考
    • G语言并发编程与GC
  • Go语言
  • Go面试题
sharkchili
2026-06-17
目录

go面向对象与集合

# 写在文章开头

# 详解面向对象相关面试题

# 非接口的任意类型 T() 都能够调用 *T 的方法吗?反过来呢?

这道题真正想分辨的,是你有没有把方法集(method set)和方法调用拎清楚。很多人能背"指针能调值方法、值也能调指针方法",可一问"为什么值赋给接口会编译失败"就卡住——因为他把"能调用"当成了"在方法集里"。

先摆例子,Counter有指针接收者Inc和值接收者Get:

type Counter struct{ n int }
func (c *Counter) Inc()    { c.n++ }       // 指针接收者
func (c Counter) Get() int { return c.n }  // 值接收者
type Incrementable interface{ Inc() }
1
2
3
4

四个场景,两个能编译、两个不能:

c := Counter{}
c.Inc()                  // ① 编译过,n 变成 1
m := map[string]Counter{"a": {}}
m["a"].Inc()             // ② 编译失败:m["a"] 不可寻址
var i Incrementable = c  // ③ 编译失败:Counter 没实现 Incrementable
var i Incrementable = &c // ④ 编译过
1
2
3
4
5
6

c是值不是指针,①却能调Inc,是因为c可寻址,编译器把c.Inc()自动改写成(&c).Inc()。②的m["a"]是map元素、不可寻址,取不到地址,编译器补不出这步就报错。一句话:指针方法能被自动调用,前提是接收者可寻址。

但①能调Inc、③把值赋给接口却失败,反差就在这。解释它得引入方法集规则:

  • Counter(值)的方法集 = {Get},只含值接收者方法
  • *Counter(指针)的方法集 = {Get, Inc},含值 + 指针接收者方法

接口满不满足,看的是类型的方法集有没有这个方法。Counter方法集没有Inc,所以不满足Incrementable,只有*Counter满足。

到这就能点破整道题:"能调用"和"在方法集里"是两回事。 ①能调用,靠的是"可寻址 + 编译器自动取址"——这只是设计者为降低开发者使用成本给的一层便利优化(语法糖),它不会把Inc真的加进Counter的方法集;③看的是类型的方法集,跟"这个变量能不能点出Inc"无关。

别被"值也能调指针方法"这个表象迷惑。 它是优化出来的便利,不是值真的拥有了这个方法。只有把值和指针调用方法的底层机制——可寻址、自动取址、方法集归属——理解透,这道题才算真懂,而不是背结论。

至于语言为何这么设计:值存进接口是一份拷贝,拷贝不可寻址,没法取址去调指针方法,所以干脆在方法集这层就把指针方法挡在值门外,避免运行时死局。

落到AI时代,让AI实现某接口的类型,它常把方法写成指针接收者、又在别处用值赋值,编译器报错很隐晦。笔者会收一条rule约束它——给接口赋值或传参,实现类型是指针接收者就一律传&x。懂了机制,才知道这条rule为什么成立。

# 如何知道一个对象是分配在栈上还是堆上?

Go不像C那样由开发者手动决定变量在栈还是堆,而是在编译期由**逃逸分析(escape analysis)**自动判定。判定标准只有一条:看对象在函数返回之后,是否还被外部的函数、接口或引用持有。被持有就逃到堆上,编译器能证明出了函数没人再碰它,就留在栈上。

func newInt() *int {
	x := 1
	return &x
}

func sum() int {
	y := 2
	return y
}
1
2
3
4
5
6
7
8
9

newInt把局部变量x的地址返回出去,函数栈帧销毁后这个指针仍被调用方持有,x只能逃到堆上,sum返回的是y的一份值拷贝,出了函数没有任何引用指向y,它就留在栈上。

我们可以通过go build -gcflags=-m打印Go编译期的优化策略,来查看对象的分配情况:

./main.go:4:2: moved to heap: x
./main.go:9:9: does not escape
1
2

moved to heap说明对象逃逸到了堆,does not escape则说明对象留在栈上。

需要澄清几个常被误当成判定标准、实际只是"常见现象"的点:对象大小、用了new或make、是指针还是值,它们都不直接决定分配位置,真正决定去向的,始终是"引用是否逃出当前栈帧"这一条。

考官在考:你是不是把"逃逸"和"指针/new/make"画了等号。这些只是触发逃逸的常见现象,标准只有"生命周期是否逃出当前栈帧"一条。

# new和make的区别?有哪些需要注意的

new(T)申请一块T大小的内存并清零,返回指向它的*T指针,但不初始化T的内部结构。make只用于slice、map、channel三种类型,它分配内存的同时把内部结构也建好(slice的底层数组、map的哈希表、channel的环形队列),返回的是类型本身的值,拿到就能直接用。

p := new(int)        // p 是 *int,*p == 0
s := make([]int, 3)  // s 是 []int,不是 *[]int,len/cap 都是 3
1
2

一句话区分:new给你一个指向零值的指针,make给你一个初始化好、可直接用的值。注意make返回的slice/map/chan本身是引用类型,拷贝它们是浅拷贝、共享底层数据,但make返回的是这个值、不是指向它的指针。

# 走查一段AI写的代码:它有什么问题?

func buildIndex(words []string) *map[string]int {
	m := new(map[string]int)
	for i, w := range words {
		(*m)[w] = i
	}
	return m
}
1
2
3
4
5
6
7

这段代码编译能过,一旦words非空,运行就panic:

panic: assignment to entry in nil map
1

问题就在new(map[string]int)。new只分配了"装map的盒子"、返回一个*map[string]int指针,但盒子里的map还是nil,它没做初始化。往一个nil map里写key,运行时直接panic。m本身是合法非nil指针,所以这不是空指针,而是"写nil map"。

要修正,该用make真正建出map,顺带也没必要返回指针(map本就是引用类型):

func buildIndex(words []string) map[string]int {
	m := make(map[string]int, len(words))
	for i, w := range words {
		m[w] = i
	}
	return m
}
1
2
3
4
5
6
7

AI rule:让AI生成涉及map/slice/channel的代码,凡看到new(map...)、new([]...)一律改成make。需要"空容器后续填充"时,显式用make初始化,不要用new拿指针绕。

# 请你讲一下Go面向对象是如何实现的?

面向对象的三大特性是封装、多态、继承,Go三者都有,但实现方式和Java很不一样。

封装。 Go控制可见性靠的是标识符的首字母大小写,而不是访问修饰符:首字母大写表示导出(包外可见,相当于public),首字母小写表示不导出(仅本包可见,相当于package-private)。把字段首字母小写保持包内私有,再用首字母大写的方法对外暴露读写入口,就完成了封装。

针对封装,Go牺牲了命名上的灵活性,用首字母大小写这一条规约替代public/private关键字,以此降低编码复杂度和开发者的认知负担(不过有了AI辅助编码,这点心智上的优势如今已经弱化了不少)。

多态。 多态靠接口实现,这里要把两个时机拆开:编译期只做满足性校验,检查具体类型的方法集有没有覆盖接口要求的全部方法,覆盖不了直接编译报错,运行期才靠itab做动态分发。带方法的接口变量在底层是一个(itab, data)二元组,itab里缓存着"接口类型×具体类型"对应的方法地址表:

  接口变量 w (iface,两个机器字)
  ┌────────────────┬────────────────┐
  │   tab  ───────┐│   data  ──────┐│
  └────────────────┴────────────────┘
                  │                 │
                  │                 └──►  具体类型的实例(或指向它的指针)
                  ▼
        itab(接口类型 × 具体类型,运行期构建并缓存)
        ┌──────────────────────────────────────────┐
        │ inter:  *io.Writer        接口类型元信息    │
        │ _type:  *os.File          具体类型元信息    │
        ├──────────────────────────────────────────┤
        │ fun[0]: &(*os.File).Write 方法地址表        │
        │ fun[1]: &(*os.File).Close 按接口方法顺序排好 │
        └──────────────────────────────────────────┘
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

调用w.Write(p)时,先从w.tab拿到itab,再从itab.fun[0]取出Write的真实地址,把w.data作为接收者跳过去执行。这张方法地址表是运行期才填好的(首次用到该"接口×具体类型"组合时构建、之后缓存复用),所以"调哪个Write"运行期才定,这就是多态。

继承。 Go没有继承关键字,用的是结构体嵌入加方法提升来达到类似效果,本质是组合而非继承,详见下一题。

# go语言继承有哪些特点

Go通过结构体嵌入(embedding)来复用代码。把一个类型不带字段名直接写进另一个结构体,这个叫嵌入字段(匿名字段),编译器会把嵌入类型的方法和字段提升(method promotion)到外层,外层实例可以直接访问:

type Animal struct{ Name string }
func (a Animal) Speak() string { return a.Name + " makes a sound" }

type Dog struct {
	Animal // 嵌入,没有字段名
}

d := Dog{}
d.Speak() // 直接可调,本质是 d.Animal.Speak() 的语法糖
d.Name    // 直接可访问
1
2
3
4
5
6
7
8
9
10

注意区分嵌入和聚合:聚合是a Animal这种带名字的普通字段,得d.a.Speak()才调得到,嵌入才有方法提升。

方法提升不是真正的继承,关键差别在于它没有多态覆盖。看下面这段:

type Animal struct{ Name string }
func (a Animal) Speak() string    { return "Animal speak" }
func (a Animal) Describe() string { return "Describe -> " + a.Speak() }

type Dog struct {
	Animal
}
func (d Dog) Speak() string { return "Woof" } // Dog 重写 Speak

func main() {
	d := Dog{}
	fmt.Println(d.Speak())    // Woof
	fmt.Println(d.Describe()) // Describe -> Animal speak
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

d.Speak()确实调到了Dog重写的版本,输出Woof。但d.Describe()里那句a.Speak()调的仍然是Animal.Speak,输出Describe -> Animal speak,并没有分发到Dog的重写版。嵌入类型完全不知道外层Dog的存在。

换成Java,父类方法内部调用会动态分发到子类重写版:

class Animal {
    String speak() { return "Animal speak"; }
    String describe() { return "Describe -> " + speak(); } // 虚分发
}
class Dog extends Animal {
    @Override String speak() { return "Woof"; }
}

Animal a = new Dog();
a.describe(); // Describe -> Woof,describe 里的 speak() 分发到了 Dog.speak
1
2
3
4
5
6
7
8
9
10

同样的结构,Java输出Describe -> Woof,Go输出Describe -> Animal speak。这就是Go的组合和Java继承的分水岭:Go只做静态的方法提升,没有Java那种父类引用调到子类重写方法的虚分发。所以Go是组合(composition)加方法提升,不是继承,"组合优于继承"在Go里是语言层面定死的。

另外,如果嵌入了多个类型、它们有相同签名的方法,方法提升会冲突,这时必须显式指定是哪个嵌入类型的方法,比如d.Animal.Speak()。

考官在考:你能不能说清Go的嵌入和真正的继承差在哪。题眼是"没有多态覆盖",父类方法内部对被重写方法的调用,Go不会动态分发到子类。

# go的interface怎么实现的?

Go的接口在底层有两种结构,取决于接口带不带方法:

  • iface:带方法的接口,结构是{ tab *itab, data 指针 }。data指向实际的值,tab指向一张itab表。
  • eface:空接口interface{},结构是{ _type 指针, data 指针 }。没有方法表,_type直接记录具体类型,data指向值。

itab是iface的核心,里面存接口类型、具体类型、以及方法地址表(fun数组)。它的具体结构和动态分发的过程,见前面"请你讲一下Go面向对象是如何实现的"那题里的itab示意图,这里不再重复。两种接口头的区别只在于:带方法的接口多一层itab来存放方法地址表、支撑运行期的动态分发,空接口不需要方法表,直接记类型即可。两者都有data字段来指向真正的值。

考官在考:你能不能分清iface和eface,以及itab到底存什么。常见错误是把itab说成"存了值",其实值统一放在data指针里,itab只管类型信息和方法地址。

# go的reflect 底层实现

reflect不是运行期的魔法,它的全部能力都建立在interface的二元组上。前面讲eface时说过,空接口在底层是{_type, data}两个指针:_type记录具体类型的元信息,data指向真正的值。reflect做的事,就是在运行期把这个二元组拆出来给你读、给你写。

证据就在入口签名上,reflect.TypeOf和reflect.ValueOf的参数都是interface{}:

func TypeOf(i any) Type
func ValueOf(i any) Value
1
2

你写reflect.ValueOf(x)传一个int进去,x在进函数那一刻先被装箱成一个eface。reflect拿到的原材料就是这个eface:从_type它知道x是int,从data它读到值10。所以TypeOf返回的reflect.Type本质是对_type的包装,ValueOf返回的reflect.Value则同时握着类型和数据。

官方把reflect的规则总结成三大定律,前两条是一对往返:

  1. 接口值 → 反射对象:TypeOf/ValueOf把接口里的(类型,数据)取出来。
  2. 反射对象 → 接口值:Value.Interface()再装回interface{}。
  3. 要通过反射修改一个值,这个值必须是可设置的(settable)。

第三条最容易踩,也最能体现reflect的设计。看这段:

x := 10
v := reflect.ValueOf(x)
v.SetInt(20)   // panic: reflect: reflect.Value.SetInt using unaddressable value
1
2
3

很多人以为这会把x改成20,或者顶多静默失败,实际是直接panic。根因在第一步装箱:reflect.ValueOf(x)拿到的是x的一份拷贝,这份拷贝是reflect内部的临时值、不可寻址。就算让SetInt成功,改的也是这份副本,你的x根本不会变。Go不让你白改一场,干脆在这里panic拦住。

要真改到x,得把地址传进去:

x := 10
v := reflect.ValueOf(&x).Elem()
fmt.Println(v.CanSet())  // true
v.SetInt(30)
fmt.Println(x)           // 30
1
2
3
4
5

reflect.ValueOf(&x)拷贝的是指针,指针被拷贝也无所谓,它仍指着原始的x。.Elem()顺着指针走回去,拿到的是x那块原始内存,可寻址、可设置,这才改得动。判断一个reflect.Value能不能改,用CanSet(),它返回true的前提就是可寻址。

考官在考:你是不是把reflect当成黑魔法。它就是interface二元组在运行期的暴露,_type给类型、data给值;改值这一支的全部约束只有一条——必须可寻址,而可寻址取决于你递进去的是原始内存还是临时拷贝。

AI rule:让AI写用reflect改值或填充结构体的代码,凡是SetXxx、Field().Set,一律确认那个Value来自指针的Elem()(或其他可寻址来源),否则运行期必panic。

# go里用过哪些设计模式 ?

# 详解集合面试题

# go slice是怎么扩容的?

slice扩容发生在append放不下时,底层调runtime的growslice。整个过程分两层:先由nextslicecap算一个预估容量,再由roundupsize按内存档位对齐成最终容量。很多人只记得"翻倍/1.25倍",其实最终的cap是这两层共同决定的。

先看第一层,runtime/slice.go的nextslicecap:

const threshold = 256
if oldCap < threshold {
    return doublecap            // 256 之前:直接 2 倍
}
for {
    newcap += (newcap + 3*threshold) >> 2   // 256 之后:平滑过渡
    if uint(newcap) >= uint(newLen) { break }
}
1
2
3
4
5
6
7
8

阈值是256(1.18之前是1024,后来下调了)。容量没到256直接翻倍,到了256改用那行平滑公式。>>2就是除以4,3*threshold是768,把公式整理开:

新newcap = newcap + (newcap + 768) / 4
         = newcap + newcap/4 + 768/4
         = 1.25 × newcap + 192
1
2
3

这是一条仿射函数,斜率1.25、截距192。容量小时192占比大,把实际增长因子抬到接近2倍;容量越大192越可以忽略,因子就越趋近1.25。

第二层,growslice拿到预估newcap后,要按元素大小换算成字节数,再用roundupsize向上对齐到Go内存分配器的固定档位(size class):

capmem = roundupsize(uintptr(newcap)*goarch.PtrSize, noscan)
newcap = int(capmem / goarch.PtrSize)
1
2

分配器只按固定档位发内存,你要的字节数落在两档之间就向上取到最近一档,换算回来的cap往往比第一层算的更大。所以最终cap经常是不圆整的怪数。

我们可以用一段代码把两层的效果一起看出来,打印[]int每次扩容前后的cap:

s := make([]int, 0)
old := cap(s)
for i := 0; i < 1300; i++ {
    s = append(s, i)
    if cap(s) != old {
        fmt.Printf("len=%-5d cap %d -> %d\n", len(s), old, cap(s))
        old = cap(s)
    }
}
1
2
3
4
5
6
7
8
9

输出(go 1.23):

cap: 4 -> 8 -> 16 -> 32 -> 64 -> 128 -> 256 -> 512 -> 848 -> 1280 -> 1792
1

256之前是干净的2的幂,符合"翻倍";过了256就开始出现848、1280这类怪数。拿512那次对一下两层:第一层1.25×512+192=832,第二层832×8=6656字节对齐到6784字节,6784/8=848,正好是实测值。

注:int是8字节,走的是et.Size_ == goarch.PtrSize那个分支;开头0→4那一跳还混了分配器最小块的处理,和主线无关。

最后说一下1.18为什么把"硬切到1.25"改成这条平滑曲线。旧策略是cap<1024翻倍,否则×1.25,1024这个硬阈值有个断崖:cap=1023翻倍到约2046,cap=1024却只涨到1280,一个元素之差扩容结果差了快一倍,刚好跨阈值的slice行为很跳。平滑公式让增长因子随容量连续下降,抹掉了这个台阶。终点选1.25是时间空间的权衡:扩容因子越大,重分配和拷贝越少,但浪费的内存越多;大容量时浪费的绝对值可观,所以收敛到偏省内存的1.25。

考官在考:你是不是只会背"256之后1.25倍"。题眼有两个——一是1.18把硬切换改成了1.25×cap+192的平滑过渡(量级越大越趋近1.25),二是算出的newcap还要经roundupsize按内存档位对齐,最终cap常是怪数。

AI rule:让AI写"已知最终元素个数"的slice,一律make([]T, 0, n)一次给够cap,别让它从空slice循环append——那会触发多次扩容和拷贝。

# 空 struct{} 的用途

信号通知 set集合

# 无缓冲的 channel 和有缓冲的 channel 的区别

吴缓冲区必须消费后才能继续对的,容易造成死锁,有缓存区则空间未满允许继续读写,类似于java的阻塞队列,但其底层还是有更优秀的设计,例如若有消费者,且队列为空,则直接给消费者,避免投递,

# map的底层实现

和java· 数组+链表和红黑树不同,redis为了保证内存局部性,用到的bucket和高低位 字节数组,并通过渐进式驱逐的方式保证性能。

# select的实现原理?

底层是通过case实现的

# 小结

# 参考

https://zhuanlan.zhihu.com/p/471490292

https://github.com/lifei6671/interview-go

编辑 (opens new window)
上次更新: 2026/06/17, 09:31:54
Go语言常见面试题解析(上)语言基础与核心概念
G语言并发编程与GC

← Go语言常见面试题解析(上)语言基础与核心概念 G语言并发编程与GC→

最近更新
01
AI时代,Windows开发者转Mac的快速上手指南
06-17
02
G语言并发编程与GC
06-16
03
Go语言常见面试题解析(上)语言基础与核心概念
06-15
更多文章>
Theme by Vdoing | Copyright © 2025-2026 Evan Xu | MIT License | 桂ICP备2024034950号 | 桂公网安备45142202000030
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式
×
×