Java学习教程
快速学习Java
前言
Java 的核心优势:为什么企业偏爱它?
“一次编写,到处运行”的跨平台能力:这是 Java 最标志性的特点。Java 代码编译后生成的不是特定平台的机器码,而是中间态的字节码(.class 文件)。这个字节码运行在 Java 虚拟机 (JVM) 上,而 JVM 针对不同平台(Windows、Linux、macOS)有不同版本 。只要目标平台安装了 JVM,同一个字节码文件就能直接运行,彻底解决了 C/C++ 程序因操作系统或库依赖不同而需要重新编译的痛点 。
自动化的内存管理(垃圾回收 GC) :在 C/C++ 中,你需要手动 malloc/free 或 new/delete,稍有不慎就会内存泄漏。Java 则内置了垃圾回收器,它会自动监测并回收不再使用的对象内存 。这极大减少了内存泄漏和悬垂指针等令人头疼的问题,让你从繁琐的内存管理中解放出来,更专注于业务实现 。
庞大且成熟的生态系统:Java 拥有全球最大、最成熟的开发者社区之一。这意味着你几乎能找到解决任何问题的现成轮子 :
企业级框架:Spring 全家桶(Spring Boot, Spring Cloud, Spring MVC)是业界标准,极大简化了企业级应用和微服务的开发。
构建工具:Maven 和 Gradle 能帮你自动化地管理项目依赖、构建和打包,告别手动管理 .jar 包的混乱。
丰富的类库:从网络通信到数据处理,Java 标准库(Java SE API)本身已经非常强大,再加上 Apache Commons、Google Guava 等第三方库,几乎无所不能。
一、 C++ 与 Java 核心概念对比表
| 核心概念 | C++ | Java | 解读 |
|---|---|---|---|
| 程序入口 | int main(int argc, char* argv[]) { ... } | public static void main(String[] args) { ... } | Java 的 main 方法必须放在类中,public 表示全局可访问,static 表示属于类而非实例,void 表示无返回值。 |
| 编译运行 | 编译: g++ foo.cc -o outfile运行: ./outfile | 编译: javac Foo.java(生成 Foo.class)运行: java Foo | C++ 编译为可执行文件直接运行;Java 编译为字节码,由 JVM 解释/编译执行。 |
| 输出语句 | cout << "Hello" << endl; | System.out.println("Hello"); | Java 通过 System 类的 out 对象的 println 方法实现输出。 |
| 布尔类型 | bool | boolean | 关键字不同,但用法一致。 |
| 常量 | const int x = 5; | final int x = 5; | Java 使用 final 声明不可变常量。 |
| 对象创建 | 栈上: MyClass obj;堆上: MyClass* obj = new MyClass(); | MyClass obj = new MyClass(); | Java 对象始终在堆上分配,obj 为引用(类似指针,但无算术运算)。 |
| 成员访问 | 栈对象: obj.field指针: obj->field | obj.field | Java 统一使用 . 访问成员,更简洁。 |
| 继承 | class Sub : public Base { ... }; | class Sub extends Base { ... } | Java 使用 extends 明确继承关系。 |
| 接口 | 通过纯虚函数的抽象类实现 | interface MyInterface { ... }class MyClass implements MyInterface { ... } | Java 的 interface 定义方法签名,类通过 implements 实现接口,避免多继承的复杂性。 |
| 多态/虚函数 | 需用 virtual 声明多态函数 | 非 static 方法默认支持多态,final 修饰可禁止覆盖。 | Java 默认支持多态,简化设计。 |
| 内存管理 | 手动 new/delete | new 分配内存,无需手动释放,由垃圾回收器自动管理。 | Java 自动内存管理减少错误风险。 |
| 数组声明 | int x[10]; 或 int* x = new int[10]; | int[] x = new int[10]; | Java 语法更统一,x.length 直接获取长度。 |
| 引用赋值 | MyClass b = a;(对象数据拷贝) | MyClass b = a;(引用拷贝,指向同一对象) | Java 赋值传递引用而非对象副本。 |
| 相等性比较 | == 默认比较对象内容(需重载运算符) | == 比较引用地址,equals() 比较内容。 | Java 字符串等内容比较必须用 str1.equals(str2)。 |
二、环境安装
安装 JDK (建议 JDK 17 或 21 LTS ) 和一个好用的 IDE(如 IntelliJ IDEA 社区版)
三、 java构建工具
Maven 和 Gradle,它们是 Java 世界的“makefile”,用于管理项目依赖和构建生命周期
四、 了解 Spring
4.1、Spring和Spring boot的关系:
Spring Boot 是基于 Spring 框架构建的,它的出现是为了让你更轻松、更快速地去使用 Spring。它不是要替代 Spring,
Spring 是基础,是提供依赖注入、事务管理等核心能力的框架。它很强大,但配置起来相对繁琐。
Spring Boot 是进化,它站在Spring的肩膀上,通过"自动配置"和"起步依赖"等机制,把这些繁琐都隐藏了起来。
它俩的关系,就像你之前学习的接口和实现类的关系——Spring定义了强大的能力规范,而Spring Boot提供了一个开箱即用、极其便捷的默认实现,让你能更快地投入到业务开发中
4.2、Spring 常用注解
4.2.1、注解与作用对照表
| 注解 | 作用 |
|---|---|
| @SpringBootApplication | 主启动类注解,包含自动配置、组件扫描等功能 |
| @RestController | REST 控制器,返回数据而非视图 |
| @RequestMapping | 映射 HTTP 请求路径 |
| @GetMapping/@PostMapping | 分别映射 GET/POST 请求 |
| @Autowired | 自动注入依赖 |
| @Service/@Repository | 标记业务层/数据访问层组件 |
| @ConfigurationProperties | 绑定配置文件属性 |
使用示例(部分注解)
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@RestController
@RequestMapping("/api")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public List<User> getUsers() {
return userService.findAll();
}
}
4.2.2、请求映射注解:定义路径和 HTTP 方法
这些注解对应 HTTP 的几种基本操作(CRUD):
| 注解 | HTTP 方法 | 用途 | 类似数据库操作 |
|---|---|---|---|
@GetMapping | GET | 获取资源 | SELECT |
@PostMapping | POST | 创建资源 | INSERT |
@PutMapping | PUT | 更新全部资源 | UPDATE |
@PatchMapping | PATCH | 更新部分资源 | UPDATE(部分字段) |
@DeleteMapping | DELETE | 删除资源 | DELETE |
@RequestMapping | 通用 | 可以指定多种方法 | - |
这里只是声明,在@DeleteMapping不一定要删除,也可以进行其它操作
示例代码
@RestController
@RequestMapping("/api/users") // 类级别:所有方法的公共前缀
public class UserController {
// GET /api/users
@GetMapping
public List<User> listUsers() {
return userService.findAll();
}
// GET /api/users/123
@GetMapping("/{id}") // 路径变量
public User getUser(@PathVariable Long id) {
return userService.findById(id);
}
// POST /api/users
@PostMapping
public User createUser(@RequestBody User user) {
return userService.save(user);
}
// PUT /api/users/123
@PutMapping("/{id}")
public User updateUser(@PathVariable Long id, @RequestBody User user) {
user.setId(id);
return userService.update(user);
}
// DELETE /api/users/123
@DeleteMapping("/{id}")
public void deleteUser(@PathVariable Long id) {
userService.delete(id);
}
}
4.2.3、参数绑定注解:从请求中取数据
注解与数据来源对应表
| 注解 | 数据来源 | 适用场景 |
|---|---|---|
@PathVariable | URL 路径中的变量 | RESTful 风格的资源 ID |
@RequestParam | 查询参数(?key=value) | 过滤条件、分页参数 |
@RequestBody | 请求体(JSON/XML) | 提交的复杂数据对象 |
@RequestHeader | HTTP 请求头 | 认证令牌、浏览器信息等 |
@CookieValue | Cookie 数据 | 会话标识、用户偏好设置 |
@ModelAttribute | 表单数据(Form 提交) | 传统 MVC 表单处理 |
关键说明
@PathVariable:适用于动态 URL,如/users/{id}。@RequestParam:常用于 GET 请求,参数显式出现在 URL 中。@RequestBody:需配合Content-Type: application/json使用,反序列化为对象。@ModelAttribute:用于绑定表单字段到对象属性,支持多部分表单(如文件上传)。
示例代码
@RestController
@RequestMapping("/api")
public class DemoController {
// URL: /api/users/123?page=1&size=10
@GetMapping("/users/{userId}")
public String demo(
@PathVariable Long userId, // 从路径取: 123
@RequestParam int page, // 从查询参数取: 1
@RequestParam(defaultValue = "20") int size, // 带默认值
@RequestHeader("User-Agent") String ua, // 从请求头取浏览器信息
@CookieValue(value = "sessionId", required = false) String sessionId
) {
return "User: " + userId + ", Page: " + page;
}
// POST /api/users with JSON body: {"name":"Alice","age":25}
@PostMapping("/users")
public User create(@RequestBody User user) { // 自动解析 JSON 到 User 对象
return userService.save(user);
}
}
4.2.4、 响应处理注解
| 注解 | 作用 |
|---|---|
| @ResponseBody | 方法返回值直接写入 HTTP 响应体(不经过视图解析器) |
| @ResponseStatus | 指定 HTTP 响应状态码 |
使用说明
-
@ResponseBody
通常用于 RESTful API 开发,将方法返回的对象(如 JSON 或 XML)直接写入响应体,跳过视图渲染。 -
@ResponseStatus
可标注在方法或异常类上,强制返回指定的 HTTP 状态码(如@ResponseStatus(HttpStatus.NOT_FOUND))。
示例代码
@RestController
public class ResponseController {
@GetMapping("/success")
@ResponseStatus(HttpStatus.OK) // 返回 200
public String success() {
return "OK";
}
@PostMapping("/create")
@ResponseStatus(HttpStatus.CREATED) // 返回 201 Created
public User create() {
return new User("Bob");
}
// 异常处理方法
@ExceptionHandler(UserNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND) // 返回 404
public ErrorResponse handleNotFound() {
return new ErrorResponse("用户不存在");
}
}
4.2.5、依赖注入注解:管理对象
以下是整理后的表格形式:
| 注解 | 作用 | 说明 |
|---|---|---|
@Autowired | 自动注入依赖 | Spring 最常用的注入方式 |
@Resource | Java 标准的注入 | 按名称注入 |
@Inject | Java 标准的注入 | 按类型注入 |
@Qualifier | 指定注入哪个实现 | 当有多个同类型 Bean 时使用 |
示例代码
@RestController
public class UserController {
// 字段注入
@Autowired
private UserService userService;
// 构造器注入(推荐)
private final OrderService orderService;
public UserController(OrderService orderService) {
this.orderService = orderService; // Spring 自动调用
}
// Setter 注入
@Autowired
public void setMailService(MailService mailService) {
this.mailService = mailService;
}
}
@Service // 标记这是一个 Service 组件
public class UserService {
// 业务逻辑
}
@Repository // 标记这是一个数据访问组件
public interface UserRepository extends JpaRepository<User, Long> {
// 数据库操作
}
4.2.6、自定义注解
自定义注解可以可以被读取和处理(传参功能)
// 1. 先定义注解(就像定义标签模板)
public @interface Cacheable {
String key() default "";
int ttl() default 3600; // 过期时间
}
// 2. 在代码上贴标签
@Service
public class UserService {
@Cacheable(key = "user.list", ttl = 1800) // 贴个标签:这个方法要缓存30分钟
public List<User> getAllUsers() {
// 查询数据库...
}
@Cacheable(key = "user.", ttl = 600) // 贴标签:缓存10分钟
public User getUserById(Long id) {
// 查询数据库...
}
}
// 3. 写代码读取标签(这才是关键!)
@Aspect
@Component
public class CacheAspect {
// 拦截所有贴了 @Cacheable 的方法
@Around("@annotation(cacheable)")
public Object handleCache(ProceedingJoinPoint joinPoint,
Cacheable cacheable) {
// 读取注解里的值
String key = cacheable.key(); // 拿到 "user.list"
int ttl = cacheable.ttl(); // 拿到 1800
// 根据注解的值做不同的处理
Object result = cache.get(key);
if (result == null) {
result = joinPoint.proceed(); // 执行原方法
cache.put(key, result, ttl); // 按ttl存缓存
}
return result;
}
}
示例2:多注解组合
// 定义多个注解
public @interface Cache {
String key();
int ttl() default 3600;
}
public @interface RateLimit {
int value(); // 每秒允许次数
String key() default "default";
}
// 在一个类中使用多个注解
@Service
public class ProductService {
@Cache(key = "product.list", ttl = 1800)
@RateLimit(10) // 每秒10次
public List<Product> getAllProducts() {
return productRepository.findAll();
}
@Cache(key = "product.", ttl = 600)
@RateLimit(value = 5, key = "product.detail")
public Product getProduct(Long id) {
return productRepository.findById(id);
}
}
// 处理器可以同时处理多个注解
@Aspect
@Component
public class ServiceAspect {
@Around("@annotation(cache) && @annotation(rateLimit)")
public Object handleService(ProceedingJoinPoint pjp,
Cache cache,
RateLimit rateLimit) {
// 从 @Cache 取值
String cacheKey = cache.key();
int ttl = cache.ttl();
// 从 @RateLimit 取值
int limit = rateLimit.value();
String limitKey = rateLimit.key();
// 组合使用这些值
// 1. 检查限流
if (!rateLimiter.tryAcquire(limitKey, limit)) {
throw new RuntimeException("太频繁了");
}
// 2. 尝试从缓存获取
Object result = cacheManager.get(cacheKey);
if (result == null) {
result = pjp.proceed();
cacheManager.put(cacheKey, result, ttl);
}
return result;
}
}
自定义注解就是一个传参工具,只不过:
参数不是传给方法,而是贴在代码上
读取不是即时获取,而是通过反射后续读取
用途不是业务逻辑,而是告诉框架/工具怎么处理这段代码
4.2.6、组件标记注解
| 注解 | 分层 | 含义 |
|---|---|---|
@Component | 通用 | 最基础的组件,标记为 Spring 管理的 Bean |
@Service | 业务层 | 标记业务逻辑类(语义上更明确) |
@Repository | 数据层 | 标记数据访问类(Spring 会自动转换数据库异常) |
@Controller | 控制层 | 标记控制器 |
完整实战示例(博客系统)
// 1. 实体类
public class Article {
private Long id;
private String title;
private String content;
private LocalDateTime createTime;
// getter/setter 省略
}
// 2. 业务层
@Service
@Transactional
public class ArticleService {
@Autowired
private ArticleRepository articleRepository;
public Article findById(Long id) {
return articleRepository.findById(id)
.orElseThrow(() -> new ArticleNotFoundException(id));
}
public Article save(Article article) {
article.setCreateTime(LocalDateTime.now());
return articleRepository.save(article);
}
}
// 3. 控制器层
@RestController
@RequestMapping("/api/articles")
@CrossOrigin(origins = "http://localhost:3000") // 允许跨域请求
public class ArticleController {
@Autowired
private ArticleService articleService;
@GetMapping
public List<Article> list(
@RequestParam(required = false) String keyword,
@RequestParam(defaultValue = "1") int page,
@RequestParam(defaultValue = "10") int size
) {
// 根据关键词搜索文章
return articleService.search(keyword, page, size);
}
@GetMapping("/{id}")
public Article getOne(@PathVariable Long id) {
return articleService.findById(id);
}
@PostMapping
@ResponseStatus(HttpStatus.CREATED)
public Article create(@Valid @RequestBody Article article) {
return articleService.save(article);
}
@PutMapping("/{id}")
public Article update(
@PathVariable Long id,
@Valid @RequestBody Article article
) {
article.setId(id);
return articleService.save(article);
}
@DeleteMapping("/{id}")
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(@PathVariable Long id) {
articleService.delete(id);
}
// 异常处理
@ExceptionHandler(ArticleNotFoundException.class)
@ResponseStatus(HttpStatus.NOT_FOUND)
public ErrorResponse handleNotFound(ArticleNotFoundException ex) {
return new ErrorResponse(ex.getMessage());
}
}
总计
注解与角色对照表
| 注解 | 一句话解释 | 经典比喻 |
|---|---|---|
@Controller | 负责接客,处理HTTP请求 | 饭店门口的迎宾员 |
@Service | 负责算账,处理业务逻辑 | 饭店里炒菜的厨师 |
@Repository | 负责搬货,操作数据库 | 仓库的搬运工 |
@Component | 啥活都干,通用工具类 | 饭店的水电工 |
说明
@Controller:处理用户请求并返回响应,通常与视图层交互。@Service:封装业务逻辑,协调多个数据操作或复杂计算。@Repository:直接与数据库交互,提供数据增删改查功能。@Component:通用组件,用于非特定层但需被Spring管理的类。
注解设计哲学
声明式编程:你只需要声明"是什么",框架负责"怎么做"
约定优于配置:遵循命名规范,减少配置
关注点分离:不同注解处理不同维度的关注点
为什么分这么细?
1. 各司其职,分工明确
前台(Controller)只负责接待,不负责算账
业务部(Service)只负责算账,不负责去仓库搬货
仓库(Repository)只负责搬货,不负责接待
2. 容易找人(维护方便)
页面报错 → 找 Controller
业务逻辑错了 → 找 Service
数据存错了 → 找 Repository
通用功能坏了 → 找 Component
3. 换人不换岗(解耦)
// 今天用MySQL数据库
@Repository
public class UserRepository {
// 操作MySQL
}
// 明天换MongoDB,只换仓库管理员,业务部不用改
@Repository
public class UserRepository {
// 操作MongoDB,对外提供同样的方法
}
更多推荐



所有评论(0)