Java知识点 #2
回顾 #1
前端三大件
html
css
前两个用的时候花5分钟过一遍就行
js
查菜鸟教程api 注意与Java语法点不同的地方就行 15min回顾就行
前端技术掌握建议
在Java后端开发中,**HTML、CSS、JS的使用频率和深度取决于具体的开发模式和项目需求**。以下是详细分析及替代框架的介绍:
### 一、Java后端开发中HTML/CSS/JS的使用场景
#### 1. **传统全栈开发(MVC模式)**
- **使用较多**:
- 典型场景:早期的Java Web项目(如Spring MVC、Struts2)中,后端直接渲染页面(JSP、Thymeleaf等模板引擎),需手动编写HTML/CSS/JS实现前端逻辑。
- 示例:后端控制器返回HTML页面,页面中嵌入JS实现表单验证、动态交互等。
- **特点**:前后端耦合度高,前端逻辑简单,适合中小型项目或快速原型开发。
#### 2. **前后端分离模式(主流趋势)**
- **使用较少**:
- 后端仅提供API接口(JSON数据),前端逻辑完全由独立的前端项目实现(如Vue、React)。
- 后端开发者只需关注接口设计、业务逻辑和数据处理,无需深入HTML/CSS/JS细节。
- **特点**:分工明确,后端专注性能、安全和业务逻辑,前端体验由专业前端团队优化。
### 二、Java后端开发者需要掌握的前端知识
即使采用前后端分离,Java后端仍需了解以下基础:
1. **HTML/CSS/JS基础**:
- 理解前端渲染原理(如浏览器如何解析HTML、CSS盒模型),方便调试接口返回的数据结构。
- 示例:通过JS发送Ajax请求调用后端API,需了解`fetch`或`XMLHttpRequest`的基本用法。
2. **前端构建工具**:
- 了解NPM/Yarn、Webpack/Vite的作用,便于与前端团队协作(如调试跨域问题、联调接口)。
3. **基础框架**:
- 简单掌握Vue/React的组件化思想(非深入开发),便于理解前端如何消费后端接口。
### 三、替代前端框架和工具(前后端分离场景)
若Java后端无需直接编写前端代码,可依赖以下工具或框架简化前端开发:
#### 1. **前端框架(由前端团队使用)**
- **Vue.js**:轻量级框架,适合构建单页应用(SPA),生态丰富(如Vue Router、Vuex)。
- **React**:高效的组件化框架,适合复杂交互场景(如电商、仪表盘),需搭配React Router、Redux等工具。
- **Angular**:TypeScript编写的重量级框架,适合企业级大型项目(需学习DI、RxJS等概念)。
#### 2. **低代码/无代码平台(快速搭建前端)**
- **优势**:无需手写HTML/CSS/JS,通过可视化界面拖拽组件生成前端页面,对接Java后端API。
- **示例**:
- **国内平台**:阿里云宜搭、腾讯云微搭、钉钉简道云。
- **国际平台**:OutSystems、Mendix。
#### 3. **后端渲染增强工具(传统模式优化)**
- **Thymeleaf**:Java后端模板引擎,支持HTML内嵌入表达式(如`${user.name}`),简化动态内容渲染。
- **Freemarker**:老牌模板引擎,常用于生成报告、邮件内容等静态页面。
#### 4. **UI组件库(减少CSS编写)**
- **Bootstrap**:基于CSS/JS的响应式组件库,提供按钮、导航栏、表单等预制样式,可直接在HTML中引用。
- **Element UI**(Vue生态)/ **Ant Design**(React生态):封装完善的组件库,支持快速搭建页面。
### 四、总结:Java后端是否需要深入HTML/CSS/JS?
- **传统全栈项目**:需掌握基础语法,能编写简单页面和交互逻辑。
- **前后端分离项目**:只需了解基础原理,重点关注API设计和接口联调,前端开发交给专业团队或低代码平台。
- **趋势建议**:
- 若团队规模小,需兼顾简单前端需求,可学习Vue/React基础;
- 若专注后端技术,优先深入Java生态(如Spring Boot、微服务、分布式架构),前端依赖成熟框架或工具即可。
尚硅谷Java 基础module18 19 20 (一遍遍看 熟记 会用)
模块18回顾:
1.Collection集合:单列集合的顶级接口
a.add addAll clear size isEmpty remove toArray contains
2.迭代器:Iterator
a.获取:iterator方法
b.方法:
hasNext()
next()
c.并发修改异常:在迭代集合的时候,不能随意修改集合长度
原因:调用add,只给实际操作次数+1.后面调用next的时候,没有给预期操作次数重新赋值,导致预期操作次数和实际操作次数不相等了
3.数据结构:
栈:先进后出
队列:先进先出
数组:查询快,增删慢
链表:查询慢,增删快
4.ArrayList
a.特点:
元素有序,有索引,元素可重复,线程不安全
b.数据结构:
数组
c.方法:
add(元素)直接在最后添加元素
add(索引,元素)在指定索引位置上添加元素
remove(元素)删除指定元素
remove(索引)按照指定索引删除元素
size()获取元素个数
get(索引)根据索引获取元素
set(索引,元素)将指定索引位置上的元素修改成我们指定的元素
d.利用无参构造创建集合对象,第一次add时,会创建一个长度为10的空数组
超出范围,自动扩容->Arrays.copyOf
扩容1.5倍
5.LinkedList
a.特点: 元素有序 有索引(java提供了按照索引操作元素的方法,并不代表本质上拥有索引),元素可重复,线程不安全
b.数据结构:双向链表
c.方法:有大量直接操作收尾元素的方法
6.增强for:
a.格式:
for(元素类型 变量名:集合名或者数组名){
变量就代表每一个元素
}
b.原理:
遍历集合时,原理为迭代器
遍历数组时,原理为普通for
模块19重点:
1.会Collections集合工具类的常用方法
2.会使用泛型
3.知道HashSet和LinkedHashSet的特点以及使用
4.知道HashSet将元素去重复的过程
模块19回顾:
1.Collections集合工具类
方法:
addAll-> 批量添加元素
shuffle-> 元素打乱
sort->排序-> ascii
sort(集合,比较器)-> 按照指定的顺序排序
2.泛型:
a.含有泛型的类:
public class 类名<E>{}
new对象的时候确定类型
b.含有泛型的方法:
修饰符 <E> 返回值类型 方法名(E e){}
调用的时候确定类型
c.含有泛型的接口
public interface 接口名<E>{}
在实现类的时候确定类型
在实现类的时候还没有确定类型,只能new对象的时候确定
d.泛型通配符
<? extends 类型> ?接收的泛型类型是后面类的本类以及子类
<? super 类型> ?接收的泛型类型是后面类的本类以及父类
3.哈希值:计算机计算出来的十进制数,可以看成是对象的地址值
a.要是没有重写hashCode方法,默认调用Object中的hashCode方法,计算的是对象的哈希值
b.要是重写了hashCode方法,计算的是对象内容的哈希值
4.HashSet集合
特点: 元素唯一 无序 无索引 线程不安全
数据结构: 哈希表 = 数组+链表+红黑树
5.LinkedHashSet
特点:元素唯一 有序 无索引 线程不安全
数据结构: 哈希表+双向链表
6.set存储自定义对象怎么去重复 -> 重写hashCode和equals方法
7.去重复过程:先比较元素哈希值,再比较内容
如果哈希值不一样,存
如果哈希值一样,再比较内容->哈希值一样,内容不一样,存;哈希值一样,内容一样,去重复
模块20重点:
1.会使用HashMap和LinkedHashMap以及知道他们的特点
2.会使用Properties属性集
3.会操作集合嵌套
4.知道哈希表结构存储元素过程
模块20回顾:
1.HashMap
a.特点:无序,无索引,key唯一,线程不安全,可以存null键null值
b.数据结构:哈希表
c.方法:put remove get keySet entrySet values containsKey
2.LinkedHashMap:
a.特点:有序,无索引,key唯一,线程不安全,可以存null键null值
b.数据结构:哈希表+双向链表
3.key如何去重复:重写hashCode和equals方法
4.TreeSet:是set接口实现类
a.特点:对元素排序,无索引,元素唯一,线程不安全,不可以存null键null值
b.构造:
TreeSet()
TreeSet(Comparator c)
5.TreeMap:
a.特点:对 key排序,无索引,key唯一,线程不安全,不可以存null键null值
b.构造:
TreeMap()
TreeMap(Comparator c)
6.Hashtable:是map接口的实现类
a.特点:无序,无索引,key唯一,线程安全,不能存null键null值
b.用法:和HashMap一样
c.数据结构:哈希表
7.Vector:
a.特点:有序,有索引,元素可重复,线程安全
b.数据结构:数组
8.Properties:是Hashtable子类
a.特点:无序,无索引,key唯一,线程安全,不能存null键null值,key和value都是String的
b.特有方法:
setProperty
getProperty
stringPropertyNames
load(IO流对象) -> 将流中数据加载到集合中
模块21重点:
1.分清楚IO流流向
2.会字节流和字符流的读写操作
#2
24.lambda ->
仅包含一个抽象方法接口 用于替代匿名内部类
(参数列表) -> { 方法体 }
Java Lambda 表达式通过以下方式提升开发效率:
- 简化代码:减少匿名内部类的样板代码。
- 增强可读性:使集合操作(过滤、映射、排序)更直观。
- 支持并行处理:通过 Stream API 轻松实现并行计算。
建议结合 Stream API 深入学习,掌握 filter
、map
、reduce
等核心操作,这是现代 Java 开发的必备技能。
以下是对 Java Lambda 表达式的简要总结:
### **1. 本质**
- **函数式编程思想**的体现,允许将 **代码块(行为)作为数据传递**(如作为方法参数或返回值)。
- **匿名函数**:无需显式定义方法或类,直接编写实现逻辑。
### **2. 核心使用场景**
- **简化匿名内部类**:尤其适用于仅包含 **单一抽象方法(SAM)的接口**(如 `Runnable`、`Comparator`)。
- **集合操作**:配合 `Stream API` 实现过滤、映射、排序等链式操作。
### **3. 语法结构**
```java
(参数列表) -> { 代码块 } // 完整形式
```
- **参数列表**:接口中抽象方法的参数,无参数用 `()`;若类型可推导,可省略参数类型。
- **箭头符号**:`->` 分隔参数与代码块。
- **代码块**:
- 若只有一行代码,可省略 `{}` 和 `return`(隐式返回结果)。
- 若有多行代码,需用 `{}` 包裹,显式用 `return` 返回结果。
### **4. 关键特性**
- **函数式接口**:必须是 **SAM 接口**(可用 `@FunctionalInterface` 注解强制校验)。
- 例:`Runnable`(无参无返回)、`Comparator`(比较逻辑)、`Supplier`(生产数据)、`Consumer`(消费数据)。
- **变量捕获**:
- 可访问 **实例变量** 和 **静态变量**。
- 访问 **局部变量** 时,该变量必须是 **隐式 final**(赋值后不可修改)。
### **5. 常用示例**
#### **示例 1:简化 Runnable**
```java
// 传统匿名内部类
new Thread(new Runnable() {
@Override
public void run() {
System.out.println("Hello Lambda!");
}
}).start();
// Lambda 表达式
new Thread(() -> System.out.println("Hello Lambda!")).start();
```
#### **示例 2:Comparator 排序**
```java
List<String> list = Arrays.asList("apple", "banana", "cherry");
// 传统方式
Collections.sort(list, new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
return o2.length() - o1.length();
}
});
// Lambda 表达式
list.sort((a, b) -> b.length() - a.length()); // 或直接用方法引用:Comparator.comparingInt(String::length).reversed()
```
#### **示例 3:Stream 操作**
```java
List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5);
int sum = numbers.stream()
.filter(n -> n % 2 == 0) // 过滤偶数
.mapToInt(Integer::intValue) // 转换为 IntStream
.sum(); // 求和
```
### **6. 优势**
- **代码简洁**:减少模板代码,提升可读性。
- **行为参数化**:将逻辑作为参数传递,灵活应对不同业务场景。
- **并行处理**:结合 `Stream API` 轻松实现数据并行操作(`parallelStream()`)。
### **7. 注意事项**
- **仅适用于 SAM 接口**:若接口有多个抽象方法,无法使用 Lambda。
- **避免过度使用**:复杂逻辑建议封装为方法,保持代码清晰。
- **与方法引用的区别**:
- Lambda 直接编写逻辑,如 `(x) -> x.toString()`。
- 方法引用调用现有方法,如 `String::toString`(引用已有实现)。
通过 Lambda 表达式,Java 实现了更简洁的函数式编程,尤其在集合处理和异步编程中大幅提升开发效率。
25.方法引用 ::
与 Lambda 的对比
场景 |
Lambda 表达式 |
方法引用 |
静态方法调用 |
|
|
对象实例方法调用 |
|
|
类的任意对象方法调用 |
|
|
构造方法调用 |
|
|
使用条件
- 目标方法参数列表必须与函数式接口的抽象方法参数列表完全匹配(包括数量和类型)。
- 返回值类型必须与函数式接口的抽象方法返回值类型一致。
26.JUC
JUC |
传统多线程(Thread/Runnable) |
线程池管理线程,避免频繁创建销毁 |
手动创建线程,性能开销大 |
原子类无锁操作,高效并发 |
使用 |
丰富的同步工具(Latch/Barrier) |
依赖 |
并发容器优化读写性能 |
使用 |
总结
JUC 是 Java 并发编程的核心工具包,通过线程池、原子类、锁机制等组件,大幅提升了多线程编程的效率和安全性。建议优先使用 JUC 工具替代传统的 synchronized
和 wait/notify
,以减少错误并提高代码性能。
27.设计模式
反复出现的问题的通用解决方案
常见设计模式举例
类型 |
模式名称 |
核心作用 |
创建型 |
工厂模式 |
解耦对象创建和使用,通过工厂统一生成对象 |
单例模式 |
确保类全局只有一个实例,控制资源访问 | |
结构型 |
代理模式 |
为对象提供代理,控制对原对象的访问 |
装饰器模式 |
动态添加对象功能,避免继承带来的类膨胀 | |
行为型 |
观察者模式 |
定义对象间的订阅 - 通知机制,实现松耦合通信 |
策略模式 |
将算法封装为策略类,方便切换和扩展 |
设计模式(Design Patterns)是软件开发中针对常见问题的通用解决方案,它是无数开发者经验的总结,用于提升代码的可维护性、可复用性、可扩展性,并优化软件结构。以下是其核心作用和价值:
1. 解决重复性问题
软件开发中会遇到许多重复出现的问题,例如:
如何高效创建对象?(工厂模式)
如何解耦组件之间的依赖?(代理模式、观察者模式)
如何简化复杂对象的创建过程?(建造者模式)
设计模式为这些问题提供了经过验证的成熟方案,避免开发者每次都从头思考解决方案。
2. 提升代码质量
可维护性:模式通过规范代码结构,使代码更易读、易理解。例如,使用单例模式确保全局唯一实例,避免全局变量滥用导致的混乱。
可复用性:模式封装通用逻辑,允许在不同场景中复用。例如,策略模式将算法封装为独立策略类,可轻松替换或扩展算法。
可扩展性:模式通过抽象和接口设计,使系统易于修改和扩展。例如,装饰器模式在不修改原有类的前提下,动态添加新功能。
3. 统一开发语言
设计模式是开发者之间的 “通用语言”。当团队成员都理解某种模式时,沟通成本会大幅降低。例如,提到 “适配器模式”,无需详细解释即可明白其用于转换不兼容的接口。
4. 优化软件结构
设计模式遵循面向对象设计原则(如开闭原则、单一职责原则等),帮助构建更健壮的系统架构:
结构型模式(如代理、装饰器、适配器):优化类或对象的组合结构。
创建型模式(如工厂、单例、建造者):规范对象的创建流程,避免紧耦合。
行为型模式(如观察者、策略、模板方法):定义对象间的交互逻辑,解耦复杂行为。
5. 应对复杂场景
在大型项目或框架设计中,模式尤为重要:
例如,Spring 框架中大量使用了工厂模式(BeanFactory)、单例模式(Bean 默认单例)、代理模式(AOP 实现)。
MyBatis 中使用构建者模式(SqlSessionFactoryBuilder)和适配器模式(映射器接口适配 SQL 执行)。
常见设计模式举例
类型 模式名称 核心作用
创建型 工厂模式 解耦对象创建和使用,通过工厂统一生成对象
单例模式 确保类全局只有一个实例,控制资源访问
结构型 代理模式 为对象提供代理,控制对原对象的访问
装饰器模式 动态添加对象功能,避免继承带来的类膨胀
行为型 观察者模式 定义对象间的订阅 - 通知机制,实现松耦合通信
策略模式 将算法封装为策略类,方便切换和扩展
为什么需要学习设计模式?
避免 reinvent the wheel:直接使用成熟方案,减少试错成本。
提升架构思维:从 “实现功能” 转向 “优化结构”,适应大型项目需求。
应对面试和团队协作:设计模式是 Java 后端面试的高频考点,也是团队协作中的通用知识。
总结
设计模式不是银弹,不应为了用模式而用模式。关键在于理解其适用场景,在合适的时机引入,以简洁优雅的方式解决问题。对于 Java 后端开发工程师,掌握常用模式(如工厂、单例、代理、观察者、策略等)是进阶必备技能,可显著提升代码质量和系统设计能力。
28.stream流
Java Stream 是处理集合数据的声明式工具,通过流水线操作(如过滤、映射、聚合)高效处理数据。优势:
- 链式调用:代码更简洁(如
list.stream().filter().map().collect()
)。
- 惰性求值:只在终止操作时执行计算,减少中间结果开销。
- 并行处理:通过
parallelStream()
轻松实现多线程计算。
- 函数式编程:支持 Lambda 表达式,避免繁琐循环。
核心流程:创建流 → 中间操作(过滤 / 映射) → 终止操作(收集 / 统计)。
29.不可变集合
Java 不可变集合(如List.of
、Set.of
、Map.of
)创建后内容不可修改,通过工厂方法直接生成。优势:
- 线程安全:无需同步机制,适合高并发场景。
- 防篡改:防御性编程,避免意外修改。
- 高效轻量:内部实现优化,占用资源少。
- 空指针安全:不允许
null
元素(传入null
立即抛异常)。
核心原则:创建即固定,修改即报错(如调用add()
会抛出UnsupportedOperationException
)。
特性 |
不可变集合 |
传统集合(如 ArrayList) |
线程安全 |
天生安全,无需额外同步 |
非线程安全,需手动同步(如 |
修改操作 |
所有修改方法(如 |
支持动态增删 |
空元素支持 |
不允许 |
允许 |
性能 |
初始化后无需扩容,访问效率高 |
动态扩容可能带来性能损耗 |
30.file
- File 类适合简单文件操作(如检查存在性、获取信息),但功能有限。
- Path 类(Java 7+)是更现代的选择,提供链式 API 和更丰富的文件操作(如读写、复制)。
- NIO.2 API(
java.nio.file
包)推荐用于文件读写,简化了异常处理和资源管理。
- 跨平台开发时,始终使用
Paths.get()
或File.separator
确保路径兼容性。
31.工厂模式
工厂模式的适用场景
- 对象创建逻辑复杂:如需要初始化参数、连接资源等,将创建逻辑封装在工厂中。
- 多产品类型切换:客户端只需知道产品类型(或工厂),无需关心创建细节。
- 遵循开闭原则:新增产品时,优先使用工厂方法模式或抽象工厂模式,避免修改原有代码。
- 框架设计:如 Spring 的
BeanFactory
、MyBatis 的SqlSessionFactory
均使用工厂模式解耦对象创建。
工厂模式的优缺点
优点 |
缺点 |
解耦创建和使用,代码结构清晰 |
简单工厂违反开闭原则 |
方便扩展新的产品类型 |
抽象工厂模式类数量较多 |
便于维护和复用(如统一管理对象生命周期) |
学习成本较高(需理解不同模式变体) |
总结
工厂模式是面向对象设计中 “封装变化” 的经典体现,其核心价值在于将对象创建逻辑集中管理,使代码更灵活、易扩展。实际开发中:
- 简单场景优先用简单工厂(或静态工厂方法)。
- 需要频繁扩展产品时用工厂方法模式。
- 处理产品族或配套产品时用抽象工厂模式。
理解不同工厂模式的适用场景,能有效提升代码的可维护性,是 Java 后端开发必备的设计模式之一。
32.单例模式
总结
单例模式是一种 “用简单解决复杂” 的设计模式,核心在于控制实例唯一性和提供全局访问。实际开发中:
- 简单场景优先使用枚举模式或静态内部类模式(线程安全、实现优雅)。
- 需要延迟加载且注重性能时用双重检查锁定。
- 避免滥用:过度使用单例会导致代码难以测试和维护(如依赖单例的类难以 mock)。
理解不同实现的适用场景,能帮助你在保证线程安全的同时,写出简洁高效的代码。