01-Java基础知识复习
2025-01-15 19:42:11 0 举报
AI智能生成
本文档是针对Java基础知识的全面复习,内容涵盖了Java的核心编程概念,包括但不限于:Java语言的特性、数据类型、变量、运算符、流程控制语句(如if-else、for、while)、数组、字符串处理、面向对象编程(OOP)原则、类与对象的创建和使用、继承、封装、多态以及抽象类和接口的实现。
作者其他创作
大纲/内容
1.7 迭代
1.6 字节流,I/O
1.6.1 序列化与反序列化:
定义:
序列化:对象转化为字节流,涉及类:`ObjectOutputStream`
反序列化:字节流转化成对象,涉及类:`ObjectInputStream`
为什么这样做(应用场景):
匹配数据库:持久化和缓存
为了传输到数据库,必然有网络传输
为何要有serialVersionUID?
确保版本一致性
为何要确保版本一致性
防止字节流被恶意构造,加载不安全的类和执行不被期望的代码
如何保证
数字不重要,只保证一致性
没有显式指定就会随机指定,在反序列化之前把类的对象修改,就会造成反序列化指纹变化,从而失败
``` java
private static final long serialVersionUID = 1L;
```
如果不一致会报什么异常:
Java Object Serialization 会使用对象中的serialVersionUID私有静态常量长整型属性(private static final long)作为该对象的版本号,反序列化时 JVM 会校验该版本号是否和序列化时的一致,如果不一致会导致序列化失败,抛出InvalidClassException异常。
如何确保某些字段不被序列化
加一个transient关键字
1.6.2 I/O流
定义:处理输入输出的各种数据类库
分类:
字节流:处理8位字节数据,适用于二进制文件处理,如图片、视频等
输入流:以InputStream结尾
输出流:以OutputStream结尾
字符流:处理16位字节数据,适用于文本文件
输入流:以Reader为结尾
输出流:以Writer为结尾
常用类型一览| 类型 | 字节流 | 字符流 |
| --- | -------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- |
| 输入流 | FileInputStream: 从文件中读取字节数据<br/>BufferedInputStream: 为输入流提供缓冲功能,提升读取性能<br/>DataInputStream: 读取基本类型的数据 | FileReader: 从文件中读取字符数据<br/>BufferedReader: 为字符输入流提供缓冲功能,提升读取性能<br/>InputStreamReader: 字节流转字符流 |
| 输出流 | FileOutputStream: 从文件中写入字节数据<br/>BufferedOutputStream: 为输出流提供缓冲功能,提升写入性能<br/>DataOutputStream: 写入基本类型的数据 | FileWriter: 从文件中写入字符数据<br/>BufferedWriter: 为字符输出流提供缓冲功能,提升写入性能<br/>OutputStreamReader: 字符流转字节流 |
缓冲流:用于处理大文件和频繁I/O操作,所有的Buffered开头的都是
1.5 Exception和Error
定义
`Exception`: 程序中可以处理的异常
`Error`: 系统级别不可恢复的异常
相同点
都是`Throwable`的子类
都需要实现`Throwable`的方法
区别
定义上的区别
常见的Exception
`Exception`(通用异常,非必要不要使用这个)
运行时
`NullPointerException`(空指针异常)
`ArrayIndexOutOfBoundsException`(数组下标越界异常)
`IllegalArgumentException`(非法参数异常)
`ArithmeticException`(算数异常)
`ConcurrentModificationException`(并发修改异常)
检查时
`FileNotFoundException`(文件未找到异常)
`IOException`(输入输出异常)
常见的Error
可参考:
如何处理
try-catch-finally
`throw` 和 `throws` 区别
throw代表动作,表示抛出一个异常的动作;
throws代表一种状态,代表方法可能有异常抛出
throw用在方法实现中,而throws用在方法声明中;
throw只能用于抛出一种异常,而throws可以抛出多个异常
分支主题
注意事项
不随意使用try-catch
finally代码块不要return,或处理返回值
最好不要直接处理Exception,要指定类型
不建议直接使用`e.printStackTrace()`,尤其在分布式系统中会很难追踪,建议配合log4j
不在 if-else 分支处理异常
禁止延迟处理
1.1 Java的优势
跨平台
因为JVM的存在,确保一次编码,多平台可用
垃圾回收
可以自动垃圾回收,交给GC来管理
全面
生态全面:第三方库、框架、资料、中间件都有很强的适配性
面向对象
类、抽象类、接口、对象
封装、继承、多态
对比Go语言| 语言 | Java | Go |
| ---- | --------------------------- | -------------------------------------- |
| 设计思想 | 面向对象语言 | 保留了一些基础面向对象的特性 |
| 设计特性 | 一次编写,到处运行 | 语法简洁,快速编译 |
| 设计目标 | 高度灵活性和可扩展性的通用编程平台 | 提高开发者生产力并简化构建高性能服务器的过程 |
| 并发模型 | 基于线程 | 基于协程(Goroutine) |
| 内存管理 | GC自动管理,开发者可根据需求自己选择算法 | 也有GC,但更适用于处理大量并发请求的情况 |
| 生态应用 | 企业级应用开发、Web开发、大数据处理、安卓开发等领域 | 云计算、微服务、容器化技术(尤其Docker & K8S)、高性能服务器开发 |
| ---- | --------------------------- | -------------------------------------- |
| 设计思想 | 面向对象语言 | 保留了一些基础面向对象的特性 |
| 设计特性 | 一次编写,到处运行 | 语法简洁,快速编译 |
| 设计目标 | 高度灵活性和可扩展性的通用编程平台 | 提高开发者生产力并简化构建高性能服务器的过程 |
| 并发模型 | 基于线程 | 基于协程(Goroutine) |
| 内存管理 | GC自动管理,开发者可根据需求自己选择算法 | 也有GC,但更适用于处理大量并发请求的情况 |
| 生态应用 | 企业级应用开发、Web开发、大数据处理、安卓开发等领域 | 云计算、微服务、容器化技术(尤其Docker & K8S)、高性能服务器开发 |
1.2 类
1.2.1 内部类(最好不要用)
定义在类里边的类,内部类可以访问外部类的成员变量和方法,甚至是私有成员
作用
**封装性**:把逻辑相关的封装在一起,提高类的内聚性
**可以访问外部类成员**:尤其指成员内部类和静态内部类特性,对访问外部类需求非常有用
**简化代码**:减少冗余,简化结构,特指局部内部类
**事件处理**:尤其用在匿名内部类里,实现回调函数和监听事件,特别发生在抽象类和接口的适用场景
种类:
**成员内部类**:非静态,作为外部类的一个成员。它可直接访问外部类的成员(私有的也能访问)
**静态内部类**:用`static`修饰,只能访问外部类的静态成员,非静态成员无法访问
**局部内部类**:定义在方法/代码块中的类,只能在该方法/代码块内可见,通常用于临时对象构建
**匿名内部类**:没有类名的内部类,通常用于短期使用的类的实例,尤其处理回调或事件
**Lambda表达式(JDK8新特性)**:这是一种匿名函数,如果接口中只有一个抽象方法,最好使用该方法(JDK8+),否则只能使用匿名内部类。| | 匿名内部类 | Lambda表达式 |
| ---- | -------------------- | ------------ |
| 所需类型 | 全体类,包括但不限于具体类、抽象类和接口 | 接口 |
| 使用限制 | 接口中可以有多个抽象方法 | 接口中只能有一个抽象方法 |
| 实现原理 | 会多生成一个.class文件 | 其字节码文件会动态生成 |
1.2.2 不可变类
最终类
定义
对象创建以后,所有的字段都无法被修改的类
特征
不可被继承
一旦对象被创建,所有属性都不能变
生命周期:仅在构造对象时就把所有的变量都初始化
类使用`final`修饰符号
所有字段都是私有(`private`)且不可变(`final`)的
一般不提供任何对象的修改方法,尤其是`setter`
为确保可变对象引用不被修改,`getter` 需要返回一个副本,即`new`一个可变对象来保护
优缺点
优点
**线程安全**:不可变类本身就无法修改状态,所以天生线程安全, 并发环境中无法被同步
**缓存友好**:可以被安全地缓存和共享
**确保一致**:避免对象修改而导致不一致的问题
如何实现
参考String
1.2.3 String、StringBuilder、StringBuffer
为何循环拼接字符串不使用String,而是使用StringBuilder和StringBuffer?
本质原因,还是因为String是不可变类,每拼接一次都要重新创建一个对象,系统的开销逐渐加大
为了避免这个原因,StringBuffer应运而生,它是一个可变类,还是线程安全版本的,通过synchronized关键字保证的
但很多时候,犯不上特意要求线程安全的情况,StringBuilder就出来了,它是最适合高频拼接的操作
如果是我来取拼接字符串,根据频率不同和环境不同,如果在for循环内,涉及多线程问题同StringBuffer,不涉及就用StringBuilder,不在for循环内,直接用加号也行,参考阿里规约22条
StringBuilder的实现(增删改查)
append
insert
delete
replace
charAt
....
String 从JDK9开始为何改用 byte[] 而不是 char[]
JDK9之前:内部采用UTF-16编码,每个字符占用2个字节,但会对当前字符只需一个字节空间的情况造成浪费
JDK9之后:采用byte数组实现,ASCII字符串只需1个字节,减小内存占用
区别一览| 类型 | String | StringBuffer | StringBuilder |
| ---- | ---------- | ------------------- | -------------- |
| 可变类型 | 否 | 是 | 是 |
| 线程安全 | 是,不可变类天然特性 | 是,使用synchronized来保障 | 否 |
| 适用场景 | 字符串不会频繁变化 | 字符串在多线程、高并发环境下频繁变化 | 字符串在单线程环境下频繁变化 |
1.2.4 抽象类和接口
**接口类**:自上而下设计,先约定接口再实现
**抽象类**:自下而上设计,先有一些类,才抽象成共同父类
区别
方法实现
接口默认是共有且抽象的,JDK8以后也可以设置default方法或静态方法
抽象类需要对抽象方法增加abstract修饰符
构造函数和成员变量
接口不可包含构造函数,成员默认变量会被修饰为: public static final(Java常量的定义方法)
抽象类可以包含构造函数,可以允许不同的修饰符(private、protected、public),也可以不是常量
1.2.5 Object
1.2.6 对象的比较
hashCode:散列存储结构确定对象的存储位置。可用于快速比较两个对象的不同,因为如果它们的hash码不同,它们一定不相等
equals:用于比较两个对象的内容是否相等,通常重写自定义比较逻辑
==:比较两个引用是否指向同一个对象(即内存地址),对于8大基本数据类型,是值比较
hashCode与equals的关系:
如果两个对象根据equals方法被认为是相等的,那么它们就必须有相同的hashCode
反之未必相等,但会放在同一个hash桶中
1.2.7 基本数据类型
与包装类型的区别与联系
**基本类型**:有8种,直接存储数值的变量,位于栈上(局部变量在栈上,成员变量在堆上,静态(类)字段在方法区),性能较高,且不支持null
**包装类型**:每个基本类型都有个包装类型。包装类型是类,存储在堆中,可用于面向对象编程,并且支持null
类型| 分类 | 基本数据类型 | 包装类型 | 长度(Byte) | 范围 |
| --- | ------- | --------- | -------- | ---------------- |
| 布尔型 | boolean | Boolean | - | true, false |
| 整型 | byte | Byte | 1 | -2^7~2^7-1 |
| 整型 | short | Short | 2 | -2^15~2^15-1 |
| 整型 | int | Integer | 4 | -2^31~2^31-1 |
| 整型 | long | Long | 8 | -2^63~2^63-1 |
| 字符型 | char | Character | 2 | Unicode字符集中的任何字符 |
| 浮点型 | float | Float | 4 | -3.4e38~3.4e38 |
| 浮点型 | double | Double | 8 | -1.7e308~1.7e308 |
| --- | ------- | --------- | -------- | ---------------- |
| 布尔型 | boolean | Boolean | - | true, false |
| 整型 | byte | Byte | 1 | -2^7~2^7-1 |
| 整型 | short | Short | 2 | -2^15~2^15-1 |
| 整型 | int | Integer | 4 | -2^31~2^31-1 |
| 整型 | long | Long | 8 | -2^63~2^63-1 |
| 字符型 | char | Character | 2 | Unicode字符集中的任何字符 |
| 浮点型 | float | Float | 4 | -3.4e38~3.4e38 |
| 浮点型 | double | Double | 8 | -1.7e308~1.7e308 |
装箱与拆箱
**装箱**:基本类型自动转换为包装类型对象
**拆箱**:包装类型对象自动转换成基本类型的值
作用:
从JDK5开始引入,提高代码可读性,减少手动转换操作,简化代码编写
场景:
容器类无法存储基本类型,可以转换存入集合
包装类型参与运算时,自动拆装箱就会出现
Integer缓存池
对于值在-128~127之间的int类型,会直接返回一个已经缓存的Integer对象,而非创建新对象
Java 8 版本起,可以通过JVM参数 -XX:AutoBoxCacheMax=size来调整缓存池上限,这样可以把缓存范围扩大
适用场景:自动装箱、值比较
1.2.8 拷贝
**深拷贝**:不仅复制对象,还递归复制对象中所有引用的对象,确保新对象与原来的对象完全独立,修改时不会影响到原有对象,尤其包括基本类型和引用类型,堆内引用对象也会复制一份。
**浅拷贝**:只复制对象的引用,不复制引用指向的实际对象,也是创建一个新对象,但他的字段(若是对象类型)指向的是原对象中相同的内存地址
影响:深拷贝修改其中一个对象不会影响另一个,浅拷贝会影响(浅拷贝共享相同的引用)
1.2.9 泛型
容器类
集合类:如List、Map、Queue、Set
Optional
作用
**安全性**:在编译时检查类型安全
**重复性**:允许程序员写更加通用和灵活的代码
**消错性**:避免在运行时发生类型转换错误
泛型擦除
在编译时把所有与泛型有关的信息全部删除,以确保与JDK4及之前版本保持兼容
上下界限定符
上界限定符:? extends T,表示通配符必须是T类型或T的子类,通常用于读取操作,确保可以读到T或T的子类的对象
下界限定符:? super T, 表示通配符必须是T类型或T的父类,通常用于写入操作,确保可以安全地向泛型集合中插入T或T的父类的对象
**不支持基本类型**
1.2.10 Optional
JDK8起引入,用于表示可能为空的值,通过提供更为清晰的API,来避免空指针异常的发生
Optional可以包含一个值,亦可为空,从而表示存在或不存在
基本方法
of (T value):创建一个非空Optional
empty(): 创建一个空Optional
~~get(): 获取Optional中的值(别用,有NPE风险)~~
isPresent(): 判断是否有值
ifPresent(Consumer<? super T>): 若包含值,则执行指定操作
orElse(T other): 如果为空,则返回other值
orElseGet(Supplier<? extends T>): 若为空,则执行Supplier提供的操作,返回值
1.2.11 BigDecimal
如果有问你,你就回答这些就行:这是一个可以支持任意精度的数字类型,存在于java.math包里,创建方法与包装类型相同,一般使用new BigDecimal("1.23")或BigDecimal.valueOf(1.23)来创建,可支持加减乘除取余比较等多种操作,还可以自定义四舍五入的方式,具体常数我会去找它的源码,看它注释解释
如果问你它属于什么类型,可以直接引导到不可变类这个问题上去,把不可变类主要特性回答一遍就好,扯得越远越好,最好扯到String上去
1.2.12 加载过程
定义:把类加载到JVM中,先把二进制流存到内存中,进行解析、处理转化,形成可用的class类
加载阶段
将二进制流读入内存中,生成一个Class对象
连接阶段
验证:二进制流是否符合一定格式,是否规范,是否符合当前JVM版本等等之类的验证
准备:对静态变量赋初始值(为它们在方法区划分空间),如int初始值为0
解析:常量池符号引用转化为直接引用
初始化阶段
执行静态代码块,为静态变量赋值,准备阶段只是设置初始值占位
1.2.13 注解 `@interface`
是一种标记,提供元数据机制,用于给代码提供说明信息。标记在类上、方法上、属性上等,标记自身也可以设置一些值
元注解:注解的注解
Retention
Target(这个必须会用)
ElementType.TYPE
ElementType.FIELD
ElementType.METHOD
Inherited
1.3 面向对象三大特性
1.3.1 继承
概念:子类继承父类的行为、特征,使子类拥有父类的示例域和方法,或子类从父类继承方法,是的子类拥有与父类相同的行为
优点
**可复用**:子类可以复用父类代码,减少重复实现
**易维护**:可以通过修改父类代码影响子类
缺点
**紧耦合**:子类依赖父类实现,父类修改可能影响子类
**灵活性差**:继承层次结构可能会变得复杂,不易于调整或扩展
方法重载与重写
**重载**:在同一个类中定义多个方法,但这些方法名称相同,参数列表不同(类型与数量不同),返回类型不同,修饰符可以不同,可以是静态或非静态方法,处理异常方式也可以完全不同
**重写**:子类重写父类的一个或多个方法。通过父类引用调用方法时,实际执行的是子类重写后的方法,参数列表、返回类型要与父类完全一致,访问级别要相同或宽于父类,只能重写非静态方法,可以抛出比父类相同或更少的异常
Java继承方式
子类可继承父类所有公共和受保护成员,不能继承父类私有成员
Java支持多重继承吗?
不能,只支持单继承,一个类只能直接继承一个子类。
因为产生菱形继承,所以一般情况下不支持多继承
接口可以多继承的原因是:JDK8以前接口类无法定义具体方法实现,允许有多个接口必须要求子类自己实现,并不会发生歧义
但JDK8以后对接口出了defalut关键字,为了避免这个问题,如果多个接口内有相同的默认方法,子类必须重写
this, super, extends, implements
this & super
this: 用于调用自身的方法,也可以访问自己的字段,不可在静态方法或字段中使用,多用于形参与成员变量重名的情况
super: 用于调用父类方法或构造方法,也可以访问父类的字段,和this一样,不可在静态方法或字段中使用
分支主题
extends & implements:
extends: 创建一个类的子类
implements: 声明自己使用一个或多个接口
可在一个类中同时存在
1.3.2 封装
概念:封装特性对象的状态(数据)和行为(方法)封装在一个类的内部,并通过公开的接口与外部进行交互。
作用:隐藏对象内部细节,只暴露必要功能
特点:
保护数据安全性
减少系统复杂性
基本概念:
**数据隐藏**:把成员字段定义为private或protected,避免外部直接访问,必须通过公共的方法(如getter和setter,下同)才可以访问和修改
**公共接口**:通过公共方法提供访问对象数据的方式。这样可以对数据进行控制和验证,确保数据的一致性和合法性
**保护数据**:封装通过限制数据的直接访问
访问修饰符
public: **任何类**都可以访问被修饰的类或类成员(字段、方法、构造器),可修饰类、接口、字段、方法、构造函数
private: 只可以在类的内部进行访问,**类外(包括子类)均无法访问**,可修饰字段、方法、构造函数(没有类)
protected: 允许**同一个包**内的成员或**所有继承关系中的子类**访问,可修饰范围与private相同
无修饰符: 只**允许同一个包**内的成员访问,**不允许包外的类或子类**访问,除了接口都可以修饰
1.3.3 多态
定义:同一接口引用变量可以指向不同对象实例,并根据实际指向对象执行相应方法
优点
灵活处理不同对象
降低代码耦合度
增强系统扩展性
实现类/新增子类时,不必去修改原有代码,只要通过接口和父类调用即可
以上也是多态的意义
种类
编译时多态(静态多态),编译阶段确定方法的调用,主要通过方法重载实现
运行时多态(动态多态),在运行时确定方法的调用,主要通过方法重写实现
1.3.4 与面向过程的区别
1.4 Java参数传递问题
定义
值传递:值副本的传递(Java唯一的传递方式)
优点:直观且安全
缺点:开销大,性能容易下降
地址传递:地址副本的传递 ,C语言独有
优点:可直接修改原始值,适合大型对象传递
缺点:需要手动管理内存,为避免空指针或无效地址,还要进行有效性检查
引用传递:参数的引用的传递
优点:可直接修改原始值,适合大型对象传递,避免手动管理内存
Java如何传递:
结论:所有类型的变量只有值传递,没有引用传递
基本类型:传递值的副本(数值本身),对方法参数任何修改都不会影响原始变量
引用类型:传递引用副本(对象引用的内存地址),方法内可以通过引用修改对象的属性,但无法改变本身,使其指向另一个对象
因此只有值的传递
0 条评论
下一页