复习了一波 java
oracle 官网: https://docs.oracle.com/en/
选择 JDK 版本进入: https://docs.oracle.com/en/java/javase/
java 官网 API: https://docs.oracle.com/en/java/javase/11/docs/api/index.html
八种数据类型
1、byte: 1 个字节 (-2^7~2^7-1 )
2、short: 2 个字节 (-2^15~2^15-1)
3、int: 4 个字节 (-2^31~2^31-1)
4、long: 8 个字节 (-2^63~2^63-1)
5、float: 4 个字节 (3.410^(-38) ~ 3.410^(+38)) (float 占 4 个字节, 为什么比 long 表示的范围大? 因为虽然 long 占 8 个字节, 但是按整数的规则计算的, float 虽然占 4 个字节, 但是是按小数的规则计算的, 所以 float 表示的范围要比 long 大)
6、double: 8 个字节 (1.710^(-308) ~ 1.710(308))
7、char: 2 个字节 (0~2^16-1)
8、boolean: 1 个字节 (true || false)
计算机存储数据的形式
计算机中最小的存储单元是字节(Byte, 通常用 B 表示), 每个字节包含 8 个位(bit, 又叫“比特位” 通常用 b 表示, 值为 0 或者 1)
单位 | 换算 |
---|---|
1B(字节) | 8bit |
1KB | 1024B |
1MB | 1024KB |
1GB | 1024MB |
1TB | 1024GB |
所以通常我们获取浏览器当前本地缓存容量剩余可以这么求:
1 | (function () { |
类型转换
不同类型的数据之间可能会进行运算, 而这些数据取值范围不同, 存储方式不同, 直接进行运算可能会造成数据损失, 所以需要将一种类型转换成另外一种类型再进行运算
1、自动(隐式)类型转换
小类型转大类型, 自动提升为大类型, 运算结果是大类型
1 | 数据类型的范围从小到大如下: |
2、强制(显式)类型转换
手动将大类型转换成小类型, 运算结果是小类型, 转换格式: 小类型 变量名 = (小类型)大类型数据
1 | 目标类型 变量名 = (目标类型) 要转换的值 |
方法重载
什么是方法重载
在同一个类中的多个方法, 它们方法名相同, 参数列表不同, 这样的情况称为方法重载. 方法重载与返回值类型无关
参数列表不同:
1 | 1、参数的个数不同 |
方法签名
方法名 + 参数列表
为什么需要方法重载
当实现的功能相同, 但具体的实现方式不同, 我们可以通过定义名称相同, 参数(条件)不同的方法, 来更好的识别和管理类中的方法.
数组初始化
在内存中为数组开辟连续空间并为每个元素赋值的过程
内存
计算机的重要组件, 用于程序运行中临时存储数据
连续空间
数组元素在内存中的存放位置是连续的
程序的内存分配
方法区
存储可运行的 class 文件, 包含方法, 静态成员, 常量等
栈
方法运行时使用的内存,特点是“后进先出”, 即最先进入栈区的方法最后出栈, 比如 main 方法
堆
存储 new 出来的数组或者对象
本地方法栈
JVM 在调用操作系统功能时使用, 与开发无关
寄存器
CPU 使用, 与开发无关
数组类型
变量 arr 存储的是数组在堆内存中的地址值, 而不是数组元素的值, 变量 arr 通过内存地址引用堆内存中的数组, 所以数组是引用类型
final 关键字
final: “最终”的意思; 在 Java 中是一个关键字, 可以用来修饰类, 成员变量, 成员方法
1、修饰的类: 不能被继承(没有子类), 但是可以继承其他类
2、修饰的方法: 不能被重写(和 abstract 冲突, 因为 abstract 修饰的类是抽象类, 要求必须重写), System, String 这些关键字其实就是被 final 修饰的, 所以不能重写
3、修饰的变量: 是一个常量, 值只能设置一次; 如果修饰的是一个引用的地址, 那么地址不能改动而属性可以改
static 关键字
用于修饰类的成员, 被修饰的成员变量 = 类变量, 被修饰的成员方法 = 类方法; 然后可以直接类名.xxx 直接调用, 所以通常随意改变 static 修饰的类成员变量或者类方法是有风险的, 所以可以使用 final 关键字对其进行修饰, 使之成为一个不可修改的常量;
接口的概念
用于描述类具有什么功能, 但是不给出具体实现, 类要遵从接口描述的统一规则进行定义, 所以, 接口是对外提供的一组规则、标准
举例: 插座(接口) => 插头(具体实现根据插座是几个孔的规则)
接口的定义
定义接口关键字 interface
1 | interface 接口名 {} |
类和接口是实现关系, 用 implements 表示
1 | class 类名 implements 接口名 {} |
⚠️ 在声明接口的时候成员方法如果不写方法体, 会默认加上 public abstract
demo:
1 | public interface Working { |
此时接口中有抽象方法, 在 work 的实现类就要实现这个抽象方法
1 | public class Person implements Work { |
⚠️ 还需要注意的点是, 接口不能实例化,但是可以实例化实现的子类, 这种写法也叫多态
成员变量
接口中没有成员变量, 只有公有的, 静态的常量; 原因是接口中所有的变量都默认有一组修饰符, 这是系统默认写的, 如果你写了系统就不写, 如果你不写系统就默认写上, 而 final 的作用可以看上面部分
1 | public static final 常量名 = 常量值 |
成员方法
JDK7 以前, 接口中只有公有的抽象方法, 因为接口中的方法系统都会默认加上
1 | public abstract 返回类型 方法名() |
JDK8 以后, 可以拥有默认方法和静态方法;
默认方法:
1 | public default 返回类型 方法名 () {} |
静态方法:
直接写就可以了
1 | static 返回类型 方法名() {} |
JDK9 以后, 可以有私有方法:
1 | private 返回类型 方法名 () {} |
接口中构造方法
由于接口不能实例化, 也没有需要初始化的成员变量. 所以接口没有构造方法;
Java 中的 API
java 中组件的层次结构
模块(module) => 包(package) => 类或接口(class / interface)
模块: 在包的基础上又进行了一层封装, 是包的容器
Object 类
类层次结构最顶层的基类, 所有类都直接或间接的继承自 Object 类, 所以, 所有的类都是一个 Object(对象), 继承自 java.base;
常用到的类
Object, Scanner, String, StringBuilder, StringBuffer, Date, Calendar
集合
什么是集合
简称集, 是用来存储多个元素的容器
集合和数组的区别
- 元素类型
集合: 存储引用类型数据(存储基本类型时自动装箱)
数组: 可以存储基本类型和引用类型的数据 - 元素个数
集合: 元素个数不固定, 可任意扩容
数组: 固定, 不能改变容量 - 集合的好处
可以不受容器大小限制(写 js 爽的同学用起来也爽), 可以随时添加, 删除元素, 提供了大量操作元素的方法(判断,获取等等, 类似: StringBuilder 和 StringBuffer)
集合体系
单例集合(Collection)
- List: ArrayList
可重复, 有序(存取顺序相同)
1 | List list = new ArrayList(); |
- Set: HashSet
不可重复, 无序
1 | Set<Student> set = new HashSet<>(); |
写一个 demo, 首先声明一个学生累
然后声明 5 个学生, 用 set 去重
1 | public class SetDemo { |
为什么用了 Set 没有去重?
实际上已经去重完成了, 因为 Set 集合保证元素的唯一性依赖 equals()和 hashCode()两个方法, 我们没有在 student 中重写这两个方法, 默认就会使用 Object 类中的 equals(), Object 类下的 equals()方法默认比较的是内存地址, 5 个 studen 都是 new 出来的, 所以指向的内存地址不一样(这个去掉 toString 方法就可以打出来了)
- 解决方案: 在 Student 类中重写 equals()和 hashCode
1 |
|
这时候再打印就是去重之后的了
1 | set集合: [Student{name='戴沐白', age=16}, Student{name='马红俊', age=17}, Student{name='唐三', age=15}] |
双例集合(Map: key, value)
- Map: HashMap
双例集合, 元素由键值对构成, key 不可重复, value 可以重复
1 | Map<T1, T2> map = new HashMap<>(); |
写一个 demo, 还是用上面的 Student 类创建学生
⚠️ 双例集合无法直接遍历, 只能先获取所有 key 的集合(keySet), 再根据 key 遍历出 value (迭代器,增强 for )
增强 for 循环
1 | for (Object obj:list) { |
⚠️ 增强 for 循环的底层依赖的是迭代器(Iterator), 可以理解成增强 for 就是迭代器的简写形式
迭代器
为什么需要迭代器?
对过程的重复, 称为迭代. 迭代器是遍历 Collection(单例子)集合的通用方式, 可以在对集合遍历的同时进行添加, 删除等操作.
迭代器的常用方法
- next(): 返回迭代的下一个元素对象
- hasNext(): 如果仍有下一个元素, 返回 true
1 | Iterator it = list.iterator() |
泛型
即泛指任意类型, 又叫参数化类型, 对具体类型的使用起到辅助作用, 类似于方法的参数
集合类型的解释
表示该集合中存放指定类型的元素
1 | List<String> list = new ArrayList<>(); |
好处: 类型安全, 避免了类型转化
Collections 工具类
针对集合进行操作的工具类
成员方法:
- sort(List
)
根据元素的自然顺序, 将指定列表按升序排序 - max(Collection
)
返回集合的最大元素 - reverse(List
)
反转 List 集合元素 shuffle(List
)
使用默认的随机源随机置换指定的列表, 也就是可以将数组进行随机排列1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24public class Test {
public static void main(String[] args) {
List list = new ArrayList();
list.add(1);
list.add(2);
list.add(3);
Collections.sort(list);
System.out.println(list); // []
System.out.println(Collections.max(list));
Collections.reverse(list);
System.out.println(list);
Collections.shuffle(list);
System.out.println(list);
}
}
// [1, 2, 3]
// 3
// [3, 2, 1]
// [3, 1, 2]
1 | > 还有更多的方法, 在 java.utils 下面可以找到 |
- 方式二, throw new Error(…)
- JVM 的默认处理方式: 在控制台打印异常信息, 并终止程序;
什么是 IO 流
I/O, 即输入输出, IO 流指的是数据像连绵的流体一样进行传输
IO 流能做什么
在本地磁盘和网络上操作数据
IO 流的分类
- 按数据流向(输入流, 输出流)
- 按操作方式
1、字节流 - InputStream: 字节输入流顶层抽象类(FileInputStream(普通的字节输入流), BufferedInputStream(高效字节输入流))
- OutputStream: 字节输出流顶层抽象类(FileOutputStream(普通字节输出流), BufferOutputStream(高效字节输出流))
2、字符流 - Reader: 字符输入流的顶层抽象类(FileReader(普通字符输入流, BufferedReader(高效字符输入流, 也叫字符缓冲输入流)))
Writer: 字符输出流的顶层抽象类(FileWrite(普通字符输出流), BufferedWriter(高效字符输出流, 也叫字符缓冲输出流))
File 类
反射
什么是反射?
在程序运行过程中分析类的一种能力
反射能做什么?
- 分析类
1、加载并初始化一个类
2、查看类的所有属性和方法 - 查看并使用对象
1、查看一个对象的所有属性和方法
2、使用对象的任意属性和方法反射的引用场景: 构建通用的工具
demo: 通过反射的方式创建: Student 类型的对象
创建一个 Student 类
1 | public class Student1 { |
写一个 ConstructorDemos
1 | import java.lang.reflect.Constructor; |
创建一个新的学生
1 | Student1 stu = (Student1) con2.newInstance("Hardy"); |
调用类成员的方法
给学生类增加两个公共方法
1 | public void method1 () { |
在 demo 中去调用方法
1 | //反射的构造创建一个学生类 |
获取完单个方法之后, 来批量获取一下方法
1 | Method[] methods = clazz.getMethods(); |
输出:
1 | public void com.study.demos.stringDemos.Student1.method1() |
因为所有的类都直接或者间接继承于 Object, 所以会将 Object 上的一些方法也获取到了, 如果只需要获取 Student 下的方法, 用 getDeclearMethods
1 | Method[] methods = clazz.getDeclaredMethods(); |
输出:
1 | private void com.study.demos.stringDemos.Student1.methodPri2(i nt,int) |
获取成员变量是 Field, Fileds