JAVAEE基础
2021-07-25 21:52:03 17 举报
AI智能生成
JAVAEE基础
作者其他创作
大纲/内容
程序为了模拟现实世界,解决现实问题的一系列的有序的指令的集合
什么是程序
1996年推出JDK1.0
2004年推出1.5,更名为5.0,添加了一系列的功能
2014年推出了8.0,添加了一系列的功能
Java的历史
面向对象
简单性
跨平台
Java语言的特点
编译执行:效率高,不能跨平台
解释执行:效率低,可以跨平台
计算机的执行原理
先编译(将.java源文件编译成.class字节码文件),再解释执行
Java语言的执行原理
Java的执行原理
Java虚拟机,跨平台的关键
JVM
Java开发工具包,包含开发环境和运行环境
JDK
Java运行环境
JRE
名词解释
javac命令用来将.java文件编译成.class文件
java命令用来运行.class文件
注意:使用java命令运行.class文件时,不能写后缀名,例如:java HelloWorld
第一个程序
编译时需要带包编译,命令为:javac -d . HelloWorld.java
运行时需要带包运行,命令为:java first.HelloWorld
带包编译
标识符(类名、函数名、变量名等)由字母、数字、下划线、$组成,而且不能以数字开头
不能使用关键字和保留字
规定
标识符命名尽量有意义
类名使用帕斯卡(Pascal)模式,每个单词首字母大写
函数名、变量名使用驼峰式(camel)式,第一个单词首字母小写,后面每个单词首字母大写
包名全小写
常量全大写,用下划线_隔开
约定俗成的规范
注释只能用在一行
单行注释
注释可以使用多行
多行注释
注释可以生成文档,并且在其他位置调用时可以有文档提示
文档注释
注释
编码规范
更换盘符: 盘符:
查看目录内容:dir
进入文件夹: cd
进入上一层文件夹:cd ..
清空屏幕:cls
删除文件:del 文件名
删除文件夹:rd 文件夹名
退出:exit
DOS命令
Java概述
内存是存储数据的空间。
变量是内存中保存数据的一个单位。
数据类型:表示该变量能够存储的数据的范围
变量名:该变量的名称
值:该变量最终存储的内容
隐形要素:地址,表示该变量在内存存放的位置。
注意:变量之所以称为变量,是因为保存的数据是可以发生变化的。
三要素
变量的概念
变量
byte:字节类型,大小为1个字节,范围为-2^7 ~ 2^7-1
short:短整数类型,大小为2个字节,范围为-2^15 ~ 2^15-1
int: 整型,大小为4个字节,范围为-2^31 ~ 2^31-1
long: 长整型,大小为8个字节,范围为-2^63 ~ 2^63-1
注意:直接写的数字默认是int类型,如果要给long赋值,并且值超出了int类型,需要在后面加个字母L(大小写都可以)
整数
负数部分:-3.4 * 10^38 ~ -1.4 * 10^-45
正数部分:1.4 * 10^-45 ~ 3.4 * 10^38
float:单精度浮点数(小数),4个字节
double:双精度浮点数(小数),8个字节
注意:小数默认是double,如果要定义一个float,需要在后面加个字母F。
注意:1、float只有4个字节,long有8个字节,float是以指数的形式表示,而且精度低,所以范围实际上比long大
注意:如果数字在项目中需要精度,或者整数是一个很大的数字,可以使用BigDecimal类型
小数
布尔类型,只有一个字节,范围只有两个值,true和false
布尔
char
字符
基本数据类型
String
字符串
数组
其他自定义类型
引用数据类型
数据类型
int n5 = n1 * n2; // 乘法
int n3 = n1 / n2; // 整数除以整数结果还是整数,结果是2
int n4 = n1 % n2; // 求模,即余数,结果是1
算术运算符
m1++; // 自增1
m2--; // 自减1
注意:int m4 = m3++ + 5; // 当++、--在后时,先参与运算,再自操作。当++、--在前时,先自操作,将结果参与运算
一元运算符
n1 = n1 + 3; // 简写为 n1 += 3; 自增3
n2 -= 3; // n2 = n2 -3;
n3 *= 3; // n3 = n3 * 5;
n4 /= 3; // n4 = n4 / 3;
n5 %= 3; // n5 = n5 % 3;
赋值运算符
> 大于
< 小于
>= 大于等于
<= 小于等于
== 等于
!= 不等于
关系运算符
并且(与),同时满足true才会为true,短路与
&&
或者(或),满足其一就会是true,短路或
||
非,对结果取反
!
代码中&&和&结果是一样的,||和|结果也是一样的,区别在于,当只有一个符号时,会计算两边表达式的值,不会短路
短路是指如果前面一个表达式能够决定整个表达式的值,那么后面一个表达式不运算
注意
逻辑运算符
String s = m > 3 ? \"成立\" : \"不成立\";
三元运算符
运算符
语言基础
if(条件-布尔表达式){ // 代码块}
语法
如果布尔表达式返回true,则执行代码块
流程
基本if结构
if(条件-布尔表达式){ // 代码块1}else{ // 代码块2}
如果条件成立,则执行代码块1,否则则执行代码2
if-else 结构
if(条件1-布尔表达式){ // 代码块1}else if(条件2){ // 代码块2}else if(条件3){ // 代码块3}else{ // 代码块4}
如果条件1成立,则执行代码块1,否则再来判断条件2,成立则执行代码块2,否则再判断条件3,成立则执行代码块3,否则执行代码块4
注意:代码自上而下执行,只会执行一个分支
if-else if -else 结构
if(条件1){ // 代码块1 if(条件2){ }else{ }}else{ // 代码块2}
如果条件1成立,则执行语句块1,否则执行代码块2,在执行代码块1时,发现又有选择,继续判断条件2,按照if的流程继续往下执行
嵌套if结构
选择结构
switch(变量或者表达式){ case 值1: // 代码块1 [break;] case 值2: // 代码块2 [break;] case 值n: // 代码块n [break;] default: // 默认代码块 [break;]}
在case时,值不能相同
在if中的条件可以写大于小于等于等多种条件,但是case中只能判断等于
在case时,如果不满足条件,继续向下判断,如果条件满足,会执行里面的内容,如果里面的内容没有break关键字,会继续向下执行,不会判断
switch中变量的类型只能是byte、short、int、char、String[JDK7+]
switch分支结构
局部变量需要先赋值后使用
局部变量的作用域范围是在它所对应的大括号里,并且要定义后才能使用
局部变量在有重复的作用范围时,不能重复定义(重名)
在方法中定义的变量称为局部变量
局部变量
选择和分支结构
while(条件){ // 代码块}
先判断条件,如果条件成立,则执行代码块,执行完毕继续判断条件,条件成立时继续执行代码块,直到条件不成立则结束
初始变量
循环条件
循环内容(循环体)
条件的变更
循环过程的四要素
while循环
do{// 代码块}while(条件);
先执行一次代码块,然后判断条件,如果条件成立则继续执行代码块,直到条件不成立为止
while先判断条件,再执行代码块,可能一次都不执行
do-while先执行一次代码块,再判断条件,至少执行一次
while与do-while区别
do-while循环
for(初始化变量;条件;迭代变量变更){// 代码块}
1、初始化变量(执行一次)2、判断条件3、循环内容4、条件变更5、再判断条件...(循环2、3、4直到条件不成立)
for循环
直接终止当前循环,整个循环结束
break
跳过当次循环(continue后面的代码不执行),继续进行下一次循环
continue
流程控制
循环中包含其他的循环
外层循环执行一次,里层循环全部执行后,外层再执行第二次,里层循环继续全部执行。简单来说,双重嵌套循环,总循环次数等于外层循环次数乘以里层循环次数。
在嵌套循环时,使用break或continue只对当前循环有效。
嵌套循环
循环
实现特定功能的一段代码,可以反复使用
概念
public static void 方法名(){ // 需要重复执行代码块}
方法名的定义需要遵循标识符的定义规则。
方法的定义
当程序中有重复的代码块,可以放到一个方法中,以方便扩展和维护。简化流程的理解过程。
作用
方法的基本使用
public static 返回值类型 m1(){ return 值;}
在一个方法中,return后面不应该有代码,因为return就表示方法结束
在一个方法中,不能仅用有条件的方式来返回,必须在所有的情况下都能返回
当返回值类型为void时,在方法中可以没有return,也可以使用return作为方法的结束,用来终止嵌套循环。此时return后面直接加分号。
方法的返回值
方法的多级调用是指,在方法中调用方法,通常用来流程简化。
方法的多级调用
在方法中再次调用当前方法,称为递归调用
循环只需要使用一个方法栈空间,所以消耗空间小,执行速度快,递归需要使用多次方法栈空间,要谨慎使用。
递归
方法
计算机中二进制表示数字对于人类来说太长了,一般情况下,通常使用8进制或者16进制来简短的描述2进制
进制概念
52采用倒除法计算除以2的余数,反向统计为110100
十进制转换成二进制(倒除法)
99== 9 * 10 + 9
二进制转换成十进制
110100 = 1 * 2的二次方 + 1 * 2的四次方 + 1 * 2的5次方 = 4 + 16 + 32 = 52
任何进制转换成十进制规则
在Java中,书写2进制使用0b开头,8进制用0开头,十六进制用0x开头
进制的转换
3 & 50000 00110000 0101-----------0000 0001
计算规则:同为1则为1,否则为0
与运算
3 | 50000 00110000 0101-----------0000 0111
计算规则:只要有一个为1,结果为1
或运算
计算规则:表示各位取反,0变1,1变0
使用~作为取反(非)运算符
非运算
计算规则,相异为1,相同为0。
^作为异或运算符。
任何数与另外一个数字异或两次得到该数字本身。
小技巧:可以不用第三个变量实现两个整数的交换。
异或运算
>>向右位移。移动n位相当于除以2的n次方
<<向左位移。移动n位相当于乘以2的n次方。低位补0
性能比乘除高得多。
位运算(位移)
如果在逻辑判断中使用&或者|,在判断结果上与&&或者||是一样的,但是&&或者||有短路的特征。而&或者|一定要计算两边的结果。
二进制的运算
例如:3 ,原码为0000 0011
直接通过10进制转换成二进制之后的编码。
例如:-3,原码表示为:1000 0011
负数的表示方式,在最高位使用符号位1来表示,其他位与正数方式一致。
原码
-3 原码表示为:1000 0011,使用反码1111 1100
将负数的反码设计为:符号位不变,其他各位取反。对于正数来说,反码与原码一致。
反码
-3 原码表示为:1000 0011,使用反码1111 1100,使用补码1111 1101
正数原码反码补码一致,负数补码等于反码+1
补码
原码、反码、补码
3.2----------------------------------------------------------11.0011001100110011001100110011001100110011
整数部分按照整数的方式转换。小数部分乘以2,减1
这就是导致浮点数不精确的原因
浮点数十进制转换成二进制
进制
一组连续的存储空间,存储数据类型相同的一组数据
特征:连续空间、相同类型、长度固定
int[] a = new int[5]; // 创建5个元素大小的int型数组
创建
数组的概念
数字,默认值都是0整数都是0小数都是0.0char是0对应的ascii码布尔默认值是false字符串的默认值是null
数组的默认值
int [] a; // 声明a = new int[5]; // 再分配空间a[0] = 10; // 赋值
先声明,再分配空间,再赋值,再使用
int [] a1 = new int[10];
声明的同时分配空间
声明并赋值复杂方案
声明并赋值简单方案
创建方式
1、创建一个超过原来数组大小的新数组
2、将原数组中的元素复制到新数组中
3、将要添加的新元素添加到新数组中
参数说明:源数组,从那里开始复制,目标数组,从那里开始存储,复制长度
参数说明:源数组,新数组的长度,返回一个新数组
系统提供的方法
数组的扩容
值传递,将变量中的值传递了其他变量,通常来说基本数据类型都是值传递
引用传递,在引用数据类型中,存储是对应的元素的位置,在传递时,只传递了位置信息
值传递和引用传递
语法:类型后面加... 相当于数组,是一种特殊的数组(例:String... arr)
优点:是在调用时,可以不传参,也可以传多个参,不能构建成数组
缺点:1、只能作为方法的参数 2、只能作为方法的最后一个参数 3、在方法中只能使用一个可变长参数
可变长参数数组
冒泡排序
选择排序
插入排序
JDK自带排序
数组排序
二维数组[了解]
万事万物皆为对象
对于程序来说,主要研究对象的属性和方法
属性:也叫特征,一般是名词,例如:颜色、大小等
方法:也叫行为,一般是动词,例如:走,跑,吃等
面向对象的概念
简称为OOP,面向对象的思想一般指在研究项目时,采用研究相应的业务有哪些对象参与,以及对象有哪些属性和方法,在执行方法时与其他对象之间的关联。面向对象的编程是指用面向对象的思想去思考,并且写对应代码。可以解决复杂的项目业务问题。
面向对象的编程
是指在研究项目时,考虑项目执行步骤,每一步如何完成,以此写出的代码就是面向过程的编程。一般应用底层开发(系统),以及业务较为简单的项目。
面向过程的编程
面向对象的编程和面向过程的编程
类是指从多个对象中抽取出相同的特征和行为的一个抽象的概念。
类的概念
类是对象的模板(抽象)
对象是依据类创建的实例(可以有多个)
在创建了对象后会有默认值,与前面学习的数组默认值一样
属性又叫做实例变量
类和对象的关系
定义位置:实例变量定义在类的内部,与方法并列的。局部变量定义在方法的内部。
默认值:实例变量有默认值,与数组类似。局部变量需要先赋值后使用。
使用范围:实例变量在整个类中基本都能使用。局部变量只能在定义的方法中使用。
命名冲突:局部变量可以与实例变量重名,在方法中使用时默认使用局部变量。
实例变量(属性)与局部变量的区别
类中没有static关键字的方法是实例方法。
实例方法
方法的重载是指在类中,可以定义相同名词的方法
1、方法名词相同
2、参数列表不同(类型,个数,顺序)
重载与访问修饰符(public等),返回值类型、参数的变量名称、异常的声明无关。
在方法调用时,只需要传入相应类型的参数即可,无需考虑方法名称上的差异。
好处
在方法调用时,优先考虑传入参数类型相符的方法,如果没有,会考虑自动转换类型能够匹配的方法。
方法的重载
构造方法是通过new关键字调用的方法,用来创建对象。
构造方法与类名相同,没有返回值,不是void,所以构造方法一般以大写字母开头。
当类没有定义构造方法时,会默认有一个无参的构造方法。
构造方法基本定义
在一个类中,可以写多个重载的构造方法。有参构造方法的作用是用来强制用户在创建对象时必须给关键属性赋值。
类中默认有个无参的构造方法,如果显示的定义了任何构造方法,那么原来默认的无参构造方法就会失效。
构造方法的重载
构造方法
this一般指代当前对象
1、在实例方法或构造方法中,如果定义了局部变量名称与属性相同,可以通过this.属性来调用属性。
2、在一个实例方法中,如果想要调用其他的实例方法,可以使用this.方法名(),此处this可以省略。
3、在构造方法中,如果想调用类中定义其他构造方法,可以使用this关键字。
用法
this关键字的用法
封装、继承、多态
三大特征
封装分为属性封装和方法封装。
将属性设置为私有,提供公有的访问方法(getter和setter),在访问方法中,对属性的赋值或取值进行限制。
属性封装
封装的作用是将需要被外部访问的方法暴露(公有),将不需要外部关注和使用的方法私有。
方法的封装
封装
继承在Java中使用extends关键字来描述,表示扩展。
Java中的继承一般指is a关系,例如:狗 is a 动物,所以狗继承自动物,具备用动物的所有的特征和行为,那么动物是父类,狗是子类。
继承的概念
继承只能单继承(继承一个直接父类),但是可以多级继承(父类继承其他父类,那么子类就间接继承)
继承的特点
构造方法, 因为需要与类名相同,所以不可继承。
无法访问的(private,默认的在不同包的子类中)视为不可继承。
不可继承
本类 本包 非本包子类 其他private √默认的 √ √protected √ √ √public √ √ √ √
访问修饰符
在子类中,可以定义一个与父类中的方法完全一样的方法,称为方法的重写(override)
1、方法名称和参数必须与父类完全一样。
2、返回值类型必须与父类完全一样。
3、异常声明必须与父类完全一样。
4、访问修饰符可大不可小。
原则
为了防止在方法重写时单词拼写错误导致重写失败,可以使用@Override注解来检查。
1、重载可以发生在一个类中,而重写至少需要两个类。2、重载要求方法名称相同,但是参数列表不同,其他的不关注。但是重写严格得多,要求除了访问修饰符以外的其他都要相同。3、重载实际是两个方法,而且都可以调用。但是重写属于一个方法的覆盖,子类的对象只能调用重写后的方法。4、构造方法只能重载,不能重写。
重载(overload)和重写(override)的区别
经典面试题
方法的重写
super关键字表示父类的对象
一般情况下,是子类有与父类相同的属性,此时,直接调用属性,会调用子类的属性,使用super可以调用父类的属性。
super.属性,来调用父类的属性
一般情况下,是子类重写父类的方法后,只是需要添加一些子类方法的代码,还需要接着使用父类的方法中的代码,此时可以在子类的方法中使用super调用父类的方法。
super.方法,来调用父类的方法
super(),来调用父类的构造方法
使用方式
子类在调用构造方法时,会自动调用父类的默认的无参构造方法。
当父类没有无参构造方法时,子类没有办法调用到默认的无参构造方法,此时会报错,需要手动调用有参构造方法。
无论子类构造方法中有没有调用父类的构造方法,都会调用父类的构造方法。如果使用super()调用父类的构造方法,一定要放到代码的第一行。
调用构造方法
super关键字
当创建子类对象时,会先创建父类的对象。1、分配相应的空间2、创建父类的对象 a、初始化父类的属性 b、调用父类的构造方法3、创建子类对象 a、初始化子类的属性 b、调用子类的构造方法
继承过程中的对象创建流程
所有的类最顶层的父类是Object,默认继承(隐式)自Object。
继承
程序中的多态是指可以使用父类的引用指向子类的对象。
由于采用父类的引用去指向子类的对象,所以父类的引用只能调用父类的属性和方法。如果想要调用子类的特有属性和方法,需要强制转换类型(向下转型,拆箱),如果转换的类型不对,会出现ClassCastException异常(类型转换异常)此时应该使用instanceof关键字来判断类型。
多态
栈空间很小,由系统管理,一般的局部变量,方法调用等都在栈中完成,所以递归层次较深时,会出现栈溢出。
堆空间比较大,一般存放对象,new关键字创建出来的对象和数组一般都存在堆里。
栈和堆
面向对象的三大特征
指抽象的
表示该类不能创建对象。有一些抽象的概念所对应的类,例如动物类,本不应该创建对象,但是可能会由于失误创建了该对象,为了限制此问题的出现,那么可以给类加上此关键字,作用是让该类不能被创建对象
修饰类
表示该方法不能直接实现,需要在子类中重写实现。因为有些方法在父类中实现没有意义,只有在各个不同的子类中去实现,那么此时可以给该方法添加此关键字
修饰方法
抽象类中可以没有抽象方法,但是抽象方法所在的类必须是抽象类
abstract
指静态的(类的),可以修饰属性或方法
表示该属性为静态属性(类属性),该属性在类中只有一份,所有的对象共享一份
注意: 由于类属性整个类只有一份,所有的对象共享,所以一般推荐使用类名来直接操作,不需要创建对象。
修饰属性
表示该方法为类方法,应该通过类名直接调用,不需要创建对象。
注意:1、static方法中可以访问其他的static方法,也可以使用static属性,但是不能调用实例方法,也不能访问实例属性, 也不可以使用this或super关键字,原因是此时没有创建对象。2、实例方法中可以访问实例属性,类属性,this或super关键字,也可以调用实例方法,类方法。
static修饰的语句块叫做静态语块,没有static修饰的叫做动态语句块
语句块的作用一般用来初始化属性值或者完成一些对象创建时就需要完成的操作。
静态语句块是类加载时执行,动态语句块是创建对象时执行,所以静态语句块中只能操作静态属性和静态方法。
修饰语句块
先执行静态的内容:- 父类静态属性初始化- 父类的静态代码块- 子类的静态属性初始化- 子类的静态代码块后执行非静态内容,先执行父类的非静态内容,再执行子类。- 父类实例变量初始化- 父类的动态代码块- 父类的构造方法- 子类的实例变量初始化- 子类的动态代码块- 子类的构造方法
代码创建过程的执行顺序
static
final关键字表示最终的
该类不可以被继承
表示该方法不能被重写
表示该变量赋值后不能被重新赋值,由变量变成了常量
修饰变量
final
三个修饰符
接口里面定义的所有属性都是public static final的。
接口里面只能定义抽象方法。
接口中不能定义构造方法,代码块。
接口中可以定义默认方法
接口的定义规则
在Java中类只能单继承,但是可以实现多个接口
1、如果同时继承类并实现接口,那么继承类要放在前面2、实现多个接口使用逗号隔开3、当继承类并同时实现接口时,如果接口中有一个抽象方法与父类中某个方法声明完全一致,在子类中可以不实现该方法。
接口的基本使用
接口中也可以定义静态方法和默认方法(JDK的高版本添加)
不能定义实例方法,可以定义静态方法,使用接口名调用
接口的其他用法[了解]
接口
内部类是指在一个类的内部定义的类。
概念:在类里面直接定义的内部类,使用方式与成员变量相似。
在成员内部中,如果属性与外部类属性同名,优先调用内部类属性,可以使用外部类的名称.this去调用外部内的属性。
在成员内部中,不可以定义静态属性,在外部内中,也不能直接调用内部类的属性和方法。需要创建对象才能调用。
使用
成员内部类[了解]
概念:在类中定义一个static的类,用法与静态属性或静态方法相似
静态内部类
概念:在类的方法中定义的类
与该方法的使用方式一致。而且只能在该方法中使用,所以该内部类不能使用public来修饰。
局部内部类[了解]
直接使用接口或者抽象类来直接创建对象,在创建对象的过程中实现其未实现的方法
本质与局部内部类用法相似。
匿名内部类
分类
内部类
Object类是所有类的父类,是最顶层的父类,所有的类直接或间接继承了Object类
如果类继承了一个类,则间接继承了Object,如果没有继承任何类,则默认直接继承了Object。
所有类都具备有Object中定义的方法。Object类中没有定义属性
getClass方法是final的,所以不能重写,该方法表示返回对象所对应的实际类型。
显示当前对象所对应的类型
getClass方法
根据对象的地址或字符串或数字计算出来的10进制结果。
要保证相同对象返回相同的hashCode,尽量保证不同对象返回不同的hashCode。
系统默认是采用对象地址作为hashCode值,如果项目中需要判断比较对象是否相同,应该重写hashCode方法,以保证使用对象唯一标识来判断对象是否相同,而不是采用地址直接比较。
hashCode方法
当对象使用println输出时或将对象当作字符串拼接时,会自动调用toString方法,此时toString默认会显示该类型(getClass)加上地址(hashCode),此内容一般没有意义,可以自己重写toString方法,将对象信息返回。
toString方法
主要用于垃圾回收。
1、由系统管理,不需要手动调用。2、垃圾回收是定时回收。3、System.gc()方法是手动调用垃圾回收, 但是只是通知系统进行垃圾回收,并非直接回收。
finalize方法
equals方法是用来判断两个对象是否相同。默认是判断地址是否相同,应该重写该方法,以达到根据id标识判断的逻辑结果。
1、判断是否同一个地址。2、判断obj是否为空。3、判断是否同一个类型。4、强转类型。5、判断id标识是否相同。
重写的步骤
equals方法
Object类
包装类是指基本数据类型所对应类,有八种
byte Byteshort Shortint Integerlong Longfloat Floatdouble Doublechar Characterboolean Boolean
在JDK1.5之后实现了自动装箱和拆箱
Integer.MAX_VALUE; // 最大值
Integer.toHexString(n4); // 显示十六进制字符串
Double.parseDouble(s);使用对应的包装类的parseXXX方法
包装类常用的一些内容
对于Integer,系统预先创建了256个对象,范围是-128~127之间,作用是可以共享对象,节约内存。
整数缓冲池(常量池)
包装类
字符串是一个final的类,底层使用一个private final char[]来保存字符串值
与整数常量池相同的是,都可以共享使用,以节省空间
与之不同的,整数常量池在IntegerCache类加载后,就创建了256个对象,以共享使用,而字符串值太多,无法直接一开始就创建,所以是在第一次使用该字符串的字面量值时在常量池创建,并且提供共享引用。
字符串常量池
String s = \"Hello\"; // 得到某个下标位置的字符 char ch = s.charAt(0); // h
charAt()
// 判断字符串是否包含另一个字符串 boolean b = s.contains(\"ell\");
contains()
// 将字符串转换成数组 char [] arr = s.toCharArray();
toCharArray()
indexOf(String)指在一个字符串中查找另一个字符串首次出现位置,如果没有,返回-1
indexOf()
得到字符串的长度
注意与数组区分,数组是length属性,而字符串是length()方法
length()
去掉字符串两边的空格,中间的空格不会去掉,原字符串是不变的,需要接收该方法的返回值
trim()
字符串转换成大写
toUpperCase()
字符串转换成小写
toLowerCase()
// 判断字符串是否以另一个字符串结尾 String s3 = \"photo.png\"; boolean b1 = s3.endsWith(\".png\");
endsWith()
// 将字符串中的一个字符串全部替换成另一个字符串 String s4 = \"hellohello\"; s4 = s4.replace(\"ell\
replace()
// 将字符串根据另一个字符串切割成数组 String s5 = \"武汉-黄石-宜昌-孝感\"; String [] arr1 = s5.split(\"-\");
split()
截取字符串中的一部分
String s6 = s5.substring(3); // 一个参数表示截取后面所有
substring()
String s8 = \
拼接字符串
concat()
常用方法
String类由于不可变,每次对其操作,必须接收返回值,操作需要更多的空间。如果项目中需要大量操作字符串的,为了节约空间,提升效率,推荐使用可变字符串。可变字符串是直接在字符数组中操作的。除非需要扩容,否则不会浪费额外的空间。
JDK5.0添加的,线程不安全,但效率高
StringBuilder
JDK1.0就有的,线程安全(几乎所有的方法上都直接使用synchronized关键字),但效率低
StringBuffer
添加(拼接)字符串
append()
删除
delete()
修改
插入
insert()
将可变字符串变成普通字符串
toString()
可变字符串
浮点数精确运算
大数字运算
两种用法
减法
subtract()
加法
add()
乘法
multiply()
除法
divide()
BigDecimal
得到当前时间
new Date()
得到当前时间的毫秒数
getTime()
根据时间毫秒数创建一个时间对象
new Date(1620715603615L)
boolean b =now.before(before); // 是否早
比较两个时间
before()
int n =now.compareTo(before); // now比before早返回-1,晚返回1,同返回0
compareTo()
long mill = System.currentTimeMillis();
得到当前系统的毫秒数
currentTimeMillis()
Calendar c = Calendar.getInstance()
不通过new,而通过下面的方式创建对象,当前时间的日历
getInstance()
yy表示两位年,yyyy四位年MM月,mm分dd日 ss秒hh 12小时制小时,HH24小时制的小时SSS毫秒 a上午下午
日期格式化
new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\")
Date d1 = new Date();String s = sdf.format(d1);
将日期格式化成指定的字符串格式
format()
String s1 = \"2020-12-15 16:14:56\";Date d2 = sdf.parse(s1);
将规定格式的字符串转换成日期
parse()
日期相关类
System是系统类
数组复制
arrayCopy
currentTimeMillis
退出当前程序
exit(0)
请求垃圾回收
gc()
系统输入属性
System.in
系统输出属性
System.out
System
常用类
集合是类似于数组,存储对象的容器,定义了对容器中对象的增删改查遍历等一系列方法的类。位于java.util包中。
1、数组长度固定,集合长度不固定。
2、数组可以存储基本数据类型和引用数据类型,集合只能存储引用数据类型。
集合与数组的区别
由于JDK5.0后有自动装箱拆箱,所以向集合中添加基本数据类型也是正确的,本质上是将其自动装箱,变成了包装类的对象。
集合的概念
Collection是一个集合的顶层接口。定义了存储多个对象的集合,具备有基本的增删改查等方法。
特点
List和Set是Collection的子接口。
List中元素是有下标,可重复的。而Set中的元素无下标,不可重复。
add、addAll、clear、remove、contains、size、isEmpty、toArray
Collection父接口中的方法
Collection集合
Collections类是集合的工具类,提供了集合的一些操作,例如:排序,反序,打乱等。
// 随机打乱元素顺序 Collections.shuffle(list);
// 排序 Collections.sort(list);
// 反序 Collections.reverse(list);
Collections类的使用
List子接口继承自Collection接口,具备有Collection接口的特点。而且自身具备有序、有下标、元素可重复等特点。
List子接口
插入、删除速度比较慢。遍历比较快。
// 根据下标删除元素 list.remove(0);
// 根据对象删除元素 list.remove(Integer.valueOf(3));
获取元素的个数list.size()
// 通过下标获取元素list.get(1)
// 添加元素 list.add(3);
ArrayList
插入、删除速度比较快,遍历比较慢。链表有单向和双向之分。添加元素时往首尾添加性能更优。
和ArrayList方法一样
list.removeFirst();
list.removeLast();
LinkedList
Vector与ArrayList基本实现方式一致,只是大部分方法前面加上了synchronized关键字,表示加锁,实现线程安全,性能极低,基本不使用。
Vector
List接口的常用实现类
特点是无序、无下标,元素不可重复。
底层使用HashMap,HashSet中添加的元素直接放到HashMap的key上,所以元素不能重复(map的key不能重复),无序,无下标。
添加元素
删除元素
remove()
HashSet
使用了链表的HashSet,是有序的
LinkedHashSet底层是继承了HashSet,使用了HashSet中创建了LinkedHashMap的构造方法。LinkedHashMap相对于HashMap仅仅是多添加了一个链表,用来记录添加元素的顺序。
LinkedHashSet
TreeSet实现了排序功能
要求添加的元素必须使用Comparable接口,通过比较返回负数、正数、零来进行排序,负数排左边,正数排右边,零当作重复的元素去掉
Comparable接口
TreeSet
Set接口
Map接口采用键值对(key-value)的方式存储数据
key不能重复,value可以重复,如果key重复,value会覆盖。
get(key); // 获取值
keySet(); // 获得所有的key
values(); // 获得所有的value
entrySet(); // 遍历时使用的entry(键值对)的集合
Hashtable代码与HashMap基本一样,只是大部分方法前面加上了synchronized关键字,表示加锁,线程安全,但是性能很低,基本不使用。
Hashtable
继承了Hashtable,添加了对资源文件操作的内容,一般用来在系统初始化时加载资源文件。
// 通过文件路径读取文件内容 InputStream inStream = TestMain1.class.getResourceAsStream(\"/db.properties\");
// 直接加载文件中的内容到集合中 prop.load(inStream);
Properties
有序是指,保留添加顺序。
有序
无序是指,不保留添加顺序。
无序
排序是指,添加后按照指定的规则进行排序。
排序
TreeMap会将添加的元素按照key排序,所以key对应的类型应该实现Comparable接口。否则会报错。
TreeMap
Map接口
集合
异常就是指程序运行过程中,出现的不正常的情况,一般会导致程序运行终止。例如:除数为0。
异常的概念
出现异常的原因并非是bug,大部分情况是由用户造成的(例如:文件格式不正确,路径不存在等)如果程序中不处理,会导致程序终止,所以应该在程序中对异常出现的情况进行提醒或处理。
异常处理的必要性
Throwable是所有的异常的顶级父类。
Error是指系统错误,例如内存不足,硬件问题等,此类问题程序无法解决,所以不做异常处理
Error
Exception才是需要处理的异常
运行时异常一般是程序员写的bug,只需要检查一下,加个判断就能解决。所以又称为未检查异常(非受检异常),此类异常在程序中不强制要求处理。
运行时异常(RuntimeException)
通常是用户操作可能引发的,程序员没办法使用代码避免此类异常的出现,所以在程序中强制必须处理。所以称为已检查异常,又称为非运行时异常。
已检查异常(CheckedException)
Exception
Throwable
异常的分类
在运行时异常出现时,可以不处理异常。但是如果代码中包含有已检查异常,必须进行异常处理。
throws表示抛出异常,会将异常抛给调用者,自己不需要处理。
语法是在方法声明时使用throws关键字声明要抛出的异常,如果有多种异常,可以用逗号隔开。
throws
如果在处理业务的过程中,需要以异常的形式提醒调用者,那么此时可以手动抛出异常。
throw 异常对象
throw
throws抛出异常是最简单异常处理方式,但是该方式要根据实际情况选择,当异常产生的原因是由调用者造成的(参数格式问题等),那么该方法本身是无法解决此问题的,应该抛给调用者解决,但是如果原因不是调用者造成的,而且调用根本不能解决此问题,则没必要抛出。
使用throws和throw处理
try是尝试运行可能出现异常的代码
try
catch是出现异常后,执行此处的代码,catch可以出现多次,Exception类型只能在catch最后一个
catch
finally表示一定会执行,如果有return,在返回之前执行。。尽量保证逻辑不相关的代码不要在一个try中。
finally
try-catch-finally
通常是在项目中要抛出一个业务异常时,需要一个异常类来描述该业务。
需继承自Exception即可
自定义异常
异常处理
异常
一般情况下,一个应用程序在运行的时候会有一个进程。
线程是轻量级的进程,一个进程中可以有多个线程,同一个进程的线程之间可以共享数据。
进程和线程
1、抢占的CPU的时间片。
2、运行过程中的数据,堆的数据共享,每一个线程都有独立的栈空间。
3、线程执行的代码(任务)
线程的组成
// 得到当前线程的名称String name = Thread.currentThread().getName();
启动线程
start()
继承Thread类
实现Runnable接口
start方法表示启动线程,包括执行线程中任务。
run方法是定义线程中需要执行的任务,不能直接调用
start方法和run方法的区别
继承Thread类,优点是使用方便,创建对象后可以直接调用start。缺点是不能再继承其他的类。
实现Runnable接口,缺点是创建对象后,还需要创建Thread类的对象,才能调用start方法,比较麻烦。优点是还可以继承其他的类。
继承Thread类和实现Runnable接口的区别
线程的基本创建
线程被创建后,进入此状态。
new(创建)
线程调用start方法后,进入就绪状态,此时并不意味着就开始执行了,还需要等待抢占CPU时间片。
start(就绪)
当线程抢占到CPU的时间片时,就会执行任务(run方法中的业务代码),CPU的时间片到期后,会继续转入就绪状态。
running(运行)
当线程中的任务执行完毕后,进入终止状态。
terminate(终止)
基础状态
表示当前正在执行的线程进入休眠状态,等待休眠状态时间结束后,会进入就绪状态。
sleep方法
此方法表示在线程运行过程中,放弃当前执行的时间片,进入就绪状态。
yield方法
此方法表示将A线程join(合并)到B线程中,此时B线程会暂停执行,直到A线程执行完毕后,B线程才会进入就绪状态。
join方法
线程执行过程中的方法
等待状态:可能都会造成线程的阻塞
sleep:让当前线程进入休眠状态,需要满足休眠时间结束才会继续进入就绪状态。
wait:让当前线程进入等待状态,需要等待被其他线程唤醒才会进入就绪状态。
yield:让当前线程从运行状态进入到就绪状态。
join:让当前线程暂停,让其他线程先行。
阻塞状态:线程同步时,没有抢到锁,被迫进入了阻塞状态。
线程状态
1、多线程并发操作。
2、共同操作(写操作)同一个共享的临界资源。
导致线程不安全的原因
将要操作的临界值加锁,让其他线程等待(阻塞)当前线程对临界值的操作完毕后,才可以继续执行。
synchronized(锁){} // 注意,锁应该唯一,而且需要是Object,不能是基本数据类型。
public synchronized void(){} 对方法进行加锁,锁的是调用者。
使用synchronized加锁
同步锁机制
线程安全
表示当前线程进入等待状态,等待notify唤醒,有参数的表示超时时间,超过时间还没被唤醒会自动醒来。
wait
表示唤醒使用wait等待的线程,一次只能随机唤醒一个
notify
一次性唤醒所有的线程
notifyAll
使用wait和notify、notifyAll时,必须在同步(synchronized)代码块中执行。否则会出现java.lang.IllegalMonitorStateException异常。
1、sleep是休眠,需要指定时间,时间结束后进入就绪状态。而wait是等待,需要被notify唤醒,设置时间也只是超时时间。
2、sleep休眠时持有(不释放)锁,wait等待时释放锁。
sleep和wait的区别
线程间的通信
当多个线程在处理共享资源,使用锁时,如果出现同时都持有一把锁,并且需要另一把锁才能继续执行,没有另一把锁,绝不会释放当前锁时,就会出现死锁。
死锁
线程的状态
1、创建型模式,用来创建对象的(5种)。例如:单例模式、原型模式、工厂模式
2、结构型模式,针对于多个对象之间组成一种新的结构(7种)。例如:桥接模式、门面模式、适配器模式
3、行为型模式,多个对象之间产生行为处理的方式(11种)。例如:调停者模式、命令模式、监听者模式、迭代模式
23种设计模式,共分为3大类
设计模式
stop()[已废弃,不推荐]
使用系统的interrupt标识来停止线程。
Interrupt()
使用方法
线程的终止
优先级分为10级,最高10,最低1,默认5。
线程的优先级,优先级越高的线程将优先抢到时间片
当一个线程一直抢不到时间片来执行,称为线程饿死。
线程饿死
线程的优先级
守护线程是一个特殊的线程,当其他的线程都执行完毕后,守护线程也会终止。
setDaemon(true)
守护线程
指管理大量线程的容器。需要创建任务(Runnable、Task)对象,来使用池中线程对象来执行任务,如果池中线程已经用完,会进行等待。
创建一个无上限的线程池ExecutorService service = Executors.newCachedThreadPool();
创建一个单线程的线程池ExecutorService service = Executors.newSingleThreadExecutor();
创建一个4个线程的线程池ExecutorService service = Executors.newFixedThreadPool(4);
创建线程池
将任务交给线程池去执行
submit()
关闭线程池
shutdown()
线程池的基本使用
Callable接口的返回值并不是立即就能得到的,需要线程任务执行完毕,所以会返回一个Future接口的对象,通过该对象的get方法才能获取结果
Callable接口与Runnable接口作用相似,都可以作为线程池的任务,但是Runnable接口没有返回值,当需要获取返回值时就需要使用Callable接口。
Callable接口和Future接口
线程池
Lock接口是jdk5添加的功能
synchronized是由jvm来完成加锁和解锁的过程,Lock可以自由的加锁解锁,更加灵活
对比synchronized
lock()加锁
unlock()解锁
tryLock()尝试获取锁
Lock接口
private static ReentrantLock lock = new ReentrantLock();
ReentrantLock重入锁(公平锁)
当有一个线程在写时,会互斥,当所有的线程都在读时,不互斥,共享读取,以在保障线程安全的前提下提升性能。
用于读多写少的任务
// 使用读写锁 private ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private ReadLock readLock = lock.readLock(); private WriteLock writeLock = lock.writeLock();
ReentrantReadWriteLock读写锁
Lock和ReentrantLock
1、可见性。多线程访问共享变量时,如果一个线程对其进行修改,其他的线程能够立即发现改变后的值。
2、互斥性。多线程访问共享变量时,如果一个线程对其进行操作(读写),其他线程都会等待其操作结束。
synchronized关键字,可实现线程安全。
volatile关键字只能保证线程的可见性,不能保证互斥性,所以并不能保证线程安全。
private volatile String name1 = \"a\";
volatile使用在属性前,表示该属性具备线程的可见性。
volatile关键字用法
加强版的读写锁实现,可以读写分离。
写有锁,读无锁,每次写的时候都会复制一个副本,写入后替换原来的地址。
CopyOnWriteArrayList
底层以CopyOnWriteArrayList实现,就是添加时使用的addIfAbsent()会遍历集合,如果已经存在该元素,则抛弃该副本,不存在则添加。
CopyOnWriteArraySet
JDK1.8之前,默认将其分为16段(segment),对每一段进行加锁,理论上来说,如果有16个元素,分别放到16段里,那么基本没锁。
JDK1.8之后,采用的CAS机制,即只对当前添加的对象加锁,通过CAS交换算法来修改数据。
ConcurrentHashMap[面试的一个重点]
队列,先进先出,FIFO原则,First In First Out
Queue
性能最好的线程安全的队列。采用CAS交换原则。
ConcurrentLinkedQueue
put():添加,如果没有空间则等待。
take():获取,如果没有元素则等待。
增加了两个无限期等待的方法。
主要用来实现生产消费模式。
BlockingQueue
有界队列,使用数组实现,事先在构造时先确定队列空间大小。
ArrayBlockingQueue
无界队列,使用链表实现。
LinkedBlockingQueue
线程安全的集合
多线程
JAVAEE基础
0 条评论
回复 删除
下一页