Java知识
基础语法
- 数据在计算机中最小单位为字节(byte,B),一个字节8个比特位即
1B=8b
字面量
| 常用数据 | 程序中形式 | 说明 |
|---|---|---|
| 整数 | 123 | 写法一致 |
| 小数 | 12.3 | 写法一致 |
| 字符 | ‘A’,’0’,’好’ | 必须要用单引号包裹,且只能一个字符 |
| 字符串 | “123” | 必须用双引号包裹,内容可为空 |
| 布尔值 | true,false | 只有两种值 |
| 空值 | null | 特殊值 |
| 特殊字符 | \t,\n | 缩进换行等 |
二八十六进制
对于二进制数据需要以
0B或0b开头
对于八进制数据需要以0开头
对于十六进制数据需要以0x或0X开头
- 十进制转二进制:除二取余法
- 二进制转八进制:每三位二进制为一位八进制
- 二进制转十六进制:每四位二进制为一位十六进制
基本数据类型
| 数据大类 | 数据类型 | 占用字节数 | 数据范围 |
|---|---|---|---|
| 整型 | byte | 1 | -128~127 |
| 整型 | short | 2 | -32768~32767 |
| 整型 | int(默认) | 4 | -2147483648~2147483647 |
| 整型 | long | 8 | -9223372036854775808~9223372036854775807 |
| 浮点型 | float | 4 | 1.401298E-45~3.4028235E-+38 |
| 浮点型 | double(默认) | 8 | 4.9000000E-324~1.797693E+308 |
| 布尔型 | boolean | 1 | true,false |
| 字符型 | char | 2 | 0~65535 |
表达式的自动类型提升
- 表达式的自动类型转换
表达式中小范围类型的变量,会自动转换为表达式中较大范围的类型,再参与运算
byte short char ->int ->long -> float-> double
- 表达式最终结果类型由表达式中最高数据类型决定
- 表达式中 byte short char是
直接转换成int参与运算
一维数组
1 | /* |
二维数组
1 | 类型[][] 数组名 = new 类型[][]{...} |
多态
多态是继承/实现情况下的一种现象。分为行为多态和对象多态
多态是对象和行为的多态,不包括成员变量
1 | // A 是B C的父类,func是A的抽象方法 |
多态前提:
继承/实现情况下- 存在父类引用子类的情况
- 存在
方法重写
好处
- 多态形式下,右边是解耦的,便于扩展维护
- 定义方法时,使用父类类型的
形参,可以接受一切子类,使方法可以接受多个类对象,更灵活
问题以及解决
- 多态不能调用子类的独有功能
解决:类型转换
1 | // 自动类型转换 |
注意
- 存在继承/实现关系就可以在编译阶段进行强转,编译阶段不会报错
- 运行阶段发现对象的真实类型与强转后的类型不同,就会报类型转换异常
final关键字
可以修饰类,方法,变量
分别为最终类:不能再被继承
最终方法:不能再被重写
变量:有且只能赋值一次
注意
- final修饰
基本数据类型的变量,变量存储的数据不可以改 - final修饰
引用数据类型的变量,变量存储的地址不可以改,但是地址所指向的内容可以改
单例设计模式
作用: 确保某个类只有一个对象
步骤
- 把类的构造器私有
- 定义一个静态类变量记住类的一个对象
- 定义一个公开方法获取这个类变量
单例形式
- 上面的为
饿汉式单例 - 还有
懒汉式单例
懒汉式单例中,只需要定义一个静态变量,不用先获取对象
然后提供一个静态方法,当该变量为空时再new一个对象,最后再返回这个对象
枚举
特点
- 枚举类是一种特殊类,用来表示一组固定的常量
- 是最终类,不可以被继承,枚举类都是继承自java.lang.Enum类
- 枚举类第一行只能罗列常量,每个常量都会记住枚举类的一个对象
- 枚举类构造器必须私有,所以不能对外创建对象
书写与使用
1 | 修饰符 enum 枚举类名{ |
常见应用场景
- 信息分类和标志
应用理由
- 枚举是有限且确定的常量,适合固定且有限的取值集合
- 枚举常量有名字,比数字或字符串直观。比如 Status.SUCCESS 一看就是“成功”,比 200、”OK” 更清晰
- 枚举能带属性和方法,不仅仅是标志,还能存储和管理相关信息
1 | public enum Status { |
抽象类
特点
- 以abstract关键字修饰类或方法
- 抽象类有普通类的所有(构造器,成员,方法),不一定有抽象方法,抽象方法只能在抽象类中
- 抽象类只能继承,不能创建对象
- 要继承抽象类,子类必须重写所有抽象方法,否则子类也必须声明为抽象类
- 抽象方法只能声明不能写方法体,除非是被继承重写的
书写
1 | 修饰符 abstract 返回值类型 抽象类名{ |
常见应用场景
- 知道子类都要做某个行为,但每个子类要做的事情都不一样,父类就定义为抽象方法,交给子类去实现
- 这样的抽象类会更好的支持多态
- 适用模版方法设计模式
应用理由
模版方法设计模式:
- 提供一个方法作为完成某些功能的模版,模版方法封装了每个实现步骤,但允许子类提供特定步骤的实现
写法:
- 定义一个抽象类
- 写一个模版方法,将相同步骤放进去
- 写一个抽象方法,替换到模版方法不确定的步骤中,交给子类实现
接口
特点
- 接口以interface关键字修饰
- 接口中只能写常量和抽象方法
- 接口中常量的public static final可以省略
- 抽象方法的public abstract可以省略
- 接口不能创建对象,但是可以被实现(implements关键字)
- 实现接口的类称实现类,实现类可以实现多个接口
- 实现类与抽象子类一样,若没有重写完实现的抽象方法,则自己要标记为实现类
- 如果多个接口中存在方法签名冲突(返回值不同),则此时不支持多继承,也不支持多实现
- 既继承父类,又实现接口,父类和接口中有同名的默认方法,则实现类优先使用父类的
书写
1 | public interface 接口名{ |
常见应用场景
- 弥补单继承的不足,实现类可以实现多个接口,拥有多个角色,更多功能
- 程序可以面向接口编程,利于程序的解耦合
应用理由
- 代码只依赖接口,不依赖具体实现类
- 新增实现类不影响现有代码
- 可以轻松使用接口的Mock进行单元测试
与抽象类相同处
- 多是抽象方式,都可以有抽象方法,那不能创建对象
- 都是派生子类形式,抽象类是子类继承形式,接口是被实现类实现
- 一个类继承抽象类,或者实现接口,都必须重写所有的抽象方法,否则自己要变成抽象类或者报错
- 都能支持多态,都能解耦合
与抽象类不同处
- 抽象类可以定义类的全部普通成员,接口只能定义常量,抽象方法,默认方法,私有方法,静态方法
- 抽象类只能被类单继承,接口可以被类多实现
- 一个类继承一个抽象类就不能再继承其他抽象类,一个类实现了一个接口还可以继承其他类或者实现其他接口
- 抽象类体现模版思想,更利于做父类,实现代码的复用性
- 接口更适合代码的解耦合,解耦合性更强更灵活
代码块
静态代码块
特点
- 类加载时自动执行,由于类只会加载一次,所以静态代码块也只会执行一次
书写
1 | static{ |
常见应用场景
- 可完成类的初始化,例如:对静态变量的初始赋值
实例代码块
特点
- 每次创建对象时都会执行,且在构造器前执行
书写
1 | {} |
常见应用场景
- 和构造器一样都是用来完成对象的初始化的,例如,对实例变量进行初始化赋值
内部类
定义在另外一个类中的类就是内部类
当一个类的内部,包含了一个完整的事物,且这个事物没有必要单独设计时,可以把这个事物设计成内部类
成员内部类
特点
- 就相当于类中的普通成员
- 无static修饰,属于外部类的对象持有
- 成员内部类可以直接访问外部类的静态成员,也可以直接访问外部类的实例成员
- 使用this关键字获取当前内部类的对象,使用外部类.this获取外部类的对象
书写
1 | public class 外部类名{ |
静态内部类
特点
- 有static修饰的内部类
- 区别与成员内部类,静态内部类是外部类本身持有的
- 静态内部类访问外部类的静态成员,而不可以访问外部类的实例成员
书写
1 | public class 外部类名{ |
匿名内部类
特点
- 特殊的局部内部类
- 这个类不需要命名,一般有个默认的隐藏名字
- 本质上是子类,并会立即创建出一个对象
书写
1 | new 类或者接口(参数列表){ |
常见应用场景
- 方便地创建一个子类对象
- 只想用一次,不值得专门写一个类
- 常见于回调、监听器、线程任务等
- 通常作为对象参数传递给方法使用
函数式编程
Lambda
特点
Lambda 表达式 是 定义函数的语法
Lambda 函数 是 表达式运行后生成的函数对象
- Lambda不是可以简化所有匿名内部类,而是只能简化函数式接口的匿名内部类
- Lambda函数可以简化某些匿名内部类对象,从而让代码更简洁,可读性更好
函数式接口:只有一个抽象方法的接口,可以用
@FunctionalInterface注解检查
书写
1 |
|
Lambda表达式省略规则
- 参数类型可以全部不写
1
2
3(String s) -> System.out.println(s);
// 等价于
(s) -> System.out.println(s); - 如果只有一个参数,可以省略(),但是多个参数不可以省略()
1
s -> System.out.println(s);
- 如果Lambda表达式中只有一行代码,大括号可以省略,但是同时也要省略;,如果这行语句是return,也必须去掉return
1
2
3s -> System.out.println(s)
(a, b) -> a + b
方法引用:简化Lambda表达式
静态方法引用
书写
1 | 类名::静态方法 |
常见使用场景
- 若Lambda表达式里只是调用
一个静态方法,并且->前后参数的形式一致,就可以使用静态方法引用
实例方法引用
书写
1 | 对象名::实例方法 |
常见使用场景
- 如果某个Lambda表达式只是通过对象名称调用
一个实例方法,并且->前后参数的形式一致,就可以使用实例方法引用
特定类的方法引用
书写
1 | 类型名称::方法 |
场景使用场景
- 若某个Lambda表达式中只是调用以特定类的实例方法,并且前面参数列表中第一个参数是作为方法的主调,后面的所有参数都是作为该实例方法的入参的,则此时就可以使用特定类的方法引用
主调:如(a1,a2) -> a1.func(a2) 则a1就是主调
常用API
String
创建字符串对象的方式
方式一:Java程序中所有的字符串文字都为此对象
方式二:调用String类的构造器初始化字符串对象
| 构造器 | 说明 |
|---|---|
| public String() | 创建一个空字符串对象,不含任何内容 |
| public String(String original) | 根据传入的字符串内容,来创建字符串对象 |
| public String(char[] chars) | 根据字符数组内容,创建字符串对象 |
| public String(byte[] bytes) | 根据字节数组内容,创建字符串对象 |
两种方式区别
- 使用””创建的字符串对象会存入字符串常量池中,相同字符串一个地址,只存储一份
- 使用构造器创建的对象,每new一次就会产生一个新的字符串对象存储在堆内存中
String提供的常用方法
| 方法名 | 说明 |
|---|---|
| public int length() | 获取字符串的长度 |
| publi char charAt(int) | 返回某个索引的字符 |
| public cgar[] toCharArray() | 将当前字符串变成字符数组 |
| public boolean equals(Object) | 与另一个字符串内容一样返回true |
| public boolean equalsIgnoreCase(String) | 与上面比,忽略大小写 |
| public String substring(int,int) | 返回索引区间字符串(包前不包后) |
| public String substring(int) | 返回从索引处开始到末尾的字符串 |
| public String replace(CharSequence,CharSequence) | 使用新值,将字符串内的旧值替换 |
| public boolean contains(CharSequence) | 判断字符串中有没有包含某个字符串 |
| public boolean startsWith(String) | 判断是不是以某个字符串开头 |
| public String[] split(String) | 以某字符串作为分割 |
==比较的是地址,equals比较的是内容
ArrayList
是集合容器
创建方式
1 | ArrayList<E> 名称 = new ArrayList<>() //创建空的集合对象 |
ArrayList提供的常用方法
| 常用方法名 | 说明 |
|---|---|
| public boolean add(E) | 将指定的元素添加到集合末尾 |
| public void add(int,E) | 在集合指定索引处插入指定位置 |
| public E get(int) | 返回指定索引处的元素 |
| public int size() | 返回集合中元素个数 |
| public E remove(int) | 删除并返回指定索处的元素 |
| public boolean remove(Object) | 删除指定元素,判断是否成功 |
| public E set(int,E) | 修改指定索引的元素,返回被修改的元素 |
异常
两个分支RuntimeException和编译时异常,前者编译阶段不会报错,如数组越界
处理异常
- 方法上使用throws关键字,可以将异常抛给调用者
- try…catch捕获异常
1 | 方法 throws 异常1,异常2,...{} |
- 方案一:底层异常往上抛,最外层捕获异常
- 方案二:最外层捕获异常之后,尝试重新修复
异常作用
- 是定位bug的重要信息
- 可以作为方法内部的特殊返回值,以便通知上层调用者,方法的执行问题
自定义异常
Java无法为所有的问题都定义异常
自定义运行时异常
类继承自
RuntimeException
重写构造器,通过throw new 异常类(*)来创建对象并抛出
有参构造器使用super调用父类的构造器
特点:编译时不报错,运行时可能出现
自定义编译时异常
类继承自
Exception
重写构造器,通过throw new 异常类(*)来创建对象并抛出
有参构造器使用super调用父类的构造器
特点:编译时就会报错
泛型
作用
- 泛型提供了在编译阶段约束所能操控的数据类型,并自动进行检查的能力,可以避免强制类型转换,极其可能出现的异常
泛型类
1 | 修饰符 class 类名<类型变量,类型变量,...>{} |
泛型接口
实现类对每个函数传入值类型不尽相同,用泛型可以提高灵活性
1 | 修饰符 interface 接口名<类型变量,类型变量,...>{} |
泛型方法
1 | 修饰符 <类型变量,类型变量,...> 返回值类型 方法名(形参){} |
通配符
- 即”?”,可以在
使用泛型时代表一切类型,E T K V是在定义泛型的使用使用泛型指在已有的类的情况下使用泛型
泛型上下限
- 泛型上限: ?extends 类名A ?能接收的必须是A类及其
子类 - 泛型下限: ?super 类名B ?能接收的必须是B类及其
父类
泛型支持的数据类型
泛型和集合不支持8种基本数据类型,只支持对象数据类型(引用数据类型)
可以使用包装类
| 基本数据类型 | 引用数据类型 |
|---|---|
| byte | Byte |
| short | Short |
| int | Integer |
| long | Long |
| char | Character |
| float | Float |
| double | Double |
| boolean | Boolean |
Integer.valueOf()函数会缓存-128到127,在这个区域内不用new新对象,而超过这个区域则会new新对象
int转String:Integer.toString(int)String转int:Integer.valueOf(String)
转其他基本数据类型也是,
引用数据类型.valueOf()
Stream流
Stream 不是集合,它不会存储数据,而是对数据进行 计算/操作 的一种抽象。
结合了Lambda表达式
数据源 → Stream 流操作 → 结果。
使用步骤:获取Stream流,然后使用流的各种方法处理数据,最后收集
获取Stream流
1 | /** |
Map集合拿Stream流:
1 | // 获取键流 |
Stream流常用方法
调用后会返回新的流
| 常用中间方法 | 说明 |
|---|---|
Streamfilter(Predicate<? super T> predicate) | 用于将流中的数据过滤 |
Streamsorted() | 对元素进行升序排序 |
Streamsorted(Comparator<? super T> comparator) | 按照指定规则排序 |
Streamlimit(long maxSize) | 获取前几个元素 |
Streamskip(long n) | 跳过前几个元素 |
Streamdistinct() | 去除流中的重复元素 |
map(Function<? super T,? extends R> mapper) | 对元素进行加工,并返回对应的新流 |
staticconcat(Stream a,Stream b) | 合并两个流为一个流 |
Stream的终结方法
调用之后返回的不是流了
| 常用终结方法 | 说明 |
|---|---|
void forEach(Consumer action) | 对流运算后的元素进行遍历 |
long count() | 统计对流运算后的元素个数 |
Optionalmax(Comparator<? super T> comparator) | 对流运算后的最大值元素 |
Optionalmin(Comparator<? super T> comparator) | 对流运算后的最小值元素 |
max、min返回的可能是空的,所以要放在Optional中,使用返回值.get()即可得到值
终结方法::收集Stream流
收集Stream流:将流操作后的结果转回到集合或者数组中
| Stream提供的常用终结方法 | 说明 |
|---|---|
R collect(Collector collctor) | 把流处理后的结果放到指定集合 |
| Object[] toArray() | 把流处理后的结果放到数组 |
| Collectors的具体收集方式 | 说明 |
|---|---|
public staticCollector toList() | 元素收集进List集合 |
public staticCollector toSet() | 元素收集进Set集合 |
public static Collector toMap(Function keyMapper,Function valueMapper) | 元素收集进Map集合 |
可变参数
书写
定义在方法、构造器的形参列表中
1 | 数据类型...参数名称 |
作用
- 可以表示0个或者多个相同类型的数据给它,也可以传一个数组给它
- 灵活的接受数据,可以替代数组传参
- 这种参数在方法体内变成数组形式
File
File类对象可以代表
文件或者文件夹
创建File对象
| 构造器 | 说明 |
|---|---|
| public File(String path) | 根据文件路径创建对象 |
| public File(String parent,String child) | 根据父路径和子路径创建 |
| public File(File file,String child) | 根据父路径对应文件和子路径名字创建 |
- 创建时不管路径到底有没有对应的文件或文件夹
判断文件类型获取文件信息
| 方法名称 | 说明 |
|---|---|
| public boolean exists() | 判断当前对象对应文件路径是否存在 |
| publi boolean isFile() | 判断当时文件对象对应的是否为文件 |
| public boolean isDirectory() | 判断当时文件对象对应的是否为目录 |
| public getName() | 获得当前文件名称(包含后缀) |
| public long length() | 获取文件大小。返回字节个数 |
| public long lastModified() | 获取文件最后修改时间 |
| public String getPath() | 获取创建文件对象时使用的路径 |
| public String getAbsolutePath() | 获取绝对路径 |
创建删除文件/文件夹
| 方法名称 | 说明 |
|---|---|
| public boolean createNewFile() | 创建一个新的空文件 |
| public boolean mkdir() | 创建一个空目录 |
| public boolean mkdirs() | 创建一个多级空目录 |
| public boolean delete() | 删除文件、空文件夹 |
delete默认只能删除文件和空文件夹,删除后不会进入回收站
遍历文件夹
只能遍历
一级文件夹
| 方法名称 | 说明 |
|---|---|
| public String[] list() | 获得一级文件夹下所有文件名称 |
| public File[] ListFiles() | 获得一级文件夹下所有的文件对象 |
ListFiles注意事项:
- 文件的对象调用或者路径不存在时,返回null
- 文件夹为空时返回空数组
- 文件夹里面有内容时,返回所有一级文件和文件夹的路径放在数组中
- 有隐藏文件时也会返回
- 无权访问文件夹时,返回null
字符集
ASCII字符集
- 一个字节存储一个字符
- 只有数字英文符号
- 字节首位是0
- 由于很多字符集都兼容了ASCII码,所以一般不会乱码
GBK
- 中文字符两个字符
- 中文字符首位必须是
1 - 数字。英文是一个字符
Unicode >> UTF-8
可变长编码方案
分为4个长度区:1,2,3,4个字节
- 英文数字占
1个字节 - 中文占
3个字节
UTF-8 二进制编码方式:
- 自上而下分别是1字节、2字节、3字节、4字节长度区间
- 去掉前缀码后剩下的位置会被对应字符填充,左边多的地方补充为0
0xxxxxxx (ASCII码)110xxxxx 10xxxxxx1110xxxx 10xxxxxx 10xxxxxx11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
编码和解码
| 方法名称 | 说明 |
|---|---|
| byte[] getBytes(String CharsetName) | 按字符集编码,CharsetName为空时是默认字符集 |
| String(byte[],String CharsetName) | 按字符集解码,CharsetName为空时是默认字符集 |
IO流
按流方向分:
input流,负责将数据读到内存
output流,负责写数据出去
按流内容分:
字节流,适合操作所有文件
字符流,适合操作纯文本文件,如果txt文件、java文件
IO流四大类:
- 字节输入流(InputStream)
- 字节输出流(OutputStream)
- 字符输入流(Reader)
- 字符输出流(Writer)
FileInputStream(文件字节输入流)
以内存为基准,可以将磁盘文件中数据以字节的形式送到内存
创建文件字节输入流管道与源文件接通
- public FileInputStream(File file)
- public FileInputStream(String filePath)
每次读取一个字节,若无字节返回
-1- public int read()
- 每次用
一个字节数组读取数据,返回数组读取多少个字节,没有数据可读会返回-1- public int read(byte[] bs)
FileOutputStream(文件字节输出流)
以内存为基准,可以将内存中数据以字节的形式送到磁盘文件
创建文件字节输出流管道与源文件接通
- public FileOutputStream(File file)
- public FileOutputStream(String filePath)
创建文件字节输出流管道与源文件接通,
可追加数据- public FileOutputStream(File file,
boolean append) - public FileOutputStream(String filePath,
boolean append)
- public FileOutputStream(File file,
写一个字节出去
- public void write(int a)
写一个字节数组出去
- public void write(byte[] buffer)
写一个字节数组的一部分出去
- public void write(byte[] buffer,int pos,int len)
关闭流
- public void close() throws IOException
可以输入
"\r\n".getByte()实现换行
多线程
创建线程 - 继承Thread类
- 通过继承Thread类,然后覆写run方法
- 创建该类对象
- 调用对象的start方法启动线程
优缺点
- 简单
- 已经继承了Thread类,不能继承其他类,不利于功能扩展
调用start才是启动子线程,直接调用run还是单线程
创建线程 - 实现Runnable接口
- 通过实现Runnable接口,然后覆写run方法
- 创建该类任务对象
- 任务对象传给Thread类构造其线程对象
- 调用后面构造的线程对象的start方法启动线程
优缺点
- 任务类只是实现接口,还能实现其他接口和继承其他类,扩展性强
- 需要多一个Runnable对象
可以用匿名内部类方法简化,Runnable是典型的函数式接口
创建线程 - 利用Callable接口、FutureTask类实现
上面两种run方法都不能返回结果,若使用静态变量存储结果,不能保证读取变量时子线程运行完毕
- 创建任务对象
- 定义一个类实现Callable接口,重写call方法,封装要做的事情和返回的数据
- 把Callable类型的对象封装成FutureTask(线程任务对象)
- 把线程任务对象交给Thread对象
- 调用Thread类的start函数启动线程
- 线程执行完毕后通过FutureTask对象的get方法去获取线程任务执行的结果
get方法会阻塞当前线程,直到有返回
优缺点:
- 实现的是接口,而且可以获取线程执行完毕后的结果
- 编码稍复杂




