JAVA环境
JVM:java虚拟机
加载.class并运行.class
JRE:java运行环境
除了包含JVM以外还包含了运行java程序所必须的环境
JRE = JVM+java系统类库(小零件)
JDK:java开发工具包
除了包含JRE以外还包含了开发java程序所必须的命令工具
JDK = JRE+编译、运行等命令工具
IDE:集成开发环境
一整套带图形界面的功能强大的工具,目前最流行的IDE叫Idea
JAVA基础
变量
对变量的使用就是对它所存的那个数的使用
变量在使用之前必须声明并初始化
只能包含字母、数字、_和$符,并且不能以数字开头
严格区分大小写
不能使用关键字
允许中文命名,但不建议,建议"英文的见名知意"、"小驼峰命名法"
当作用域重叠时,变量不能同名
八种基本数据类型
int 整型
4个字节,-21个多亿到21个多亿
整数直接量默认为int类型,但不能超出范围,若超范围则发生编译错误
两个整数相除,结果还是整数,小数位无条件舍弃(不会四舍五入)
运算时若超范围会发生溢出,溢出不是错误,但需要避免
long 长整型
8个字节,很大很大很大
长整型直接量需要数字后加L或l
运算时若有可能溢出,建议在第1个数字后加L
double 浮点型
8个字节,很大很大很大
浮点数直接量默认为double型,若想表示float则需在数字后加F或f
double或float型数据运算时,有可能会发生舍入误差,精确场合不能使用。推荐使用BigDecimal来计算准确,而且BigDecimal使用string来存储的,所以内存足够大就有更大的取值范围
boolean 布尔型
1个字节
只能取值为true或false
char 字符型
2个字节
采用Unicode编码格式,一个字符对应一个码。表现的形式是字符char,但本质上是码int(0到65535之间)ASCII码:'a'---97 'A'---65 '0'---48
字符直接量必须放在单引号中,只能装1个
特殊符号需要通过\来转义
类型间的转换
数据类型由小到大依次为:byte,short,int,long,float,double,char
两种方式:
自动/隐式类型转换:小类型到大类型
强制类型转换:大类型到小类型,强转有可能溢出或丢失精度
两点规则:
整数直接量可以直接给byte,short,char赋值,但不能超范围
byte,short,char型数据参与运算时,系统会自动将其统一转换为int再运算
内存单位换算
1G=1024M(兆)
1M=1024KB(千字节)
1KB=1024B(字节)
1B=8bit(位)
运算符
算术:+、-、*、/、%、++、--
关系:>、<、>=、<=、==、!=
逻辑:&&、||、!
赋值:=、+=、-=、*=、/=、%=
三目:boolean?数1:数2
字符串连接:+
若两边为数字,则做加法运算
若两边出现了字符串,则做字符串连接
分支结构
if结构:1条路
if...else结构:2条路
if...else if结构:多条路
switch...case结构:多条路(可以作用于:byte,short,int,char,String,枚举类型,其它类型都是不允许的)
循环结构
while结构:先判断后执行,有可能一次都不执行
do...while结构:先执行后判断,至少执行一次
for结构:应用率最高,与次数相关的循环
break:跳出当前层的循环
continue:跳过循环体中剩余语句而进入下一次循环
增强型for循环,JDK5之后推出的一个特性,它可以用相同的语法遍历集合或数组
基本类型数组
是一种数据类型(引用类型)
相同数据类型元素的集合
初始化
int[] arr = new int[3]; //0,0,0
int[] arr = {1,4,7}; //1,4,7
int[] arr = new int[]{1,4,7}; //1,4,7
int[] arr;
arr = {1,4,7}; //编译错误,此方式只能声明同时初始化
arr = new int[]{1,4,7}; //正确
访问
通过数组名.length可以获取数组的长度(元素的个数)
通过下标/索引来访问数组中的元素,下标从0开始,最大到(数组的长度-1)
遍历/迭代:从头到尾挨个走一遍(for循环)、
复制
System.arraycopy(a,1,b,0,4);
int[] b = Arrays.copyOf(a,6);
若目标数组的长度>源数组长度,则在末尾补默认值
若目标数组的长度<源数组长度,则将末尾的截掉
排序
Arrays.sort(arr); 只有升序排序
内存图
![](https://i-blog.csdnimg.cn/blog_migrate/c265d2620ed95ef39a1ae888e5dce566.png)
方法
概念
封装一段特定的业务逻辑功能
尽可能独立,一个方法只干一件事
方法可以被反复调用多次
可以减少代码重复,有利于代码维护
假设有一个功能,在很多地方都得使用,就将功能封装到一个方法中
定义
修饰词 返回值类型 方法名(参数列表) {
方法体
}
调用
无返回值:方法名(有参传参);
有返回值:数据类型 变量 = 方法名(有参传参);
return
return 值; //1)结束方法的执行 2)返回结果给调用方-------用在有返回值的方法中
return; //1)结束方法的执行------------------------------------用在无返回值的方法中
参数
形参:形式参数----定义方法时的参数叫做形参
实参:实际参数----调用方法时的参数叫做实参
Package
作用:避免类的命名冲突
同包中的类不能同名,但不同包中的类可以同名
类的全称:包名.类名,包名常常有层次结构
建议:包名所有字母都小写
使用import导入包
同包中的类可以直接访问
不同包中的类不能直接访问,若想访问:
先import导入类再使用类------------建议
类的全称----------------------------------太繁琐,不建议
访问控制修饰符
public:公开的,任何类
protected:受保护的,本类、子类、同包类
默认的:什么也不写,本类、同包类
private:私有的,本类
final关键字
修饰变量:变量不能被改变
final修饰实例变量,必须声明同时初始化或在构造方法中初始化,否则编译错误
final修饰局部变量,只要在使用之前初始化即可
修饰方法:方法不能被重写
修饰类:类不能被继承
static关键字
静态变量:
属于类,存储在方法区中,一份
常常通过类名点来访问
何时用:所有对象所共享的数据(图片、音频、视频等)
内存图
![](https://i-blog.csdnimg.cn/blog_migrate/90517a27cd11f0b4e984003bcfd4fcee.png)
静态方法:
属于类,存储在方法区中,一份
常常通过类名点来访问
静态方法中没有隐式this传递,所以只能直接访问静态成员,而不能直接访问实例成员
何时用:方法的操作与对象无关----方法中不需要访问对象的属性或行为
静态块:
属于类,在类被加载时自动执行,因为一个类只被加载一次,所以静态块也只执行一次
何时用:加载/初始化静态资源(图片、音频、视频等)
static final常量
必须声明同时初始化
由类名打点来访问,不能被改变
建议:常量所有字母都大写,多个单词用_分隔
编译器在编译时会将常量直接替换为具体的数,效率高
何时用:数据永远不变,并且经常使用
字符集
utf-8:其中中文字3字节表示1个,英文1字节表示1个
序列化和反序列化
对象序列化:将一个java对象按照其结构转换为一组字节的过程
对象反序列化:将一组字节还原为java对象(前提是这组字节是一个对象序列化得到的字节)
transient关键字可以修饰属性,用于在进行对象序列化时忽略不必要的属性,达到对象瘦身的目的
泛型
JDK5之后推出的另一个特性
泛型在集合中被广泛使用,用来指定集合中的元素类型.
有泛型支持的类在使用时若不指定泛型的具体类型则默认为原型Object
面向对象
面向对象简述
OO:面向对象
OOA:面向对象分析
OOD:面向对象设计
OOP:面向对象编程
类和对象
对象:软件中真实存在的单个个体/东西。类:类型/类别,代表一类个体
类是对象的模板/模子,对象是类的具体的实例
类中可以包含:
对象的属性/特征-----------------------------成员变量
对象的行为/动作/功能----------------------方法
一个类可以创建多个对象
引用数据类型 引用类型变量 指向 对象
Student zs = new Student();
包装类
java定义了8个包装类,目的就是为了解决基本类型不能直接参与面向对象开发的问题,使得基本类型可以通过包装类的形式存在。
包括:Integer、Character、Byte、Short、Long、Float、Double、Boolean,其中Character和Boolean是直接继承自Object的,而其余6个包装类继承自java.lang.Number类。
JDK1.5推出了一个新的特性:自动拆装箱,当编译器编译时若发现是基本类型与包装类型之间相互赋值,将自动补充代码来完成转换工作,这个过程称为自动拆装箱。
方法的签名
方法名+参数列表
方法的重载(overload/overloading)
作用:方便用户的调用
发生在同一类中,方法名相同,参数列表不同
编译器在编译时会根据方法的签名自动绑定方法
方法的重写(override/overriding)
重写方法被调用时,看对象的类型-----------------------这是规定,记住就OK
重写需遵循"两同两小一大"原则
两同
方法名相同
参数列表相同
两小
派生类方法的返回值类型小于或等于超类方法的
void和基本类型时,必须相等
引用类型时,小于或等于
子类方法抛出的异常小于或等于父类方法抛出的异常
一大
子类方法的访问权限大于或等于父类方法的
构造方法
作用:给成员变量赋初值
与类同名,没有返回值类型(连void都没有)
在创建(new)对象时被自动调用
若自己不写构造方法,编译器默认提供一个无参构造方法,若自己写了构造方法,则不再默认提供
构造方法可以重载
this关键字
指代当前对象,哪个对象调用方法它指的就是哪个对象,只能用在方法中,方法中访问成员变量之前默认有个this
this的用法
this.成员变量名-----访问成员变量,当成员变量与局部变量同名时,若想访问成员变量,则this不能省略
this.方法名()--------调用方法(一般不用)
this()----------------调用构造方法(一般不用)
内部类中使用外部类的对象用类名.this
null关键字
表示空,没有指向任何对象
若引用的值为null,则该引用不能进行任何点操作了,若操作则发生NullPointerException空指针异常。
成员变量和局部变量
成员变量和局部变量是可以同名的,使用的时候默认采取的是就近原则
成员变量分两种:
实例变量:没有static修饰,属于对象的,存储在堆中,有几个对象就有几份,通过对象/引用打点来访问
静态变量:有static修饰,属于类的,存储在方法区中,只有一份,常常通过类名点来访问
引用类型数组
给元素赋值时,需要new个对象存入数组中,若元素不赋值,则默认值为null,容易发生空指针异常
若想访问对象的数据,需要通过数组元素去打点来访问
内存图
![](https://i-blog.csdnimg.cn/blog_migrate/a3b03fb2fca864df80afe1febca3e724.png)
抽象方法
由abstract修饰
只有方法的定义,没有具体的实现(连{}都没有)
抽象类
由abstract修饰
包含抽象方法的类必须是抽象类
抽象类不能被实例化(new对象)
抽象类是需要被继承的,子类:
重写抽象方法---------------变不完整为完整
也声明为抽象类------------一般不这么用
抽象类的意义:
封装共有的属性和行为-------------------代码复用
为所有子类提供统一的类型----------向上造型(代码复用)
可以包含抽象方法,为所有子类提供统一的入口(向上造型后能点出来),同时可以达到强制必须重写的目的(相当于制定了一个标准)
匿名内部类
何时用:若想创建一个子类的对象,并且对象只被创建一次,可以设计为匿名内部类,可以大大简化代码操作
在匿名内部类中不能修改外面局部变量的值,因为在此处该变量会被默认为final的
接口
是一种数据类型(引用类型)
由interface定义
JDK1.8以前只能包含常量和抽象方法(所有数据默认都是常量,所有方法默认都是抽象的)。JDK1.8以后可以包含实现方法
接口不能被实例化
接口是需要被实现/继承的,实现/派生类:必须重写所有抽象方法
一个类可以实现多个接口,用逗号分隔。若又继承又实现时,应先继承后实现。
接口可以继承接口
继承
作用:代码复用
通过extends来实现继承
父类:共有的属性和行为
子类:特有的属性和行为
子类可以访问子类的+父类的属性和方法,但父类不能访问子类的
一个父类可以有多个子类,但一个子类只能继承一个父类-----------单一继承
继承具有传递性
java规定:构造子类之前必须先构造父类
在子类的构造方法中若没有调用父类的构造方法,则默认super()调用父类的无参构造方法
在子类的构造方法中若自己调用了父类的构造方法,则不再默认提供
super()调用父类构造方法,必须位于子类构造方法的第一行
super:指代当前对象的父类对象
super.成员变量名-------------------------访问超类的成员变量
super.方法名()-----------------------------调用超类的方法
super()---------------------------------------调用超类的构造方法
多态
同一个对象被造型为不同的类型时,有不同的功能-------对象的多态
对象的多态:水、我、你......
同一个类型的引用在指向不同的对象时,有不同的实现----行为多态的
行为的多态:cut()、getImage()、move()......
向上造型/自动类型转换:
超类型的引用指向派生类的对象------前面是超类型,后面是派生类型
能点出来什么,看引用的类型
能造型成为的数据类型:超类+所实现的接口
强制类型转换,成功的条件只有两种:
引用所指向的对象,就是该类型
引用所指向的对象,实现了该接口或继承了该类
强转时若不满足如上条件,则发生ClassCastException类型转换异常。建议:在强转之前先通过instanceof来判断引用指向的对象是否是该类型
面向对象三大特征总结
封装:
类:封装的是对象的属性和行为
方法:封装的是具体的业务逻辑功能实现
访问控制修饰符:封装的是具体的访问权限
继承:
作用:代码复用
各种继承形态
超类:所有派生类所共有的属性和行为
接口:部分派生类所共有的属性和行为
派生类:派生类所特有的属性和行为
单一继承、多接口实现,具有传递性
多态:
对象以及方法的多态
所有对象都是多态的,通过向上造型来体现
所有抽象方法都是多态的,通过方法的重写来体现
向上造型、强制类型转换、instanceof判断
类的设计规则
将子类所共有的属性和行为,抽到父类中-------------抽共性
若子类的行为(实现代码)都一样,设计为普通方法
若子类的行为(实现代码)都不一样,设计为抽象方法
将部分派生类所共有的属性和行为,抽到接口中
接口是对继承的单根性的扩展--------------实现多继承
接口是一个标准、一种规范,实现了接口就能干某件事,不实现接口就干不了那个事
程序的执行过程
超类的static块
派生类的static块
超类的构造方法
派生类的构造方法
进制
十进制
规则:逢10进1
数字:0 1 2 3 4 5 6 7 8 9
基数:10
权:万 千 百 十 个
二进制
规则:逢2进1
数字:0 1
基数:2
权:128 64 32 16 8 4 2 1
十六进制
规则:逢16进1
数字:0 1 2 3 4 5 6 7 8 9 a b c d e f
基数:16
权:65536 4096 256 16 1
用途:因为2进制书写太麻烦,所以常常用16进制来缩写2进制
进制转换
二进制转换为十进制的规则:所有为1的权相加
权: 32 16 8 4 2 1
2进制: 1 1 0 1 0 1
10进制: 32+16+4+1---------------53
二进制转换为十六进制的规则:将2进制从低位开始,每4位2进制缩为1个16进制(每4位1缩)
权: 8 4 2 1
2进制: 0011 1010 1011 1010 1011
16进制: 3 a b a b--------3abab
补码
计算机处理有符号数(正负数)的一种编码方式
以4位2进制为例讲解补码的编码规则:
计算的时候如果超出4位则高位自动溢出舍弃,保持4位不变
最高位称为符号位,高位为1是负数,高位为0是正数
位运算
取反:~
0变1,1变0
与运算:&
运算规则:逻辑乘法,见0则0
或运算:|
运算规则:逻辑加法,见1则1
右移位运算:>>>
运算规则:将2进制数整体向右移动,低位自动溢出舍弃,高位补
左移位运算:<<
运算规则:将2进制数整体向左移动,高位自动溢出舍弃,低位补0
JAVA基础API
String
java.lang.String类使用final修饰,不能被继承
String的底层封装的是一个字符数组
String在内存中采用Unicode编码格式,每个字符占用2个字节的空间
字符串对象一旦创建,对象内容永远无法改变,但字符串引用可以重新赋值(指向新的对象)
字符串常量池
java对String字符串有一个优化措施:字符串常量池(堆中)
编译器在编译时,若发现是两个字面量相连,则会直接连接好并将结果保存起来
String a = "abc" + "bcd;//编译时候会变成String a = "abcbdc"同时存入常量池
java推荐我们使用字面量/直接量(直接"")的方式来创建对象,并且会缓存所有以字面量形式创建的字符串对象到常量池中,当使用相同字面量再创建对象时将会复用常量池中的对象,以减少内存开销
![](https://i-blog.csdnimg.cn/blog_migrate/bd88e03b263bbd81e4088484c70b233e.png)
String的常用方法:
length():获取字符串的长度(字符个数)
trim():去除当前字符串两边的空白字符
toUpperCase()/toLowerCase():将当前字符串中的英文部分给转换为全大写/全小写
startsWith()/endsWith():判断当前字符串是否是以给定的字符串开始的/结束的
charAt():返回当前字符串指定位置上的字符----根据位置找字符
indexOf()/lastIndexOf():检索给定字符串在当前字符串中第一次/最后一次出现的位置,根据字符串找位置
substring():截取当前字符串中指定范围内的字符串(含头不含尾--包含start,但不包含end)
静态方法valueOf():将其它数据类型转换为String
matches():使用给定的正则表达式(regex)验证当前字符串的格式是否符合要求,符合则返回true,否则返回false
replaceAll():将当前字符串中满足正则表达式(regex)的部分给替换为给定的字符串(s)
split():将当前字符串按照满足正则表达式的部分进行拆分,将将拆分出的以String[]形式来返回
byte[] getBytes(String charsetName) 将当前字符串转换为一组字节,参数为字符集的名字,常用的是UTF-8。
StringBuilder
由于String是不变对象,每次修改内容都会创建新的对象,因此String不适合频繁修改操作,为了解决这个问题,java提供了StringBuilder类。
StringBuilder是专门用于修改字符串的一个类,内部维护一个可变的char数组,所做操作都是在这个数组之上进行的,修改速度、性能非常优秀,并且提供了修改字符串的常见方式:增、删、改、插
非线程安全的,并发处理的,性能稍快
StringBuilder的常用方法:
append():增加内容-----------------增
delete():删除部分内容-------------删
replace():替换部分内容-----------改
insert():插入内容--------------------插
toString():转为String对象
StringBuffer
线程安全的,同步处理的,性能稍慢
File
File类的每一个实例可以表示硬盘(文件系统)中的一个文件或目录(实际上表示的是一个抽象路径)
路径的格式
相对路径:相对路径的好处在于有良好的跨平台性
"./"是相对路径中使用最多的,表示"当前目录",而当前目录是哪里取决于程序运行环境而定,默认就是在当前目录下
绝对路径:文件的全路径
使用File的功能:
访问其表示的文件或目录的属性信息,例如:名字,大小,修改时间等等
创建和删除文件或目录
访问一个目录中的子项
但是File不能访问文件数据
常用方法
createNewFile()方法,可以创建一个新文件
delete():删除当前文件或目录,如果目录不是空的则删除失败。
mkDir():创建当前File表示的目录,要求父目录必须存在
mkDirs():创建当前File表示的目录,同时将所有不存在的父目录一同创建
listFiles()方法可以访问一个目录中的所有子项
isFile()是否为一个文件
isDirectory()是否为一个目录
listFiles(FileFilter filter)获取目录中符合特定条件的子项
exists():判断File表示的文件或目录是否真实存在。true:存在 false:不存在
isHidden():File表示的文件或目录是否为隐藏的
canRead():File表示的文件或目录是否可读
canWrite():File表示的文件或目录是否可写
length():返回一个long值,表示占用的磁盘空间,单位为字节
IO
java io可以让我们用标准的读写操作来完成对不同设备的读写数据工作.
java流的划分
按照方向
输入:用来读取数据的,是从外界到程序的方向,用于获取数据.
输出:用来写出数据的,是从程序到外界的方向,用于发送数据.
按照传输数据形式
字节流:java.io.InputStream和java.io.OutputStream
字符流:java.io.Writer和java.io.Reader
按照分工
低级流:低级流的另一端是明确的,是实际读写数据的流,读写一定是建立在低级流基础上进行的,低级流都是字节流
高级流:不能独立存在,必须连接在其他流上,目的是当数据流经当前流时对数据进行加工处理
文件流
文件流是一对低级流和字节流,用于读写文件数据的流.用于连接程序与文件(硬盘)的"管道".负责读写文件数据.
构造方法:
对于FileOutputStream会在创建时将该文件创建出来(如果该文件不存在才会这样做),自动创建该文件的前提是该文件所在的目录必须存在,否则会抛出异常
FileOutputStream(String filename) 若文件已经存在则会覆盖
FileOutputStream(File file)若文件已经存在则会覆盖
FileOutputStream(String filename,boolean append)若为true则会追加
FileOutputStream(File file,boolean append)若为true则会追加
FileInputStream(String pathname) 如果指定的文件不存在则会抛出异常
FileInputStream(File file)如果指定的文件不存在则会抛出异常
方法
void write(int d) 将int值对应的2进制的"低八位"写如到文件第一个字节位置上
例如fow.write(1)
1个int值占4个字节,每个字节是一个8为2进制
int 1的2进制样子:00000000 00000000 00000000 00000001
write方法调用后,文件中就有了1个字节,内容为:00000001
int read()读取1个字节并以int型整数返回读取到的字节内容,返回的int值中对应的2进制的"低八位"就是读取到的数据。如果返回的int值为整数-1(这是一个特殊值,32位2进制全都是1)表达的是流读取到了末尾了。
例如int d = fis.read();
该int值d对应的2进制:00000000 00000000 00000000 00000001自动补充24个0
读取到的数据2进制对应的整数就是1.
int read(byte[] data) 一次性从文件中读取给定的字节数组总长度的字节量,并存入到该数组中。 返回值为实际读取到的字节量。若返回值为-1则表示读取到了文件末尾。
void write(byte[] data) 一次性将给定的字节数组所有字节写入到文件中
void write(byte[] data,int offset,int len) 一次性将给定的字节数组从下标offset处开始的连续len个字节写入文件
缓冲字节流
java.io.BufferedOutputStream和BufferedInputStream.
缓冲流是一对高级流和字节流,作用是提高读写数据的效率
缓冲流内部有一个字节数组,默认长度是8K.缓冲流读写数据时一定是将数据的读写方式转换为块读写来保证读写效率.
通过缓冲流写出的数据会被临时存入缓冲流内部的字节数组,直到数组存满数据才会真实写出一次
方法
flush()当write方法调用后并非实际写出,而是先将数据存入缓冲区(内部的字节数组中),当缓冲区满了时会自动写出一次性写出。
构造方法
BufferedOutputStream(OutputStream out):创建一个默认8kb大小缓冲区的缓冲字节输出流,并连接到参数指定的字节输出流上。
BufferedOutputStream(OutputStream out,int size):创建一个size指定大小(单位是字节)缓冲区的缓冲字节输出流,并连接到参数指定的字节输出流上。
BufferedInputStream(InputStream in):创建一个默认8kb大小缓冲区的缓冲字节输入流,并连接到参数指定的字节输入流上。
BufferedInputStream(InputStream in,int size):创建一个size指定大小(单位是字节)缓冲区的缓冲字节输入流,并连接到参数指定的字节输入流上。
对象流
java.io.ObjectOutputStream和ObjectInputSteam
对象流是一对高级流和字节流,在流连接中的作用是进行对象的序列化与反序列化。
处理的对象需要实现可序列化接口:java.io.Serializable
构造方法
ObjectInputStream(InputStream in):创建一个对象输入流并连接到参数in这个输入流上。
ObjectOutputStream(OutputStream out):创建一个对象输出流并连接到参数out这个输出流上
方法
readObject():进行对象反序列化,将读取的字节转换为一个对象并以Object形式返回(多态)。
writeObject(Object obj):进行对象的序列化,将一个java对象序列化成一组字节后再通过连接的输出流将这组字节写出。
转换流
OutputStreamWriter和InputStreamReader
衔接字符与字节流的,将字符和字节相互转换
转换流是高级流和字符流
打印流
PrintWriters是字符流和高级流
PrintWriter具有自动行刷出的缓冲字符输出流,实际开发中更常用.它内部总是会自动连接BufferedWriter作为块写加速使用.
构造方法
PrintWriter(File file)可以直接对文件进行写操作的构造器
PrintWriter(String filename)可以直接对文件进行写操作的构造器
PrintWriter(String filename,String charset)可以直接对文件进行写操作并且指定字符集
PrintWriter(Writer writer,boolean autoflush);println方法写出一行字符串后就会自动flush()一次,但是print方法和write方法写出字符串时并不会自动flush()
PrintWriter(OutputStream out):将PrintWriter链接在给定的字节流上(构造方法内部会自行完成转换流等流连接)
方法
println()方法是输出字符出后带上换行符
print()方法输出字符串后不带换行符
缓冲字符流
BufferedReader和BufferedWriter
缓冲字符流内部也有一个默认长度8k的char数组缓冲区,读写文本数据以块读写形式加快效率.并且缓冲流有一个特别的功能:可以按行读写文本数据.
缓冲字符流是高级流和字符流
方法
readLine()读取一行字符串。当我们第一次调用readLine()方法时,缓冲字符输入流实际会一次性读取8k的char 回来并存入内部的char数组中(块读文本操作)。readLine方法只将char数组中从头开始一直到第一个换行符位置的内容以一个字符串形式返回。
IO总结
![](https://i-blog.csdnimg.cn/blog_migrate/b06b3eaa866796b7e980d64c9433469f.png)
Throwable
java中所有错误的超类为:Throwable。其下有两个子类:Error和Exception
Throwable
Error
OutOfMemoryError(OOM)
Exception
IOException
FileNotFoundException
RuntimeException
NullPointerException(NPE)
IllegalArgumentException
ClassNotFoundException
ClassCastException
ArithmeticException
IndexOutOfBoundsException
ArrayIndexOutOfBoundsException
StringIndexOutOfBoundsException
JDK7之后在try的"()"中定义的并初始化的对象同时实现了java.io.AutoCloseable接口的对象编译期会自动实现流的关闭
throw用来对外主动抛出一个异常
throws当一个方法中使用throw抛出一个非RuntimeException的异常时,就要在该方法上使用throws声明这个异常的抛出。
编译器要求我们必须处理这个异常,处理手段有两种
使用try-catch捕获并处理这个异常
在当前方法上继续使用throws声明该异常的抛出给调用者解决。 具体选取那种取决于异常处理的责任问题。
子类重写超类含有throws声明异常抛出的方法时对throws的几种特殊的重写规则
可以不再抛出任何异常
可以仅抛出部分异常
可以抛出超类方法抛出异常的子类型异常
不允许抛出额外异常(超类方法中没有的,并且没有继承关系的异常)
不可以抛出超类方法抛出异常的超类型异常
为了避免抛出异常时有非常多复杂的语法约束,通常自定义的异常都会是RuntimeException的子孙类异常,这样就不需要主动的try..cash和在方法上添加throws
正则表达式
通常用于匹配一个字符串是否符合格式要求
正则表达式的语法
[]:表示一个字符,有限制范围,该字符范围是[]中指定的内容
[abc]:这个字符可以是a或b或c
[a-z]:表示任意一个小写字母
[a-zA-Z]:表示任意一个字母
[a-zA-Z0-9]:表示任意一个字母数字
[a-zA-Z0-9_]:表示任意一个数字字母下划线
[^abc]:该字符只要不是a或b或c
预定义字符:
.:表示任意一个字符,没有范围限制
\d:表示任意一个数字,等同于[0-9]
\w:表示任意一个单词字符,等同于[a-zA-Z0-9_]----单词字符指字母/数字/_
\s:表示任意一个空白字符
\D:表示不是数字
\W:不是单词字符
\S:不是空白字符
量词:
?:表示前面的内容出现0-1次
例如: [abc]? 可以匹配:a 或 b 或 c 或什么也不写
+:表示前面的内容最少出现1次
例如: [abc]+ 可以匹配:b或aaaaaaaaaa...或abcabcbabcbabcba....
但是不能匹配:什么都不写 或 abcfdfsbbaqbb34bbwer...
*:表示前面的内容出现任意次(0-多次)---匹配内容与+一致,只是可以一次都不写
例如: [abc]* 可以匹配:b或aaaaaaaaaa...或abcabcba....或什么都不写
但是不能匹配:abcfdfsbbaqbb34bbwer...
{n}:表示前面的内容出现n次
例如: [abc]{3} 可以匹配:aaa 或 bbb 或 aab 或abc 或bbc
但是不能匹配: aaaa 或 aad
{n,m}:表示前面的内容出现最少n次最多m次
例如: [abc]{3,5} 可以匹配:aaa 或 abcab 或者 abcc
但是不能匹配:aaaaaa 或 aabbd
{n,}:表示前面的内容出现n次以上(含n次)
例如: [abc]{3,} 可以匹配:aaa 或 aaaaa.... 或 abcbabbcbabcba....
但是不能匹配:aa 或 abbdaw...
()用于分组,是将括号内的内容看做是一个整体
例如: (abc){3} 表示abc整体出现3次. 可以匹配abcabcabc
但是不能匹配aaa 或abcabc
(abc|def){3}表示abc或def整体出现3次.
可以匹配: abcabcabc 或 defdefdef 或 abcdefabc
但是不能匹配abcdef 或abcdfbdef
Lambda表达式
JDK1.8以后支持的新特性
lambda可以用更精简的代码创建匿名内部类.但是该匿名内部类实现的接口只能有一个抽象方法,否则无法使用!
lambda表达式是编译器认可的,最终会将其改为内部类编译到class文件中
语法:(参数名)->{方法体}
lambda表达式中参数的类型可以忽略不写
lambda表达式方法体中若只有一句代码,则{}可以省略,如果这句话有return关键字,那么return也要一并省略!
线程
线程:一个顺序的单一的程序执行流程就是一个线程
主线程:执行main方法的线程
后台线程:也叫守护线程
守护线程是通过普通线程调用setDaemon(boolean on)方法设置而来的,因此创建上与普通线程无异.
当一个进程中的所有普通线程都结束时,进程就会结束,此时会杀掉所有正在运行的守护线程.
多线程:多个单一顺序执行的流程并发运行。当出现多个代码片段执行顺序有冲突时,希望它们各干各的时就应当放在不同线程上"同时"运行,一个线程可以运行,但是多个线程可以更快时,可以使用多线程运行
并发:多个线程实际运行是走走停停的。线程调度程序会将CPU运行时间划分为若干个时间片段并尽可能均匀的分配给每个线程,拿到时间片的线程被CPU执行这段时间。当超时后线程调度程序会再次分配一个时间片段给一个线程使得CPU执行它。如此反复。由于CPU执行时间在纳秒级别,我们感觉不到切换线程运行的过程。
多线程并发安全问题,当多个线程并发操作同一临界资源,由于线程切换时机不确定,导致操作临界资源的顺序出现混乱严重时可能导致系统瘫痪.临界资源:操作该资源的全过程同时只能被单个线程完成.
synchronized
在方法上修饰,此时该方法变为一个同步方法,即:多个线程不能同时 在方法内部执行.只能有先后顺序的一个一个进行. 将并发操作同一临界资源的过程改为同步执行就可以有效的解决并发安全问题.
同步块,可以更准确的锁定需要排队的代码片段
同步监视器对象
同步监视器对象即上锁的对象,要想保证同步块中的代码被多个线程同步运行,则要求多个线程看到的同步监视器对象是同一个.
在同步方法上使用synchronized,同步监视器对象不可指定,只能是this
在同步块上使用这个对象可以是java中任何引用类型的实例,必须是引用类型,多个需要同步执行该同步块的线程看到的该对象必须是同一个
当在静态方法上使用synchronized后,该方法是一个同步方法.由于静态方法所属类,所以一定具有同步效果.同步监视器对象也不可指定,只能是类对象(Class的实例).在JVM中,每个被加载的类都有且只有一个Class的实例与之对应
静态方法中使用同步块时,指定的锁对象通常也是当前类的类对象
互斥锁当多个线程执行不同的代码片段,但是这些代码片段之间不能同时运行时就要设置为互斥的.使用synchronized锁定多个代码片段,并且指定的同步监视器是同一个时,这些代码片段之间就是互斥的.
同步与异步的概念:同步和异步都是说的多线程的执行方式。多线程各自执行各自的就是异步执行,而多线程执行出现了先后顺序进行就是同步执行
生命周期
![](https://i-blog.csdnimg.cn/blog_migrate/13dec0834128ed4697fb1f3327b01cbd.png)
创建方式
继承Thread并重写run方法。
耦合问题:线程与任务耦合在一起,不利于线程的重用。
继承冲突:由于java单继承,导致如果继承了线程就无法再继承其他类去复用方法
实现Runnable接口单独定义线程任务(推荐)
方法
start():启动线程的方法。调用后线程被纳入到线程调度器中统一管理,并处于RUNNABLE状态,等待分配时间片开始并发运行。
Thread.currentThread()该方法可以获取运行这个方法的线程
main.getPriority();获取该线程的优先级
main.isInterrupted();是否被中断了
main.isDaemon();是否为守护线程
Thread.sleep(long ms)使运行该方法的线程进入阻塞状态指定的毫秒,超时后线程会自动回到RUNNABLE状态等待再次获取时间片并发运行.
main.interrupt()当一个线程调用sleep方法处于睡眠阻塞的过程中,该线程的interrupt()方法被调用时,sleep方法会抛出该异常从而打断睡眠阻塞.
线程优先级
线程start后会纳入到线程调度器中统一管理,线程只能被动的被分配时间片并发运行,而无法主动索取时间片,但可以设置线程的优先级以获取更多的时间片机会
1为最小优先级,10为最高优先级.5为默认值
调整线程的优先级可以最大程度的干涉获取时间片的几率.优先级越高的线程获取时间片的次数越多,反之则越少.
Collection
集合与数组一样,可以保存一组元素,并且提供了操作元素的相关方法,使用更方便.
Collection接口
List:线性表.是可重复集合,并且有序
Set:不可重复的集合,大部分实现类是无序的.
这里可重复指的是集合中的元素是否可以重复,而判定重复元素的标准是依靠元素自身equals比较的结果.为true就认为是重复元素.
集合变量只能存放引用类型元素,并且存放的是元素的引用(地址)
方法
boolean add(E e):向集合中添加一个元素,成功添加则返回true
int size():返回当前集合的元素个数
boolean isEmpty():判断当前集合是否为空集.当且仅当size=0时返回true.
void clear():清空集合
boolean contains(Object o):判断集合是否包含给定元素
boolean remove(Object o):从集合中删除给定元素,成功删除返回true.
boolean addAll(Collection c):将给定集合所有元素添加到当前集合中。
boolean removeAll(Collection c):删除当前集合中与给定集合的公有元素。
boolean containsAll(Collection c):判断当前集合是否包含给定集合中的所有元素。
Iterator iterator():获取用于遍历当前集合的迭代器
T[] toArray(T[] t):将当前集合转换为一个数组。参数为要转换的数组。如果给定的数组长度不足,则方法内部会自行根据给定数组类型创建一个与集合size一致长度的数组并将集合元素存入后返回。
Arrays.asList()可以将一个数组转换为一个List集合.asList方法会返回Arrays定义的内部类ArrayList,该集合内部直接引用给定数组array,所以对该集合操作就是对array数组的操作,对数组操作后,集合也会改到改变。同时添加元素相当于要对数组扩容,数组是定长的不可以真实的扩容,因此会抛出不支持该操作的异常.删除也是一样的
迭代器遍历过程中不得通过集合的方法增删元素,如果要在迭代的过程中删除元素只能通过迭代器的remove方法可以将通过next方法获取的元素从集合中删除。不同的集合都提供了一个用于遍历自身元素的迭代器实现类。
Collections
Collections是集合的工具类,里面定义了很多静态方法用于操作集合.
方法
Collections.sort(List list)可以对List集合进行自然排序(从小到大),该方法要求集合中的元素类型必须实现接口:Comparable,重写compareTo,这个方法用来定义元素之间比较大小的规则.所以只有实现了该接口的元素才能利用这个方法比较出大小进而实现排序操作.这种方法对代码具有侵入性
Collections.sort(List list,Comparator c)实现比较器接口后必须重写方法compare.该方法用来定义参数o1与参数o2的比较大小规则,返回值用来表示o1与o2的大小关系
List
List集合是可重复集,并且有序,提供了一套可以通过下标操作元素的方法
继承自Collection
实现类
java.util.ArrayList:内部使用数组实现,查询性能更好.
java.util.LinkedList:内部使用链表实现,增删性能更好,首尾增删元素性能最好.
方法
E get(int index)获取指定下标对应的元素
E set(int index,E e)将给定元素设置到指定位置,返回值为该位置原有的元素,替换元素操作
void add(int index,E e)将给定元素插入到指定位置
E remove(int index)删除并返回指定位置上的元素
List subList(int start,int end)获取当前集合中指定范围内的子集。两个参数为开始与结束的下标(含头不含尾),对子集元素的操作就是对原集合对应元素的操作
java网络编程
Socket
Socket(套接字)封装了TCP协议的通讯细节,使得我们使用它可以在客户端与服务端建立网络链接,并通过 它获取两个流(一个输入一个输出),然后使用这两个流的读写操作完成与服务端的数据交互
ServerSocket
作用
向系统申请服务端口,客户端的Socket就是通过这个端口与服务端建立连接的。
监听服务端口,一旦一个客户端通过该端口建立连接则会自动创建一个Socket,并通过该Socket与客户端进行数据交互。
方法
accept()这个方法是一个阻塞方法,调用后方法"卡住",此时开始等待客户端的链接,直到一个客户端链接,此时该方法会立即返回一个Socket实例,通过这个Socket就可以与客户端进行交互了。
HTTP
超文本传输协议,是浏览器与服务器通讯的应用层协议,规定了浏览器与服务器之间的交互规则以及交互数据的格式信息等。
规则是:要求浏览器与服务端之间必须遵循一问一答的规则,即:浏览器与服务端建立TCP连接后需要先发送一个请求(问)然后服务端接收到请求并予以处理后再发送响应(答)。注意,服务端永远不会主动给浏览器发送信息
数据的格式
Request:请求行,请求头,请求体。消息正文部分可以没有
请求行:请求方式(SP)抽象路径(SP)协议版本(CRLF)三个部分 注:SP是空格
请求头:请求头由若干行组成,每行结束也是以CRLF标志。每个请求头的格式为:消息头的名字(:SP)消息的值(CRLF)。请求头部分结束是以单独的(CRLF)标志。
请求体:消息正文是2进制数据,通常是用户上传的信息,比如:在页面输入的注册信息,上传的附件等内容。
Response:响应行,响应头,响应体
响应行:状态行是一行字符串(CRLF结尾),并且状态行由三部分组成,格式为:protocol(SP)statusCode(SP)statusReason(CRLF)协议版本(SP)状态代码(SP)状态描述(CRLF)
响应头:请求中的消息头格式一致,表示的是服务端发送给客户端的附加信息。
响应体:2进制数据部分,包含的通常是客户端实际请求的资源内容。
HTTP要求浏览器与服务端的传输层协议必须是可靠的传输,因此是使用TCP协议作为传输层协议的。
请求和响应中大部分内容都是文本信息(字符串),并且这些文本数据使用的字符集为:ISO8859-1.这是一个欧洲的字符集,里面是不支持中文的!!!。而实际上请求和响应出现的字符也就是英文,数字,符号。
响应的状态码是一个3位数字,分为5类:
1xx:保留
2xx:成功,表示处理成功,并正常响应
3xx:重定向,表示处理成功,但是需要浏览器进一步请求
4xx:客户端错误,表示客户端请求错误导致服务端无法处理
5xx:服务端错误,表示服务端处理请求过程出现了错误
Content-Type是用来告知浏览器响应正文中的内容是什么类型的数据(图片,页面等等)
html text/html
css text/css
js application/javascript
png image/png
gif image/gif
jpg image/jpeg
Content-Length是用来告知浏览器响应正文的长度,单位是字节。
浏览器接收正文前会根据Content-Type和Content-Length来得知长度和类型从而读取出来做对应的处理以显示给用户看。
设计模式
享用模式各种连接池数据池
中介模式nacos
桥接模式驱动链接数据库
单例
工厂
建造