一 入门介绍
一. Java语言前言
1.字节:计算机中存储数据的最小计量单位,用byte或者B表示
计算机中最小的存储单元是二进制,二进制用bit表示
8个二进制代表一个字节
8bit = 1B
2.常用的dos命令
win+r→输入cmd
二. java环境
1.JVM和跨平台
jvm(java虚拟机):java运行程序的假想计算机,主要用来运行Java程序,一次编写,到处运行
2.JDK和JRE
jdk:java开发工具包,包含了jre
jre:java运行环境,包含了jvm以及后面开发用到的核心类库
jdk包含了jre,jre包含了jvm
*从jdk9开始就没有单独的jre目录了,jdk9引用模块化的技术,让开发者能按照自己的应用创建一个最小的运行时环境
三. 程序开发
编写->编译->运行
关键字:java自带
二 数据类型
一. 常量
1.在代码的运行过程中,值不会发生改变
整数常量,小数常量,字符常量 ‘a’,字符串常量 “aa”,布尔常量,空常量 null
二. 变量
1.变量的数据类型:
a.基本数据类型:4类8种
整型:byte(1字节) short(2) int(4) long(8)
浮点型 float(4) double(8)
字符型 char(2)
布尔型 boolean(1)
b.引用数据类型:类 数组 接口 枚举 注解
2.变量的定义
在代码的运行过程中,值会随着不同的情况而随时发生改变的数据
字符串不属于基本数据类型,属于引用数据类型,用String表示
String是一个类,只不过字符串在定义的时候可以和基本数据类型格式一样
3.变量的使用
定义初始化,使用
定义Long类型的变量,建议后面加个L long num = 10L
4.变量的运算
变量的加减乘除
转义字符:\
作用:将普通字符转成具有特殊含义的字符
将具有特殊含义的字符转成普通字符
n普通字符 \n转义字符
t普通字符 \t制表符
float和double的区别:
float的小数为只有23位,double的小数位有52位
不要用float或double直接参与运算,会有精度损失
变量使用注意事项:
- 变量不初始化
- 在同一个作用域中不能定义重名的变量
- 不同作用域中的数据尽量不要调用
在小作用域中能直接访问大作用域的变量,但是大作用域中不能直接访问小作用域的变量
三. 标识符
给类,方法,变量取的名字
硬性规定
标识符可以包含“英文字母”“数字”“$和_”
标识符不能以数字开头
标识符不能是关键字
软性建议
给类取名:大驼峰式
四.数据类型转换
when?
a.等号左右两边类型不一致
b.不同类型的数据做运算
分类
a.自动类型转换
b.强制类型转换
基本类型按照取值范围从小到大排序
byte,short,char→int→long→float→double
自动类型转换
取值范围小的可以赋值给取值范围大的
取值范围小的和取值范围大的做运算
强制类型转换
将取值范围大的数据类型赋值给取值范围小的数据类型
float num1 = (float)1.5(小数默认类型是double)
注意事项:
精度损失,数据溢出
三 运算符
一. 算数运算符
任务类型的算术运算符遇见字符串,都会变成字符串
- 自增自减运算符
变量++ →后自加 ++ 变量→前自加 自增自减只变化1
混合使用: 符号在前先运算,符号在后先使用原值后运算(简单设计)
二. 赋值运算符
- 基本赋值运算符 =
先看等号右边的,再将等号右边的数据赋值给等号左边的变量
- 复合赋值运算符 +=,-=,/=,*=
i += 2 → i = i + 2(不可完全等价)
三. 关系运算符
- 结果:boolean ——> true,false
- == 符号前后相等
- <
- ≥
- ≤
- ≠
四. 逻辑运算符
作用:连接多个bollean结果的
结果:boolean结果
- && 有假则假,前为false,不继续执行运算
- || 有真则真,前为true,继续执行运算
- ! 不是true就是false
- ^ 符号前后结果一样为false,不一样为true
- & 如果符号前后都是数字,看作是位运算符,前为false,继续执行运算
- | 如果符号前后都是数字,看作是位运算符,前为true,继续执行运算
五. 三元运算符
- 格式 Boolean表达式?表达式1:表达式2
score ≥ 60 ? “及格”:”不及格”
四 常用的类
1.Scanner:键盘录入
-
导包 import java.util.Scanner
-
创建对象:Scanner sc = new Scanner(System.in)
-
调用方法
sc.nextInt() 录入一个整数
sc.next() 录入字符串,遇到空格或者回车就结束录入
sc.nextLine() 录入字符串,遇到回车就结束录入
2.Random:生成随机数
a.概述:java定义好的类
b.作用:在一个指定的范围内随机一个整数
c.使用:
- 导包:import java.util.Random
- 创建对象:Random ra= new Random()
- 调用方法:
ra.nextInt() 在int的取值范围内随机一个整数
ra.nextInt(int bound) → 在0→(bound-1)之间随机
3.switch
- a.格式
switch(变量){
case 常量值1:
执行语句1;
break
…..
default:
执行语句;
break;
}
4.if….else
- a.格式
if(表达式){
执行语句1
}else{
执行语句2
}
5.for循环
- 格式
for(初始变量;比较;步长语句){
执行语句
}
6.while循环
- 格式
while(比较){
循环语句
步进表达式
}
7.do… while
- 格式
do {
循环语句
步进表达式
}while(比较)
五 数组
一.数组的定义
- 数组概述:是一个容器,数组本身属于应用数据类型
- 作用:一次存储多个数据
- 特点:
a.既可以存储基本类型的数据,还能存储引用类型的数据
b.定长(定义数组是长度为多长,最多能存多少个数据)其实也是最大的缺点
- 定义:
a.动态初始化:在定义数组的时候,没有给具体的数据,只指定了长度
数据类型 数组名[] = new 数据类型[长度]
b.静态初始化:在定义数组的时候,我们直接给了数据
简化的静态初始化:数据类型 数组名[] = {元素1,元素2,…}
二.数组操作
- 获取数组的长度
- 格式:数组名.length
- 注意:length后不要带小括号,这是数组的属性,不是数组中的方法
- 索引
- 概述:元素在数组中的位置
- 索引都是从0开始,最大索引是数组长度减1
- 作用:我们要操作元素,必须通过索引来操作
- 存储元素
格式:数组名[索引]=赋值
- 获取元素
格式:数组名[索引]
细节说明:直接输出数组名,会输出数组在内存的地址值(数组在内存中的唯一标识)
如果数组中没有存储数据,直接获取也能获取出来一些数据(元素的默认值)
- 遍历元素
for(int i=0;i<arr.length;i++)
快捷键:数组名.fori
三.操作数组的两个常见的问题
- 数组索引越界异常 ArrayIndexOutOfBoundsException
- 原因:超出了数组的索引范围
- 空指针异常 NullPinterException
- 当数组对象为null时,操作数组元素
四.内存图
- 内存,可以理解为“内存条”,所有的软件,程序运行起来都会进入到内存中,占用内存,java将内存分为了五块
- 分为哪五块?
- a.栈(Stack)
主要运行方法,方法的运行都会进栈内存进行,运行完毕之后,需要“弹栈”腾出空间
- 堆(Heap)
保存的是对象,数组,每new一次,都会在堆内存中开辟空间,并为这个空间分配一个地址值,堆内存中的数据都是有默认值的
- 方法区(Method Area)
代码的“预备区”。记录了类的信息以及方法的信息,方法区中主要保存clas文件以及其中的信息
代码运行之前,需要先进内存(方法区)
- 本地方法栈(Native Method Stack)
本地方法可以理解为对java功能的扩展
- 寄存器(pc register)
五.二维数组
- 概述:数组中套了多个数组
- 定义:
- 动态初始化:数据类型 数组名[][] = new 数据类型[m][n]
- 静态初始化:数据类型 数组名[][] = { {元素1,元素2…..},{元素1,元素2…..}……
模块六 方法
一. 方法的使用
1.方法介绍以及简单方法定义
所有代码放在main方法中→代码太多,不好维护
解决:将不同的功能放在不同的方法中,想执行某个功能,直接调用方法名就行了
2.格式
修饰符 返回值类型 方法名(参数){
方法体
return 结果
}
3.通过通用格式可以分成四种方法来学习
a.无参无返回值
1.无参无返回值定义:
public static void 方法名(){
方法体->实现此方法的具体代码;
}
public static void farmer(){
.....
}
b.有参无返回值
public static void 方法名(数据类型 变量名){
方法体->实现此方法的具体代码
}
public static void add(int x,int y){
int sum = x + y;
System.out.println("sum += " + sum);
}
c.无参有返回值
public static 返回的数据类型 方法名(){
方法体->实现此方法的具体代码;
return 结果;
}
public static int ran(){
int num = math.random();
return num;
}
d.有参有返回值
public static 返回的数据类型 方法名(数据类型 变量名){
方法体->实现此方法的具体代码;
return 结果;
}
public static int add(int x,int y){
int sum = x + y;
return sum;
}
4.形式参数和时间参数的区别
形式参数:在定义方法的时候形式上定义的参数,此参数还没用值
实际参数:在调用方法的时候给形参赋予的具体的值
二.方法注意事项
- 方法不调用不执行
- 方法的执行顺序只和调用顺序有关
- 方法之间不能相互嵌套
- void 不能和[return 结果]共存,但是void能和[return]共存
a. void: 代表没有返回值
b. return 结果:就代表有返回值了
- 一个方法中不能连续写多个return
- 调用方法一定先定义
三.方法的重载
需求:实现一个函数,计算两个,三个,四个,五个整数相加
- 概述:方法名相同,参数列表不同的方法
2.什么叫参数列表不同;
- 参数个数不同
- 参数类型不同
- 参数类型顺序不同
方法重载的注意事项:
判断两个方法的是否为重载方法,和什么无关:
- 和参数名无关
- 和返回值无关
七 面向对象
一. 类和对象
1.面向对象的介绍
a.面向过程:自己的事情自己干,代表语言c语言
b.面向过程:自己的事情别人帮忙去干,代表语言Java语言
c.为什么要使用面向对象思想编程:简化了过程,减少了代码量
d.什么时候使用面向对象思想编程:调用别人的功能时
2.类和对象
2.1 类
1.测试类:带main方法的类,主要时运行代码的
2.实体类:是一类事务的抽象表示形式
组成部分:
a.属性(成员变量)
定义位置:类中方法外
作用范围:作用于当前类
定义格式:数据类型 变量名
默认值:整数:0,小数:0.0,布尔:false,引用:null,字符:'\\u0000'
b.行为(成员方法)
将static方法去掉,其他的一样
2.2 对象
1.概述:一类事物的具体表现
2.使用:
a.导包:import 包名.类名
如果两个类在同一个包下,想使用对方的成员不需要导包
如果两个类不在同一个包下,想使用对方的成员需要导包
b.创建对象:想要使用哪个类的成员,就new哪个类的对象
类名 对象名 = new 类名()
c.调用对象
想用使用哪个类的成员,就用哪个对象去调用
对象名.方法名()-->调用的是无参无返回值方法
对象名.方法名(实参)-->调用的是有参无返回值方法
数据类型 变量名 = 对象名.方法名()-->调用的是无参有返回值方法
数据类型 变量名 = 对象名.方法名(实参)-->调用的是有参有返回值方法
3.匿名对象的使用
1.int i = 10
a. int:数据类型
b. i:变量名
c 等号右边的10才是真正的数据
2.person p = new person()
a.等号左边的person:对象的类型,好比是int
b:p:对象名
c:等号右边的new person():真正的数据,是一个person对象,这个对象是真正创建出来了
所谓的匿名对象:其实就是没有等号左边的部分,只有等号右边的部分
3.使用
new 对象().方法()
//原始方式
person p = new person();
p.eat()
//匿名方式
new person().eat();
注意:
1.我们只是单纯的想调用一个对象的方法,可以用匿名对象
2.但是涉及到赋值,千万别用匿名对象
二. 成员变量和局部变量的区别
1.定义位置不同:
a.成员变量:类中方法外
b.局部变量:定义在方法之中或者参数位置
2.初始化值不同
a.成员变量:有默认值可以直接使用
b.局部变量:没有默认值不可以直接使用
3.作用范围不同
a.成员变量:作用于整个类
b.局部变量:作用于方法内部
4.内存位置不同
a.成员变量:在堆中,跟着对象走
b.局部变量:在栈中,跟着方法走
5.生命周期不同
a.成员变量:随着对象的创建而产生,跟着对象的消失而消失
b.局部变量:随着方法的调用而产生,随着方法调用完毕而消失
三. static关键字
1.概述:静态关键字
2.使用
a,修饰一个成员变量
b.修饰一个方法
3.调用静态成员,类名直接调用
4.特点
a.静态成员不属于对象,属于类成员
b.静态成员会随着类的加载而加载
c.静态成员优先于对象存在在内存中
d.凡是根据静态成员所在的类创建出来的对象,都可以共享这个静态成员
5.内存说明
jdk6:方法区
jdk7:堆(回收效率高)
从jdk7开始静态变量开始在堆中出现
6.static修饰成员的访问特点
1.在静态方法中能直接访问非静态成员吗?
不可
2.在非静态方法中能直接访问静态成员吗?
可
3.在静态方法中能直接访问静态成员吗?
可
4.在非静态方法中能直接访问非静态成员吗?
可
7.静态成员的使用场景
大量使用static关键字的问题:类一加载,静态成员就会进内存,会占用大量内存
静态成员什么时候定义?
一般情况下,我们在抽取工具类的时候就可以将工具类中的所有成员都定义成静态的
什么时候定义工具类?
我们在写代码的过程中,发现有的功能在反复实现,代码一样,功能一样就可以抽取出来,形成工具类
四. 可变参数
需求:
定义一个方法,实现n个整数相加
分析:
方法参数位置,只明确了参数的类型,但是不明确参数个数,此时就可以定义成可变参数
1.介绍和基本使用
定义格式
数据类型...变量名
public void sum(int...arr){
}
注意:
可变参数的本质是一个数组
参数位置不能连续写多个可变参数,而且当可变参数和其他参数一起使用时,可变参数需要放到参数列表最后
五.权限修饰
public:公共的,在哪里都能访问
protected: 受保护的
default: 默认的,注意:不写权限修饰符就是默认,不能直接把default写出来
private:私有的,只能在自己的类中直接访问
六.final关键字
1.格式:public final class 类名{}
2.特点:
被final修饰的类不可以被继承;
被final修饰的方法不能被重写;
final和abstract不能同时使用;
被final修饰的全局变量不能二次赋值;
被final修饰的对象地址值不能改变;
被final修饰的成员变量需要手动赋值,且不能二次赋值;
七.代码块
1.构造代码块
{
代码
}
构造代码块每次都优先于构造方法执行
2.静态代码块
static{
代码
}
静态代码块优先于构造代码块和构造方法,而且只执行一次
3.使用场景
如果想让数据优先初始化,而且只需要初始化一次,就可以将这些数据放到静态代码块中
八.内部类
当一个事物的内部,还有一个部分需要完整的结构去描述,而这个内部的完整结构又只为外部事物提供服务,那么整个内部的完整结构最好使用内部类
class A{
class B{
}
}
1.静态成员内部类
1.格式:直接在定义内部类的时候加上static关键字
public class A{
static class B{
}
}
2.注意:
a.内部类可以定义属性,方法,构造等
b.静态内部类可以被final或者abstract修饰
c.静态内部类不能调用外部的非静态成员
d.内部类还可以被四种权限修饰符修饰
3.调用方式
外部类.内部类 对象名= new 外部类.内部类()
2.非静态成员内部类
外部类.内部类 对象名= new [外部类().new](<http://外部类.new>) 内部类()
3.局部内部类
可以定义在方法中,代码块中,构造中
4.匿名内部类
概述:所谓的匿名内部类,可以理解为没有显示声明出类名的内部类
问题描述:我们如果想实现接口,简单使用一次抽象方法,就需要创建一个实现类,实现这个接口,重写抽象方法,还要new实现类对象,所以我们在想如果就单纯的想使用一次接口中的方法
格式:
new 接口/抽象类(){
重写方法
}.重写的方法();
八 封装
-
封装的介绍以及使用
1.面向对象的三大特征: 封装 继承 多态
2.什么是封装思想?
将细节隐藏起来,不让外界随便使用,但是我们可以提供一个公共的接口让外界间接使用隐藏起来的细节
3.private关键字
问题:定义成员变量,只要new出来对象,就可以随便调用,哪怕是不合理的值
解决:将属性封装起来
private(私有化)——>被private修饰的成员只能在本类中使用,在别的类中使用不了
修饰成员变量 private 数据类型 数据名;
问题:属性被私有化,外界调用不了,所以需要提供公共的接口操作属性
get/set方法
2.this关键字的使用
如果成员变量和局部变量重名时,我们遵循就近原则,优先使用局部变量
this:代表的是当前对象,this可以区分重名的成员变量和局部变量
哪个对象调用了this所在的方法,this就代表哪个对象
3.构造方法
1.概述:方法名和类名一致并且能初始化对象的方法
2.分类:
a.无参构造:没有参数
b.有参构造:有参数
3.特点:
a.方法名和类名一致
b.没有返回值,连void都没有
4.格式:
public 类名(){
}
每个类虚拟机会默认创建无参构造方法
作用:new 对象使用
4.标准JavaBean
JavaBean是Java语言编写类的一种标准规范
(1)类必须是具体的,plublic class 类名
(2)并且具有无参数的构造方法,有参构造
(3)成员变量私有化,并提供用来操作成员变量的get和set方法
controller -->专门和页面打交道的类(表现层)
service -->专门放业务处理的类(业务层)
dao -->专门放和数据库打交道的类(持久层)
pojo -->专门放JavaBean类
utils -->专门放工具类
*:快速生成JavaBean的通用键:alt+insert
5.方法参数
1.基本数据类型vs引用数据类型 基本数据类型: 4类8种:整数,浮点数,字符型,布尔型 引用数据类型: 除了基本数据类型,其他的都属于引用数据类型
2.基本类型作为方法传递 变量作为参数传递,传递不是变量本身,而是参数的值 方法运行:压栈 方法结束:弹栈
3.引用类型作为方法传递 变量作为参数传递,传递的是变量的地址值
九 继承
一.继承
- 什么是继承?
父类,子类
1.父类如何形成的?
我们定义了多个类,发现这些类中有很多重复性的代码,我们就定义了一个父类,将相同的代码抽取出来
放到父类中,其他的类直接继承这个父类,就可以直接使用父类中的内容了
2.如何去继承:extends
子类 extends 父类
3.注意
a.子类可以继承父类中的私有和非私有成员,但是不能使用父类中私有成员
b.构造方法不能继承
4.继承怎么学:
a.要从能否使用来学习
2.继承如何使用
1.定义一个父类,在其中定义重复性的代码
2.定义一个子类继承父类
子类 extends 父类
3.创建子类对象,直接继承父类中非私有成员
3.继承中成员变量的访问特点
成员变量:
父类对象不能调用子类的特有变量,子类对象可以调用父类的非私有变量
先看等号左边是谁,先调用谁中的成员,子类没有找父类
成员方法
父类对象不能调用子类的特有方法,子类对象可以调用父类的非私有方法
看new的谁,先调用谁的方法,子类没有找父类
4.方法的重写
1.概述:子类中有一个和父类方法名以及参数列表相同的方法
2.前提:继承
3.访问:看new的是谁,就先调用谁的,没有在去找父类的
4.检查是否为重写方法:在该方法上写
@Override
注意事项:
1.子类重写父类方法后,权限必须要保证大于等于父类权限(权限指的是访问权限)
public > protected > 默认
2.子类方法重写父类方法,方法名和参数列表要一样
3.私有方法不能被重写,构造方法不能被重写,静态方法不能被重写
4.子类重写父类方法之后,返回值类型应该是父类方法返回值的子类类型
使用场景:
某一个功能的升级改造,子类需要对父类的某一个功能进行升级改造
二.super和this
1.继承中构造方法的特点
1.注意
new子类对象时,会先初始化父类(优先走父类的无参构造)
2.原因:
每个构造方法的第一行,默认都会有一个super(),不写jvm自动提供一个
super()代表的是父类的无参构造
2.super和this的具体使用
super
1.概述:代表的是父类引用
2.作用:可以调用父类中的成员
3.使用:
a.调用父类构造方法-->在子类中的构造中写
b.调用父类成员变量
c.调用父类成员方法
this
1.概述:代表的是当前对象
2.作用
a.区分成员变量和局部变量
b.调用当前对象中的成员
3.使用:
a.调用当前对象的构造
b.调用当前对象的成员变量
c.调用当前对象的成员方法
4.不管是super还是this都必须在第一行使用,不能同时出现;
3.继承的特点
1.继承只支持单继承,不能多继承
2.继承支持多层继承
3.一个父类可以有多个子类
4.构造方法不能继承,也不能重写
私有方法可以被继承,不能被重写
静态方法可以被继承,不能被重写
三.抽象
1.将共有的方法抽取出来形成父类,但是抽取出来的方法没法确定,此时该方法不用写方法体了,没有方法
体的方法可以定义成抽象方法,抽象方法所在的类必须是抽象类
2.关键字abstract
3.定义抽象方法
修饰符 abstract 返回值类类型 方法名(参数):
4.抽象类
public abstract class 类名{}
5.抽象类里不是必须要存在抽象方法
注意:
a.抽象方法所在的类一定是抽象类
b.抽象类中不一定非得有抽象方法
c.子类继承抽象父类是,一定要冲重写父类中所有的抽象方法
d.抽象类不能new对象,只能通过new子类对象调用重写的方法
e.抽象类中可以有构造方法,其作用是子类初始化父类成员变量时使用的
6.可以将抽象类看成是一类事物的标准,要求只要是属于这一类的,都必须要拥有抽象类中的方法,必须
要实现--->重写
十. 接口
一.接口
1.接口是一种引用数据类型,是一种标准,规则
2.关键字
a.interface
public interface 接口名{}
b.implements
实现类 implements 接口名{}
3.接口中可以定义的成员:
a.jdk7以及之前:
抽象方法:public abstract --> 即使不写public abstract,默认也有
成员变量:public static final 数据类型 变量名 = 值 --> 即使不写public static final ,默认也有
b.jdk8
默认方法:public default 返回值类型 方法名(形参){}
静态方法: public static 返回值类型 方法名(形参){}
c.jdk9
私有方法:private 返回值类型 方法名(){}
3.1抽象方法
1.定义格式:
public abstract 返回值类型 方法名(形参){}
2.注意
不写 public abstract默认也有
3.使用
a.定义实现类
b.重写抽象方法
c.new对象调用
3.2 默认方法
1.定义格式
public default 返回值类型 方法名(形参){
方法体
return 结果
}
2.使用
a.定义实现类,实现接口
b.默认方法可重写,可不重写
c.new对象调用
3.3静态方法
1.定义格式
public static 返回值类型 方法名(形参){}
2.使用
接口名之间调用
默认方法和静态方法可以当作接口中临时加入的小功能
3.4成员变量
1.格式
public static final 数据类型 变量名 = 值
2.final
final修饰的变量不能再次赋值,可以看作常量
3.使用
接口名直接调用
4.接口的特点
1.接口可以多继承
2.接口可以多实现
3.一个子类可以继承一个父类的同时实现一个或者多个接口
4.当一个类实现多个接口时,如果接口中的抽象方法有重名且参数一样的,只需要重写一次
如果接口中的默认方法有重名且参数一样的,必修重写一次
5.接口和抽象类的区别
相同点:
a.都位于继承体系的顶端,用于被其他类实现或者继承
b.都不能new
c.都包含抽象方法,其子类或者实现类都必须重写这些抽象方法
不同点:
a.抽象类:一般作为父类使用,可以有成员变量,构造,成员方法,抽象方法等
b.接口:成员单一,一般抽取接口,抽取的都是方法,视为功能的大集合
c.类不能多继承,但是接口可以
二.多态
面向对象三大特征:封装,继承,多态
1.前提:
a.必须有子父类继承或者接口实现关系
b.必须有方法的重写,没有重写,多态没有意义,多态主要玩的就是重写方法
c.new对象:父类引用执行子类对象,理解为大类型接收了一个小类型的数据
2.注意
多态下不能调用子类的特有方法
3.多态条件下的成员访问特点
成员变量,看等号左边是谁,先调用谁的
成员方法,看new的是谁,就先调用谁的
4.为什么学多态?
多态方式和原始方式new对象的优缺点:
原始方式:
a.优点:既能调用重写的,还能调用父亲非私有的,还能调用自己特有的
b.缺点:拓展性差
多态:
a.优点:拓展性强->用父类类型接口,可以传递任意它的子类对象,接受哪个子类对象就指向哪个子类对象
就调用哪个子类对象重写后的方法
b.缺点:不能直接调用子类特有功能
5.多态中的转型
5.1向上转型
父类引用指向子类对象
5.2向下转型
将大类型强制转成小类型
想要调用子类特有功能,需要向下转型
instance of判断数据类型
十一. 异常
一.API文档
1API:Application Programing Interface,检查API,又称为应用编程接口
(定义出来的类以及接口,以及其中的方法)
为了方便我们去查询开发好的接口以及类,以及其中的方法,会提供一个对应的文档-→API文档
2API文档的作用:查询我们要使用的对象以及方法,是我们程序员的“字典”
二.异常
1.异常介绍以及出现过程
概述:相当于代码出现了错误,在java中,异常都是一个一个的类
Throwable类有两个子类,Error,Exception。
Exception又分为编译时期异常(Excepiton以及子类除了RuntimeException)和运行时期异常(RuntimeException及其子类)
编译时期异常:
当我们调用方法的时候,该方法底层给我们抛了一个编译时期异常,所以才导致我们一调用此方法,一编译,就爆红了。当我们一旦触发了这个异常,jvm就会将异常信息打印到控制台上,给程序员看
运行时期异常:
运行时候才会出现,一层一层的往上抛
2.创建异常对象
3.异常处理的两种方式
异常处理的两种方式-try…catch
catch多个异常
1.格式:
try{
可能出现的异常
}catch(异常 对象名){
处理异常的代码-->将异常信息保存到日志文件中
}catch(异常 对象名){
处理异常的代码-->将异常信息保存到日志文件中
}catch(异常 对象名){
处理异常的代码-->将异常信息保存到日志文件中
}
2.注意:
如果catch的多个异常之间有子父类关系,可以直接抛出父类Exception
如果不知道多个异常之间有子父类异常的继承关系,可以之间抛出Exception
4.finally关键字
finally关键字
1.概述:代表的是不管是否触发了异常,都会执行的代码块
特殊情况:如果之前执行了System.exit(0)终止当前正在执行的java虚拟机
2.使用:都是配合try...catch使用
try{
可能出现的异常
}catch(异常 对象名){
处理异常的代码-->将异常信息保存到日志文件中
}finally{
不管是否有异常,都会执行的代码
}
3.使用场景:
1.关闭资源
2.对象如果没有用了,GC回收,回收堆内存中的垃圾,释放内存,有一些对象GC会回收不了,就需要手动
关闭,此时就可以将关闭资源的代码放在finally中
5.抛异常时注意的事项
抛异常时注意的事项
1. 如果父类中的方法抛了异常,那么子类要不要抛?
可抛可不抛
2. 如果父类中的方法没有抛异常,那么子类要不要抛?
不能抛
6.try…catch和throws的使用时机
try…catch和throws的使用时机
1.如果处理异常之后,还需要代码继续执行,使用try...catch
2.如果方法直接是递进关系(调用),我们可以先throws,但是到了最后需要用try...catch做一个
的异常处理
3.编译时期异常必须处理
运行时期异常一般不处理
7.自定义异常
自定义异常
需求:登录功能,登录失败,抛出LoginException,此时需要自定义异常
public class LoginException extends Exception{}
1.定义一个类
2.如果继承Exception就是编译时期异常
3.如果继承RunTimeException就是运行时期异常
8.打印异常信息的三个方法
打印异常信息的三个方法
Throwable类中的方法:
String toString():输出的异常类型和设置的异常信息
String getMessage():输出的是异常信息
void printStackTrace():输出的异常信息最完整,包含异常信息和出现异常的行数
十二. 基础API
一.String字符串
1.概述:String代表字符串
2.特点:
a.Java程序中所有字符串字面值(“abc”)都作为此类的实例(对象)实现
b.字符串是常量,它们的值在创建之后就不能更改了
c.String对象是不可变的,所以可以共享
二.String的实现原理
1.jdk8的时候:String的底层是一个被final修饰的char数组
2.jdk9的时候:String的底层是一个被final修饰的byte数组
字符串定义好以后,数组就创建好了,被final修饰,数组的地址就直接定了
三.String的创建
1.String()-->利用String的无参构造创建String对象
2.String(String original) -->根据字符串创建String对象
3.String(byte[] byetes) -->通过平台的默认字符集解码指定的byte数组,构建一个新的String对象
平台:操作系统 操作系统默认字符集:GBK
GBK:一个中文占两个字节 UTF-8:一个中文占三个字节
4.String (char[] value) -->通过char数组创建String对象
5.简化格式:
String 变量名 = “”
其他构造方法:
1.String(char value[], int offert, int count) -->将char数组一部分转成String对象
2.String(byte bytes[], int offert, int lengrh) -->将byte数组一部分转成String对象
6.判断方法
equals() equalsIgnoreCase()
7.获取方法
length() concat(String s) charAt(int index) indexOf(String S) subString(索引,结束索引)
8.转换方法
toCharArray() getBytes() getBytes(String charsetName) replace(c1,c2)
9.分割方法
split(String regex)
四.StringBuilder
1.概述:一个可变的字符串序列,此类提供了一个StringBuffer兼容的一套API,但是不保证同步(线程不安全,效率高)
2.作用:主要是字符串拼接
3.为什么需要StringBuilder?
原因:Sting没拼接一次,都会产生新的字符串对象,如果拼接次数过多,会占用内存,效率比较低
StringBuilder,底层自带一个缓冲区(没有被final修饰的byte数组)拼接字符串之后都会在这个缓冲区中保存,在拼接过程中不会随意产生对象
4.StringBuilder的特点
a.底层自带缓冲区,此缓冲区是没有被final修饰的byte数组,默认长度为16
b.如果超出了数组长度,数组就会自动扩容
c.默认每次扩容老数组的2倍+2
特殊情况:超出了(2n+2),就按照实际个数为准
五.StringBuilder常用方法
1.构造
StringBuilder()
StringBulder(String str)
2.常用
StringBuilder append(任意类型数据) ——>字符串拼接,返回的是StringBuilder自己
StringBuilder reverse()——>字符串翻转,返回的是StringBuilder自己
String toString()——>将StringBuilder转成String
十三. 常用API
一.数学相关类
1.概述:数学工具类
2.作用:主要用于数学运算
3.特点:
a.构造方法私有化
b.方法是静态的
4.使用:
类名直接调用
static int abs(int a) -->求参数的绝对值
static double ceil(double a) -->向上取整
static double floor(double a) -->向下取整
static long round(double a) -->四舍五入
static int max(int a,int b) -->求两个数之间的较大值
static int min(int a,int b) -->求两个数之间的较小值
二.BigInteger
1.概述:数据非常大,比long还大,这种数据我们一般称之为“对象”
2.作用:处理超大参数
3.构造:
BigInteger(String val)--> 参数的格式必须是数学形式
4.方法
BigInteger add(BigInteger val) 返回值为(this+val)的BigInteger
BigInteger subtract(BigInteger val) 返回值为(this-val)的BigInteger
BigInteger multiply(BigInteger val) 返回值为(this*val)的BigInteger
BigInteger divide(BigInteger val) 返回值为(this/val)的BigInteger
三.BigDecimal
1.问题描述:float或者double直接参与运算,可能会导致精度损失
2.作用:主要是解决float和double直接做运算出现的精度损失的问题
3.构造方法:
BigDecimal(String val)-->val必须是数字形式
4.常用方法:
static BigDecimal ValueOf(double val)-->传入的是double
BigDecimal add(String val) 返回值为(this+val)val
BigDecimal subtract(String val) 返回值为(this-val)val
BigDecimal multiply(String val) 返回值为(this*val)val
BigDecimal divide(String val) 返回值为(this/val)val
注意:如果除不尽会报错,出现运算异常
BigDecimal divide(String val,scale,RoundingMode roundingMode)
四.Date日期类
1.概述:表示特定的瞬间,精确到毫秒
2.常识
a.1000ms = 1s
b.时间原点:1970年1月1日,0时0分0秒,叫做格林威治时间
c.时区:北京位于东八区,一个时区经度差15度,时间相差一个小时,所以北京时间比时间原点所在的时区时间差8个小时
3.使用
Date() --> 获取当前系统时间
Date(long time) --> 获取指定时间,传递毫秒值 --> 从时间原点开始算
4.常用方法
1.void setTime(long time) --> 设置时间,传递毫秒值 --> 从时间原点开始算
2.long getTime() -->获取时间,返回毫秒值
五.Calendar日历类
1.概述:日历类,抽象类
2.获取:Calendar中的方法:
Calendar calender = Calendar.getInstance();
3.常用方法
int get(int filed) -->返回给定日历字段的值
void set(int filed,int value) -->将给定的日历字段设置为指定的值
void add(int filed,int amount) -->为日历字段添加或者减去指定的时间量
Date getTime() -->将calender转成Date对象
filed:代表的是日历字段->年 月 日 星期等,都是静态的
六.SimpleDateFormat日期格式化类
1.概述:日期格式化类
2.构造
SimpleDateFormat(String pattern)
3.pattern代表的是我们自己指定的日期格式
yyyy-MM-dd HH:mm:ss
4.方法
1.String format(Date date) -->将Date对象按照指定的格式转成String
2.Date parse(String source) -->将符合日期格式的字符串转成Date对象
七.jdk8新日期类
1.LocalDate本地日期
概述:LocalDate是一个不可变的日期时间对象,表示日期,通常被视为年月日
2.获取
static LocalDate now() -->创建LocalDate对象
static LocalDate of(int year,int month,int dayofMonth) -->创建LocalDate对象,设置年月日
3.LocalDateTime对象
概述:LocalDateTime是一个不可变的日期时间对象,代表日期时间,通常被视为年-月-日-时-分-秒
4.获取:
static LocalDateTime now() -->创建LocalDateTime对象
static LocalDateTime of(int year,int month,int dayofMonth,int hour,int minute,int second) -->创建LocalDate对象,设置年月日时分秒
八.System类
1.概述:系统相关类,是一个工具类
2.特点:
a.构造私有,不能利用构造方法new对象
b.方法都是静态的
3.使用:
类名直接调用
九.Array数组工具类
1.概述:数组工具类
2.特点:
a.构造私有
b.方法静态
3.使用:类名直接调用
十.包装类
1.概述:就是基本类型对应类(包装类),我们需要将基本类型转成包装类,从而让基本类型拥有类的特性
2.为什么需要包装类?
特定场景,调用方法传递包装类
eg:ArrayList集合,里面有一个add(Integer 1),此时我们不能调用add方法之后直接传递基本类型,因为引用类型不能直接接收基本类型的值,就需要先将基本类型转成包装类,传递到add中
十四. 多线程
一.多线程的基础知识
1.进程:进入到内存中执行的应用程序
2.线程:进程中最小的执行单元,负责当前进程中程序的运行,一个进程中至少需要一个线程,当然也可以拥有多个线程
简单理解:一个应用有许多功能,一个功能需要一个线程去执行
3.使用场景:
软件中的耗时场景,所有的聊天软件,所有的后台服务器
一个线程可以干一件事,我们就可以同时干多件事,提高了CPU的利用率
4.并行与并发
并行:在同一时刻,有多个任务在多个CPU上同时执行
并发:在同一时刻,有多个指令在CPU上交替执行(之前CPU是单核,CPU在多个功能之间做高速切换,人类无法感知)
5.CPU调度
1.分时调度:平均分配每个线程占用cpu的时间片
2.抢占式调度:多个线程轮流抢占cpu使用权
java是抢占式调度
6.主线程介绍
主线程:CPU和内存之间为main方法开辟的通道
二.多线程的创建
1.多线程的创建——继承Thread类
1.继承Thread类
2.重写run方法,在run方法中设置线程任务
3.创建自定义线程类的对象
4.调用Thread类的start方法,开启线程,jvm自动调用run方法
2.多线程内存情况
注意:同一个线程对象不能连续调用多次start
3.Thread类中的方法
void start() ----->开启线程,jvm自动调用run方法
void run() ----->设置线程任务
String getName() ----->获取线程名字
void setName() ----->设置线程名字
static Thread currentThread --->获取正在执行的线程对象
static void sleep --->线程睡眠,超时后自动醒来继续执行
重写的run方法中只能try,不能throws,原因:继承的Thread中的run方法没有
抛异常,所有在子类中重写完不能抛异常
4.Thread中的其他的方法
String getPriority() -->获取当前线程优先级
void setPriority(int newPriority) -->设置线程优先级,最小优先级1,
默认优先级5,最大优先级10
void setDaemon(boolean on) -->设置为守护线程,当非守护线程结束,守护
线程随之结束,守护线程也不是立马结束,系统通知其结束,这个通知的过程,
守护线程仍然会继续执行
使用场景:关闭聊天框,传送资料线程随之结束
static void yield() -->礼让线程,让出当前cpu使用权
场景说明:有两个线程同时出现,可能会执行一会线程A,再执行一会线程B,那么
我们能不能让两个线程执行的平衡一点,交替执行
void join() -->插入线程或者叫做插队线程
5.多线程的创建——实现Runnable接口
1.创建类,实现Runnable接口
2.重写run方法,设置线程任务
3.利用Thread构造方法:Thread(Runnable target)
4.调用Thread的start方法,开启线程,jvm自动调用run方法
6.两种实现多线程的方式区别
1.继承Thread:继承只能单继承,具有局限性
2.实现Runnable:没有继承的局限性
7.匿名内部类创建多线程
严格意义上来说,匿名内部类方式不属于创建多线程方式其中之一,因为匿名内
部类形式建立在实现Runnable接口的继承上实现的
三.线程安全
1.什么时候发生:当多个线程访问同一个资源的时候,导致了数据有问题
线程安全问题----->代码不安全的代码
三个线程可能操作同一张票,数据存在安全问题
原因:cpu在多个线程间做高速切换导致
解决办法:上锁
2.解决线程安全问题的第一种办法(使用同步代码块)
1.格式:
synchronized(任意对象){
线程可能出现不安全的代码
}
2.任意对象:就是我们的锁对象
3.执行
一个线程拿到锁之后,会进入到同步代码块中执行,在此期间,其他线程拿不到锁,
就进不去同步代码块,需要在同步代码块外面等待排队,需要等这执行的线程执行
完毕,出了同步代码块,相当于锁释放了,等待的线程才能抢到锁,才能进入到同
步代码块中执行
3.解决线程安全的第二种方法(同步方法)
1.格式
修饰符 synchronized 返回值类型 方法名(参数){
方法体
return 结果
}
1.格式
修饰符 static synchronized 返回值类型 方法名(参数){
方法体
return 结果
}
2.默认锁:class对象
四.死锁
1.死锁
概述:指的是两个或者两个以上的线程在执行的过程中由于竞争同步锁而产生的一种阻塞现象,如果没有外力作用,他们讲无法继续执行下去,这种情况称为死锁
2.死锁的原因分析
对资源的竞争,每个线程分别需要其他线程的资源才能继续执行,但每个线程都不愿意放弃自己的资源,导致每个线程都无法顺利的执行完成,以致于发生了死锁
五.线程状态
1.线程状态介绍
概述:当线程被创建并启动以后,它既不是一启动就进入了执行状态,也不是一直处于执行状态。在线程的生命周期中,java的枚举给出了6种线程状态
2.线程状态图
六.等待唤醒机制
要求:一个线程生产,一个线程消费,不能连续生产,不能连续消费
-->等待唤醒机制(生产者消费者,线程之间的通信)
void wait() -->线程等待,在等待过程中会释放锁,需要被唤醒
void notify() -->线程唤醒,一次唤醒一个等待线程
wait()和notify()需要由锁对象调用,且必须是同一个锁对象
七.Lock锁
1.概述:Lock是一个接口
2.实现类:ReentrantLock
3.方法:
lock() 获取锁
unlock() 释放锁
synchronized:不管是同步代码块还是同步方法,都需要在一对{}之后,
锁释放对象
lock:是通过两个方法控制需要被同步的代码,更灵活
八.Callable接口
1.概述:Callable<V>是一个接口,类似于Runnable
2.方法
V call() -->设置线程任务的,类似于run方法
3.call与run方法的区别
a.相同点:都是设置线程任务的
b.不同点:call方法有返回值,而且有异常可以throws
run方法没有返回值,而且有异常不可以throws
4.<V>
a.<V>叫做泛型
b.泛型:用于指定我们操作什么类型的数据,<>中能写引用数据类型,如果泛型
不写,默认是Object类型数据
c.实现Callable接口,指定泛型是什么类型的,重写的call方法返回值就是什
么类型的
5.获取call方法的返回值:FutureTask<V>
a.FutureTask<V>,实现了一个接口:Future<V>
b.FutureTask<V>中有一个方法:
V get() -->获取call方法的返回值
九.线程池
1.问题:之前来一个线程任务,就需要创建一个线程对象去执行,用完还需要销
毁线程对象,如果线程任务多了,就需要频繁创建线程对象和销毁线程对象,
这么做会耗费内存资源,所以我们就像线程对象能不能循环利用,用的时候直接
拿线程对象,用完还回去
2.线程池的使用
a.创建线程对象,指定池子中最多能有多少条线程对象
b.来了线程任务,看池子中有没有线程对象,如果没有,创建线程对象,给线程任
务用,用完还回去
c.如果池子中没有空闲线程,等着之前的线程任务执行完毕,归还了线程对象再使
用,用完了还回去
3.创建-->Executors
4.获取线程池对象:Executors中的静态方法:
static ExecutorService newFixedThreadPool(int nThreads)
a.参数:指定线程池中最多创建的线程对象条数
b.返回值ExecutorService是线程池
3.提交线程任务:ExecutorService中的方法
Future<?> submit(Runnable task) 提交一个Runnable任务用于执行
Future<V> submit(Callable<T> task) 提交一个Callable任务用于执行
4.submit方法的返回值:Future接口
用于接收run方法或者call方法返回值的,但是run方法没有返回值,所以可以
不用Future接收,执行call方法需要Future接收
5.ExecutorService中的方法
void shutdown() -->线程池关闭,不接收新的线程任务
十.定时器_Timer
1.概述:定时器
2.构造:Timer()
3.方法:
void schedule(TimeTask task, Date firstTime, long period)
task:抽象类,是Runnable的实现类
firstTime:从什么时间开始执行
period:每隔多长时间执行一次,设置的是毫秒值
十五.集合
一.集合框架
1.之前我们学了保存数据的有:变量,数组,但是数组定长
所以需要一个长度可变的容器,集合
2.集合的特点
a.只能存储引用数据类型的数据
b.长度可变
c.集合中有大量的方法,方便我们操作
3.分类
a.单列集合:一个元素就一个组成部分
list.add("张三")
b.双列集合:一个元素有两部分组成:key和value
map.put("fam","run") -->key,value叫做键值对
集合:
a.特点
b.使用
二.Collection接口
1.概述:单列集合的顶级接口
2.使用:
a.创建
Collection<E> 对象名 = new 实现类对象<E>()
b.<E>:泛型,决定了集合中能存储什么类型的数据,可以统一元素类型
泛型只能写引用数据类型,如果不写,默认Object类型,此时什么类型的
数据就都可以存储了
c.泛型细节:
等号前面的泛型必须写,等号后面的泛型可以不写,jvm会根据前面的泛型进行推
导,可推导即可不写
3.常用方法:
boolean add(E e) 将给定的元素添加到当前集合中
boolean addAll(Collection<? extends E> c) 将另外一个集合元素添加到当前集合中
void clear() 清除集合中的所有元素
boolean contains(Object o) 判断当前集合是否包含指定的元素
boolean isEmpty() 判断当前集合中是否有元素
boolean remove(Object o) 将指定的元素从集合中删除
int size() 返回集合中的元素个数
Object[] toArray() 把集合中的元素,存储到数组中
三.迭代器
1.概述:Iterator
2.主要作用:遍历集合
3.获取:Collection中的方法:
Iterator<E> iterator()
4.方法:
bollean hasNext() -->判断集合中有没有下一个元素
E next() -->获取下一个元素
迭代器迭代原理
int cursor //下一个元素索引位置
int lastRet = -1 //上一个元素索引位置
获取Iterator
Iterator iterator = list.iterator()
Iterator是一个接口,等号右边一定是它的实现类对象
Iterator接收的到底是哪个实现类对象呢? ->ArrayList的内部类Itr对象
四.数据结构
栈:先入后出
队列:先进先出
数组:查询快,增删慢,通过索引操作元素,数组定长
链表:增删快,查询慢,通过指针操作元素
五.List接口
1.List接口时Collection接口的子接口
2.常见的实现类
ArrayList LinkedList Vector
六.ArrayList集
1.概述:ArrayList是List接口的实现类
2.特点:
a.元素有序
b.元素可重复
c.有索引
d.线程不安全
3.数据结构:数组
4.底层源码
a.ArrayList() 构造一个初始容量为十的空列表,不是new
的时候创建,而是第一次add的时候才创建容量为十的空列表
b.ArrayList(int initialCapacity) 构造具有指定初始
容量的空列表
ArrayList数组底层是数组为什么长度可变呢?
会自动扩容--->Array.copyOf()
扩容多少倍?--->1.5倍
七.LinkedList集合
1.概述:LinkedList是List接口的实现类
2.特点:
a.元素有序
b.元素可重复
c.有索引(本质没有)
d.线程不安全
3.数据结构:双向链表
八.增强for循环
1.作用:
遍历集合或者数组
2.格式:
for(元素类型 变量名:要遍历的集合名或者数组名){
变量名就是代表的每一个元素
}
3.快捷键:
集合名或者数组名.for
4.注意
增强for遍历集合时原理是迭代器
增强for遍历数组时原理时普通for
不管是迭代器还是增强for,都不要在遍历集合的过程中随
意修改集合长度,否则会出现并发修改异常
九.Collection集合工具类
1.概述:集合工具类
2.特点:
a.构造私有
b.方法都是静态的
3.使用:类名直接调用
4.方法
static <T> boolean addAll(Collection<? super T>c,T...elements)
-->批量添加元素
static void shuffle(List<?> list) ->将集合中的元素顺序打乱
static <T> void sort(List<T> list)->将集合中的元素按照默认规则排序
static <T> void sort(List<T> list, Comparator<? super T> c)
->将集合中的元素按照指定规则排序
Comparator比较器
a.方法:
int Compare(T,O1,T,O2)
o1-o2-->升序
o2-o2-->降序
Arrays中的静态方法:
static <T> List<T> asList(T...a)
-->直接指定元素,转存到list集合中
List<String> list = Arrays.asList("张三"李四");
十.泛型
1.概述
1.泛型:<>
2.作用:
统一数据类型,防止将来的数据转换异常
3.注意:
a.泛型中的类型必须是引用类型
b.如果泛型不写,默认为Object
2.含有泛型的类定义
1.含有泛型的类定义
public class 类名<E>{
}
public class MyArrayList<E>{
Object[] = new Object[10];
int size = 0;
public boolean add(E e){
obj[size] = e;
size++;
return true;
}
}
2.什么时候确定类型?
创建具体的对象的时候
3.含有泛型的方法
1.格式:
修饰符 <E> 返回值类型 方法名(E e)
2.什么时候确定类型?
调用的时候确定类型
public static <E> boolean addAll(ArrayList<E> list,E...e){
for(E element:e){
list.add(element);
}
}
4.含有泛型的接口
1.格式:
public interface 接口名<E>{
}
2.什么时候确定类型?
a.在new实现类的时候确定类型
b.在实现类接口的时候确定类型,比如Scanner
public interface MyList <E>{
public boolean add(E e);
}
public class MyarrayList<E> implements MyList<E>{
Object[] = new Object[10];
int size = 0;
public boolean add(E e){
obj[size] = e;
size++;
return true;
}
}
public class Test{
public satic void main(String[] args){
MyarrayList<String> list = new MyarrayList<>();
list.add("张三");
}
}
5.泛型的上限下限
<?> ?代表的是泛型通配符
1.作用:可以规定泛型的范围
2.上限:
a.格式<? extends 类型>
b.含义?只能接收extends后面的本类类型以及子类类型
3.下限:
a.格式:<? super 类型>
b.含义:?只能接收super后面的本类类型以及父类类型
十一.斗地主案例
1.案例介绍:
按照斗地主的规则,完成洗牌发牌的动作
2.具体规则:
使用54张牌打乱顺序,三个玩家参与游戏,三人交替摸牌,
每人17张牌,最后三张留作底牌
3.案例分析:
准备牌
牌可以设计为一个ArrayList<String>,每个字符串一张牌
每张牌由花色和数字两个部分组成,我们可以使用花色集合与数字集合嵌套迭代完成每张牌的组装,牌由Collection类的shuffle进行随机排序
发牌
将每个人的底牌设计为ArrayList<String>,最后三张牌直接放于底牌,剩余牌通过对3取模依次发牌
看牌
直接打印每个集合
4.代码实现
package FightLandlord;
public class plate {
int number;
String suit;
public plate(){}
public plate(int number, String suit) {
this.number = number;
this.suit = suit;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getSuit() {
return suit;
}
public void setSuit(String suit) {
this.suit = suit;
}
@Override
public String toString() {
return "plate{" +
"number=" + number +
", suit='" + suit + '\'' +
'}';
}
}
package FightLandlord;
import java.util.ArrayList;
import java.util.Collections;
public class FightLandlord {
public static void main(String[] args) {
ArrayList<plate> list = new ArrayList<>();
int i= 0,j = 0,k =1;
while (i < 52) {
if(j == 0 ){
list.add(new plate(k,"black"));
j++;
i++;
} else if (j == 1) {
list.add(new plate(k,"red"));
j++;
i++;
} else if (j == 2) {
list.add(new plate(k,"sakura"));
j++;
i++;
} else if (j == 3) {
list.add(new plate(k,"square"));
j++;
i++;
}else {
j = 0;k++;
}
}
list.add(new plate(14,"small"));
list.add(new plate(15,"big"));
Collections.shuffle(list);
ArrayList<plate> list1 = new ArrayList<>(); //玩家1
ArrayList<plate> list2 = new ArrayList<>(); //玩家2
ArrayList<plate> list3 = new ArrayList<>(); //玩家3
ArrayList<plate> list4 = new ArrayList<>(); //底牌
int l = 0;
for (plate plate : list) {
if(l<51){
if(l % 3 == 0){
list1.add(plate);l++;
} else if (l % 3 ==1) {
list2.add(plate);l++;
}else {
list3.add(plate);l++;
}
}else{
list4.add(plate);l++;
}
}
System.out.println(list1);
System.out.println(list2);
System.out.println(list3);
System.out.println(list4);
}
}
十二.红黑树
1.每一个结点或是红色的,或者是黑色的
2.根节点必须是黑色
3.如果一个结点没有子结点或者父节点,则该节点相应的指
针属性为Nil,Nil是黑色的,视为叶节点
4.如果某一个节点是红色,那么它的字节点必须是黑色
5.对于一个节点,从该节点到其所有后代叶节点的简单路径
上,均包含相同数目的黑色节点
优点:查询速度特别快
集合加入红黑树的目的就是提高查询效率
HashSet集合:
数据结构:哈希表
jak8之后:哈希表=数组+链表+红黑树
十三.Set集合
Set接口并没有对Collection接口进行功能上的扩展,且底层
的实现都是依靠Map
Map的遍历需要先变成单栏结合,只能变成set
HashSet
1.概述:HashSet是Set接口的实现类
2.特点
a.元素唯一
b.元素无序
c.无索引
d.线程不安全
3.数据结构
a.jdk8之前:哈希表 = 数组 + 链表
b.jdk8之后:哈希表 = 数组 + 链表 + 红黑树
4.方法:和Collection一样
5.遍历:
a.增强for
b.迭代器
LinkedHashSet
1.概述:LinkedHashSet extends Hashset
2.特点:
a.元素唯一
b.元素有序
c.无索引
d.线程不安全
3.数据结构:
哈希表+双向链表
4.使用:和HashSet一样
5.遍历:
a.增强for
b.迭代器
哈希值
1.概述:是由计算机算出来的一个十进制数,可以看作是对
象的地址值
2.获取对象的哈希值,使用的是Object中的方法
public native int hashCode()
注意:
哈希值是通过地址值计算的,可以把哈希值看作地址值
但是注意一个问题,String的底层重写了hashCode的方法
会计算对象内容的hashCode
哈希值不一样,内容肯定不一样
哈希值一样,内容也有可能不一样
在计算哈希值的时候有一个定值是31,这是一个质数,经过
统计认为用31,可以尽可能的降低内容不一样但是哈希值一
样的情况(哈希冲突,哈希碰撞)
3.字符串的哈希值是如何进行计算的?
String = "abc"
byte[] value = {97,98,99}
hashset的存储去重复的过程
原理:
1.先计算元素的哈希值(重写hashCode方法),再比较内容
(重写equals方法)
2.先比较哈希值,如果哈希值不一样,存
3.如果哈希值一样,再比较内容,内容不一样,存
内容也一样,去重
存储自定义类型
自定义类型要去重,就要重写hashCode方法和equals方法
十四.map集合
1.map介绍
1.概述:双列集合的顶级接口
2.元素特点:
都是由key和value组成
3.框架
1.HashMap(实现Map)
特点:
a.key唯一,value可重复
b.无序
c.无索引
d.线程不安全
e.可以存null
数据结构:哈希表
2.LinkedHashMap(继承HashMap):
特点:
a.key唯一,value可重复
b.有序
c.无索引
d.线程不安全
e.可以存null
数据结构:哈希表+双向链表
3.Hashtable(实现Map)
特点:
a.key唯一,value可重复
b.无序
c.无索引
d.线程安全
e.不可以存null
数据结构:哈希表
4.Properties(继承Hashtable)
特点:
a.key唯一,value可重复
b.无序
c.无索引
d.线程安全
e.不可以存null
f.key和value都是String
数据结构:哈希表
5.TreeMap(实现Map)
特点:
a.key唯一,value可重复
b.可以对key进行排序
c.无索引
d.线程不安全
e.不可以存null
数据结构:红黑树
2.HashMap的介绍和使用
1.概述:HashMap是Map的实现类
2.特点:
a.key唯一,value可重复-->key重复了,会发生value覆盖
b.无序
c.无索引
d.线程不安全
e.可以null
3.数据结构:哈希表
4.方法
V put(K key, V value) -->返回的是被覆盖的value
V remove(Object key) -->根据key删除键值对,返回的是被删除的value
V get(Object key) -->根据key获取value
boolean containsKey(Object key) -->判断集合中是否包含指定的key
Collection<V> values() -->获取集合中所有的value,转存到Collection集合中
3.LinkedHashMap
1.概述:LinkedHashMap extends HashMap
2.特点:
a.key唯一,value可重复-->key重复了,会发生value覆盖
b.有序
c.无索引
d.线程不安全
e.可以null
3.数据结构:哈希表+双向链表
4.使用和HashMap一样
4.遍历
map的遍历都转成单列集合(set)
1.先获取key,再通过key获取value
Set<String> set = map.keySet();
for(String key : set){
System.out.println(key+":"+map.get(key));
}
2.同时获取key和value
a.先获取记录key和value的对象,Map接口中的静态内部类接口:Map.Entry
b.调用Map.Entry中获取key和value的方法
entry.getkey()
entry.getvalue()
十五.TreeSet
1.概述:set的实现类
2.特点:
a.对元素进行排序
b.无索引
c.不能存null
d.线程不安全
e.元素唯一
3.数据结构:红黑树
4.构造
TreeSet()
TreeSet(Comparator<? super E> comparator)构造一个新的空的TreeSet,根据
指定的比较器进行排序
十六.TreeMap
1.概述:map的实现类
2.特点
a.可以对key进行排序
b.无索引
c.key唯一
d.线程不安全
e.不能存null
3.数据结构:红黑树
4.构造
TreeMap()
TreeMap(Comparator<? super E> comparator)构造一个新的空的TreeMap,根据
指定的比较器进行排序
十七.Properties集合
1.概述:Properties继承自HashTable
2.特点
a.key唯一
b.无序
c.无索引
d.线程安全
e.不能存null
f.key和value默认为String
3.数据结构:哈希表
4.特有方法:
Obiect setProperty(String key,String value) -->存键值对
String getProperty(String key) -->根据key获取value
Set<String> stringPropertyNames() -->获取所有的key,保存set集合中,相当于
keySet方法
void load(InputStream inStream) -->将流中的数据加载到Properties集合中
十六.IO流
一.File类
计算机常识:
1.以.jpg结尾的一定是图片吗?
不一定,有可能是文件夹
2.什么是文本文档?
用记事本打开,人能看懂的文件 -->txt html css
3.E:\Idea\io\1.jpg,其中1.jpg的父路径是什么?
E:\Idea\io
4.分隔符:
a.路径名称分割符:
windows:\
linux:/
b.路径分隔符:一个路径和其他路径之间的分隔符
;
1.file类概述:
文件和目录路径名的抽象表示
2.简单理解:
我们在创建file对象的时候,通常需要传递一个对象,这个路径定位到哪个文件或者文件夹,
我们的file就代表哪个对象
3.file的静态成员:
static String pathSeparator:与系统有关的路径分割符,它被表示为一个字符串
File.pathSeparator// ;
static String separator:与系统有关的默认名称分割符,它被表示为一个字符串
File.separator// \
4.File的构造方法
File(String parent, String child) 根据所填写的路径创建File对象
parent:父路径
child:子路径
File(File parent, String child) 根据所填写的创建File对象
parent:父路径,是一个File对象
child:子路径
File(File pathname) 根据所填写的创建File对象
pathname:直接指定路径
5.File的获取方法
String getAbsolutePath() -->获取绝对路径
String getPath() -->获取封装路径
String getName() -->获取文件或者文件夹名称
long length() -->获取的是文件的长度(文件的字节数)
6.File的创建方法
boolean createNewFile() -->创建文件
boolean mkdirs() -->创建文件夹
7.File的删除方法
boolean delete() -->删除文件
慎用:
1.如果删除,不走回收站
2.只能删除文件夹,且也不走回收站
8.File的判断方法
boolean isDirectory() -->判断是否是文件夹
boolean isFile() -->判断是否是文件
boolean is exists() -->判断是否存在
9.File的遍历
String[] list() file.list() -->遍历指定的文件夹,返回的是String数组
File[] listFiles() -->遍历指定的文件夹,返回的是File数组
10.绝对路径和相对路径
a.绝对路径:从盘符开始写路径
E:\\idea\\io\\1.txt
b.相对路径:不从盘符开始写路径
1.txt
c.针对idea中写相对路径
哪个路径是参照路径,哪个路径就可以省略不写,剩下的就是在idea中的相对路径写法
其实就是从模块名开始写
二.字节流
1.IO流介绍以及输入输出以及流向的介绍
Output:输出
Input:输入
write:写数据
read:读数据
2.IO流
将一个设备上的数据传输到另外一个设备上,称之为IO流技术
3.IO流的作用
之前学习了集合和数组,但都是临时存储(代码运行完毕,集合
和数组会从内存中消失,从而数据就不存在了),所有集合和数
组达不到永久保存的目的,要达到永久保存数据的需求,就需要
将数据保存到硬盘上
4.IO流的流向——争对se阶段的io
参照物:内存
内存——>硬盘 Output
硬盘——>内存 Input
要是电脑和电脑之间做数据传输,就是相对的
发数据一方:输出
收数据一方:输入
5.IO流分类
字节流:万能流,一切皆字节
字节输出流:OutputStream 抽象类
字节输入流:IuputStream 抽象类
字符流:专门操作文本文档
字符输出流:Writer 抽象类
字符输入流:Reader 抽象类
字节输出流
OutputStream中子类[FileOutputStream]的介绍以及方法的简
单介绍
1.概述:字节输出流,OutputStream是一个抽象类
2.子类:FileOutputStream,往硬盘上面写数据
3.构造
FileOutputStream(File file)
FileOutputStream(String name)
4.特点:
a.指定的文件如果没有,就会自动创建
b.每执行一次,都会创建一个新的文件,覆盖老的文件
5.方法
void write(int b)一次写一个字节
void write(byte[] b)一次写一个字节数组
void write(byte[] b, int off, int len)一次写一个字节数
组的一部分
void close()关闭资源
6.字节流续写
FileOutputStream(String name,boolean append)
append:true ->实现续写对象,不进行覆盖
换行:
a.windows: \r\n->占两个字节 \n
b.linux: \n
c.mac os: \r
字节输入流
1.概述:IuputStream,是一个抽象类
子类:FileInputStream
2.作用:读数据,将数据从硬盘中读到内存中来
3.构造:
FileInputStream(File file)
FileInputStream(String path)
4.方法
int read() 一次读一个字节,返回的是读取的字节
int read(byte[] b) 一次读一个字节数组,返回的是读取的字节个数
int read(byte[] b, int off, int len) 一次读取一个字节数组的一部分,返回的是读
取的字节个数
void close() 关闭资源
注意:
1.流读完之后不要在读,除非新new一个对象
2.流关闭以后,就不能在使用流对象了
3.每个文件末尾都会有一个“结束标记”,而read方法规定如果读到了文件的结束标记,则
直接返回-1
三.字符流
字节流读取中文的问题:
字节流是万能流,更侧重于文件复制
字节流读取中文的问题:不同的中文在不同的编码中所占字节数不同
UTF-8:一个中文占3个字节
GBK:一个中文占2个字节
字符流专门操作文本文档,但是复制不要用字符流,用字节流
字符数输入流
1.概述:字符输入流->Reader->是一个抽象类
子类:FileReader
2.作用:将文本文档中的内容读取到内存中来
3.构造:
FileReader(File file)
FileReader(String path)
4.方法:
int read() 一次读取一个字符
int read(char[] cbuf) 一次读一个字符数组,返回的是读取的字符个数
int read(cahr[] cbuf, int off, int len)一次读取一个字符数组的一部分,返回的是
读取的字符个数
void close()
字符输出流
1.概述:字符输出流->writer->抽象类
子类:FileWriter
2.作用:将数据写入文件中
3.构造:
FileWriter(File file)
FileWriter(String filename)
FileWriter(String filename,boolean append)
4.方法:
void write(int c)
void write(char[] cbuf)
void write(char[] cbuf, int off, int len)
void write(String str)
void close()
5.注意:FileWriter自带一个缓冲区,写的数据会先保存到缓冲区中,写的数据需要再写
到文件中,所以必须关流才能写入刷新
flush():将缓冲区中的数据刷到文件中
close():先刷新后关闭
IO异常处理的正确写法
FileWriter fw = null;
try{
fw = new FileWriter(Filename)
fw.write("你好")
}catch(Exception e){
e.printStackTrace();
}finally{
if(fw != null){
try{
fw.close();
} catch (IOEception e){
e.printStackTrace();
}
}
}
JDK7之后:
1.格式:
try(IO对象){
可能出现的异常的代码
}catch(异常类型 对象名){
处理异常
}
2.注意:以上格式处理IO异常,会自动关流
四.字节缓冲流
1.为什么需要字节缓冲流?
基本流:FileInputStream,FileOutputStream,FileReader,FileWriter
FileInputStream,FileOutputStream的读写方法都是本地方法,与硬盘打交道,效率不高
缓冲流中自带一个长度为8192的数组,读写都是在内存(缓冲区)中完成,读写效率高
2.字节缓冲流
a.BufferOutputStream
b.BufferIutputStream
3.问题
1.使用缓冲流时,只需要关闭缓冲流,不用关闭基本流?
缓冲流的close底层会自动关闭基本流
2.缓冲流的读写过程
先依靠基本流读出数据,然后交给缓冲流,由于缓冲流缓冲区是8192,所以每次读取8192个字节放到缓冲
区中,然后再将输入流缓冲区中的数据交给输出流缓冲区,然后再将基本流数据写到硬盘上
那么在操作代码时len是干啥的呢?其实主要是在两个缓冲区中倒腾数据,将输入缓冲区中的数据读到,
然后写到输出流缓冲区中,等待输出流缓冲区满了,再依靠基本流写到硬盘上,如果输入流缓冲区中的数据
读不到了,重现从硬盘上读取8192个数据
五.字符缓冲流
BufferedWriter
1.构造
BufferedWriter(writer w)
2.方法:
用起来和FilerWriter一样
3.特有方法:
newline() 换行
BufferedWriter
1.构造
BufferedWriter(Reader w)
2.方法:
用起来和FilerReader一样
3.特有方法:
String readline() -->一次读一行
六.转换流
1.字符编码
计算机中存储的信息都是二进制表示的,而我们在屏幕上看到的数字,英文,标点符号,汉字等字符都是二
机制转换后的结果。【按照某种规则,将字符存储到计算机中,称为编码】,反之,解析出来,称为解码。
2.字符集
asc字符集,GBK字符集,Unicode字符集
3.如果编码解码不一致,还是会出现乱码的问题
InputStreamReader
1.概述:是字节通向字符流的桥梁 --> 读数据
2.构造:
InputStreamReader(InputStream in, String charsetName)
charsetName:指定编码,不区分大小写
OnputStreamWriter
1.概述:是字符流通向字节流的桥梁
2.构造:
OnputStreamWriter(OutputStream in, String charsetName)
charsetName:指定编码,不区分大小写
七.序列化流
序列化流和反序列化流介绍
1.作用:读写对象
2.两个对象:
a.ObjectOutputStream -->序列化流-->写对象
b.ObjectInputStream -->反序列化流-->读对象
3.注意
将对象序列化到文件中,我们打开文件看不懂,我们只需将这些内容成功读回来即可
ObjectOutputStream
1.作用:写对象
2.构造
ObjectOutputStream(Object obj)
3.方法
writerObject(Object obj) -->写对象
4.注意:
想要将对象序列化到文件中,被序列化的对象需要实现Serializable接口
ObjectInputStream
1.作用:读对象
2.构造:
ObjectInputStream(Object obj)
3.方法:
ReaderObject() -->读对象
八.Properties集合
Properties结合io流使用方法
Properties结合io流使用方法回顾:
1.概述
Properties extends Hashtable
2.特点:
a.无序,无索引
b.key唯一,value可重复
c.线程安全
d.key和value默认都是String
3.特有方法
setProperty(String key,String value) 存键值对
getProperty(String key) 获取键值对
stringPropertyNames() 获取所有的key放到Properties集合
load(IuputStream in) 将流中所有数据加载到Properties集合
使用场景:配合配置文件使用
注意:我们不能将硬数据放到代码中
创建配置文件:
1.在模块下建立.properties
2.在下面中写配置文件
a.key=value
b.key和value都是String,且不加引号
c.每个键值对写完后再写下一行
d.键值对只见最好不要有空格
e.键值对中不建议写中文
eg:
jdbc.username=root
jdbc.password=1234
九.Commons-io工具包
1.介绍
Apache软件基金会,开发了IO技术的工具类,大大简化了IO开发
2.使用第三方开发来的工具,都需要添加第三方提供给我们的jar包,需要将jar包解压到我们当前的目录下
IOUtils类
-静态方法 IOUtils.copy(Inputstream in,OutputStream out)传通字节流,实现文件复制
-动态方法 IOUtils.closeQuietly(任意流对象)
FileUtils类
-静态方法 FileUtils.copyDirectorToDirectory(File src,File dest);
传递File类型的目录,进行整个目录的遍历
src:要复制的文件夹路径
dest:要将文件夹粘贴的位置
-静态方法 writerStringToFile(File file, String str) 写字符串到文本文件中
-动态方法 String readFileToString(File file) 读取文本文件返回字符串
十七.网络编程
一.网络编程
1. 软件结构
C/S架构
客户端和服务端,eg:QQ
B/S架构
浏览器和服务器,eg:谷歌
2.服务器概念
概述:安装了服务器软件的计算机
3.通信三要素
ip地址,协议,端口号
UDP编程
发送端
1.创建DatagramSocket对象(快递公司)
a.空参:端口号从可用的端口号中随机一个使用
b.有参:自己指定
2.创建DatagramSocket对象,将数据进行打包
a.要发生的数据-->byte[]
b.指定接收端的ip
c.指定接收端的端口号
3.发送数据
4.释放资源
服务端
1.创建DatagramSocket对象,指定服务端的端口号
2.接收数据包
3.解析数据包
4.释放资源
TCP编程
1.创建socket对象,指明服务端的ip以及端口号
2.调用socket中的getOutputStream,往服务端发送请求
3.调用socket中的getInputStream,读取服务端响应的数据
4.关流
1.创建ServerSocket对象,设置端口号
2.调用ServiceSocket中的accept方法,等待客户端连接
3.调用ServiceSocket中的getInputStream,读取客户端发送的数据
4.调用ServiceSocket中的getOutputStream,往客户端发送响应
5.关流
二.Lombok
1.作用:简化JavaBean开发
2.使用:
a.下插件-->idea2022以后自带
b.导lombok的jar包
c.修改设置
3.常用注解
@Getter
@Setter
@ToString
@AllArgsConstructor
@NoArgsConstructor
@Data
@EqualsAndHashCode
十八.jdk新特性
一.Lambda表达式
1.面向对象思想:JAVA核心编程思想
强调的是找对象,帮我们做事
2.jdk8开始产生了新的思想:函数式编程思想
强调的是结果,不强调过程
3.在函数式编程思想的继承上产生了Lambda表达式
a.格式:
()->{}
b.各部分解释:
():重写方法的参数设置
->:将参数传递到方法体中
{}:重写方法的方法体
可推导即可省略
4.Lambda表达式使用前提
必须是函数式接口方法做参数传递。
函数式接口:有且只有一个抽象方法的接口
检测方法:@FunctionInterface
5.Lambda表达式省略规则
a.观察是否是函数式编程接口做方法的参数传递
b.如果是,考虑Lambda表达式
c.调用方法,以匿名内部类的形式传递实参
d.改写成Lambda表达式
二.函数式接口
1.函数式接口:有且只有一个抽象方法的接口
2.检测方法:@FunctionInterface
3.JDK提供的函数式接口
Supplier
Consumer
Function
Predicate
三.Stream流
1.Stream流中的流不是io流,它是一种编程方式,可以看作是流水线
2.Stream的获取
针对集合:Collection中的方法
Stream <E> stream()
针对数组:Stream接口中的静态方法
static <T> Stream<T> of(T... vaules)
四.方法引用
1.方法引用的介绍
概述:引用方法
时机:
a.被引用的方法要写在重写方法里面
b.被引用的方法从参数上,返回值要和所在重写方法一致,且引用的方法最好是操作重写方法的参数值的
c.干掉重写方法的参数;干掉->;干掉被引用方法的参数-> 将被引用方法的.改成::
十九.反射注解枚举
一.Junit单元测试
1.概述:Junit是一个单元测试框架,可以代替main方法去执行其他的方法
2.作用:可以单独执行一个方法,测试该方法是否能够跑通
3.Junit是第三方工具,使用之前需要导入jar包
4.使用:在方法上面加上@Test
5.注意事项:
@Test不能修饰静态方法
@Test不能修饰带参数的方法
@Test不能修饰带返回值的方法
6.相关注解
@Before 在@Test之前执行,用于初始化数据
@After 在@Test之后执行,用于释放资源
二.类的加载时机
1.new对象
2.new子类对象
3.执行main方法
4.调用静态成员
5.利用反射创建Class对象
三.反射
万物皆对象
Class文件-->有对象-->Class对象-->描述class对象的类叫做Class类
成员变量 -->有对象-->Field对象-->描述Field对象的类叫做Field类
成员方法 -->有对象-->Method对象-->描述Method对象的类叫做Method类
构造方法 -->有对象-->Constructor对象-->描述Constructor对象的类叫做Constructor类
反射:
1.概述:解剖Class对象的一个技术
2.问题:能解剖class对象的什么?
a.解剖出成员变量:赋值
b.解剖出成员方法:调用
c.解剖出构造方法:创建对象
3.获取Class对象
a.方式一:调用Object中的getClass方法
Class <?> getClass()
b.方式二:不管是基本类型还是引用类型,jvm都为其提供了一个静态成员:class
c.方式三:Class类中的静态方法
static Class<?> forName(String className)
className:传递的是类的全限定名
最通用的一种:方式3
开发中最常用的:方式2-->简单
四.注解
一.注解的定义
1.引用数据类型:
类 数组 接口 枚举 注解
2.作用
说明:对代码进行说明,生成doc文档(API文档)
检查:检查代码是否符合条件
分析:对代码进行分析,起到了代替配置文件的作用
3.注解的定义以及属性的定义格式
这里说的注解属性,其实本质上是抽象方法,但是我们按照属性来理解
a.定义:
public @interface 注解名{
}
b.定义属性:增强注解的作用
数据类型 属性名() -->此属性没有默认值,需要在使用注解的时候为其赋值
数据类型 属性名() default 值-->此属性有默认值,可以二此赋值
c.注解中能定义什么类型的属性
8中基本类型,String类型,class类型,枚举类型,注解类型,以上类型的一维数组
二.注解的使用
1.注解的使用:为注解中的属性值赋值
2.使用位置:
类上使用,方法上使用,成员变量上使用,局部变量使用,参数位置使用等
3.使用格式:
a.@注解名(属性名= ,....)
b.如果属性中有数组
@注解名(属性名={元素1,元素2...})
三.注解的解析
说白了就是将注解中的属性值获取出来
1.注解解析涉及到的接口:AnnotatedElement接口
2.解析思路:
先判断指定位置上有没有使用指定的注解,如果有,获取指定的注解,获取注解中的属性值
a.boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
-->判断指定的位置上有没有指定的注解
eg:判断BookShelf有无Book注解
Class bookShelf = BookShelf.class
bookShelf.isAnnotationPresent(Book.class)
b.getnnotation(Class<T> anntationClass)-->获取指定的注解,返回值为获取的注解类型
eg:获取BookShelf的Book注解
Class bookShelf = BookShelf.class
boolean result = bookShelf.isAnnotationPresent(Book.class)
Book book = bookShelf.getnnotation(Book.class)
四.元注解
1.概述:管理注解的注解
2.从哪些方面进行管理
a.控制注解的使用位置
b.控制注解的生命周期
3.怎么使用
a.@Target:控制注解的使用位置
b.@Retention:控制注解的生命周期
五.枚举
1.概述:五大引用数据类型:类 数组 接口 注解 枚举
2.定义
public enum 枚举类名{
}
3.使用:类名直接调用
4.使用场景:主要表示对象的状态