JAVA基础

JAVA

搭建Java开发环境

搭建Java开发环境
    安装JDK(Java开发工具集)时会安装JRE(Java运行环境)
    步骤:
        1,找到JDK1.8安装包
        2,安装JDK与JRE
        3,配置环境变量
            1,新建一个变量
                变量名:JAVA_HOME
                变量值:JDK安装路径
            2,修改Path变量
                变量值尾部追加:
                    %JAVA_HOME%\bin
                    %JAVA_HOME%\jre\bin
            3,新建一个变量
                变量名:CLASSPATH
                变量值:.
​
测试Java环境是否搭建成功
    步骤:
        1,打开DOS命令框
            注意:从新打开DOS命令框
        2,输入以下命令
            java:运行class文件(字节码文件)
            javac:生成class文件
            java -version
    注意:
        如果此时测试成功,后期对java没有任何修改.在从新启动电脑后,java或javac显示无效命令.这是windows系统的bug.解决方案,从新打开环境变量,打开path变量,查看.确定.从新打开dos命令框就OK
​
​
注意:
    因为有些小伙伴安装过java,所以先卸载
    步骤:
        1,打开控制面板,卸载Java
        2,删除环境变量
            打开文件管理器,在其左边栏选择此电脑
            右键,选择属性
            点击高级系统设置
            点击环境变量
            查看用户变量path中是否有java相关变量,有的就删除
            查看系统变量中是否存在CLASSPATH与JAVA_HOME有的就删除整个变量
            查看系统变量的Path变量中是否有java相关,有的就删除相关的条
            点击确定

编写第一个java程序

步骤:
    1,在D盘下找一个文件夹
    2,在该文件夹下新建一个文本文档,起名为HelloWorld.java
    3,在该文件中编写以下代码
        class HelloWorld{
            public static void main(String[] args){
                System.out.println("Hello World");
            }
        }
        注意:
            1,以上代码中的标点符号全在英文状态下输入
            2,以上代码中大小写不能有错
    4,保存

编译Java程序

步骤:
    1,打开DOS命令框
    2,进入Java文件所在的文件夹
    3,使用javac命令,将java文件编译为class文件

运行class文件

步骤:
    1,打开DOS命令框
    2,进入class文件所在的文件夹
    3,使用java命令运行class文件

名词

JDK:Java开发工具集
JRE:Java运行环境
JVM:Java虚拟机
API:Java的说明书
GC:Java垃圾回收机制

深入了解HelloWorld

1,class前有public的类称为公共类
	公共类的特点:
		1,公共类的类名必须与文件名一致
		2,一个Java文件中只能有一个公共类

2,一个Java文件中可以定义多个类,每个类都会生成其对应的class文件,该class文件的文件名,就是对应的类的类名

3,一个Java文件中定义的多个类的类名不能相同

4,String[] args:在运行class文件时传入的参数

注释

作用:
	1,解释说明,提高代码的可读性
	2,修改代码,注销无用代码
特点:
	不会影响代码的运行
Java的注释
	//单行注释

	/*
		多行注释
		122
		333
	*/

	/**
		文档注释
		111
		222
	*/
	开发工具的快捷键:
		1,选中需要注释的内容
		2,ctrl+/

输出

输出内容后换行
	System.out.println(要打印的内容);
输出内容后不换行
	System.out.print(要打印的内容);

注意:
	1次只能打印1个内容

数据类型

基本数据类型
	整数
		byte		1字节			8位		取值范围:-2^7~2^7-1		-128~127
     short		2字节			16位		取值范围:-2^15~2^15-1	
		int			4字节			32位		取值范围:-2^31~2^31-1				默认的整数类型
		long		8字节			64位		取值范围:-2^63~2^63-1				值后加l或L
	小数(浮点数)
		float		4字节			32位		值后加f或F
		double		8字节			64位		默认的小数类型
	字符
		char		2字节
			hello world:由11个字符组成
			你好世界:由4个字符组成
			注意:
				需要使用''包裹
				如:
					'a'
					'b'
					''
					'1'		
	布尔
		boolean		1字节
			取值:
				true:真
				false:假

引用数据类型
	所有类的对象都是引用数据类型.其对应的数据类型就是其类名
	引用数据类型有无数种
	String	字符串		由JDK提供的
		注意:值需要使用""包裹
		如:
			"abc"
			"你好世界"
			""
			"1"

标识符

作用:标记的符号
如:类名,变量名,常量名,方法名,注解名,枚举名,包名等都是标识符

命名规范
	强制要求
		1,不能使用数字开头
		2,不能使用特殊符号,_与$除外
		3,不能使用关键字或保留字
			目前学的关键字有:
				byte int short long float double char boolean
				true false
			见过的关键字有
				public class static void
			还没有学的关键字
				final abstract interface extends implements
				instanceof menu @interface
				for while do if else switch break continue return
				...
	潜规则
		1,不建议使用中文
		大驼峰
			一般应用与类名,注解名,枚举名,接口名
			规则:每个单词首字母大写
			如:
				Hello
				HelloWorld
				RenLei
				GouLei
				HongAn
			注意:见名知意

		小驼峰
			一般应用与变量名,方法名
			规则:第一个单词首字母小写,其他单词首字母大写
			如:
				hello
				helloWorld
				num
				shuZi
			注意:见名知意

		全大写
			一般应用于常量名
			规则:每个字母大写
			如:
				HELLO_WORLD
		全小写
			一般应用与包名
			规则:每个字母都小写
			如:
				com.qf.demo01

关键字

在Java中有有特殊含义的单词
目前学的关键字有:
	byte int short long float double char boolean
	true false
见过的关键字有
	public class static void
还没有学的关键字
	final abstract interface extends implements
	instanceof menu @interface
	for while do if else switch break continue return

保留字

暂时没有特殊含义的关键字

变量

作用:记录可以一个值可以被改变的数据
例子:
	2023年3月28日,刘去广州出差,入住都市快捷酒店502房.大床房.于2023年3月29日退房.袁入住502

	2023年3月28日		502房的客人		-		刘
	2023年3月29日		502房的客人 	-		袁

变量使用步骤:
	1,声明
	2,赋值
	3,使用

声明:
	语法:
		数据类型 变量名;
	如:
		声明一个变量记录人的年龄
		int age;
		在声明一个变量记录另一个人的年龄
		int age01;
	注意:
		同一个作用域下变量名不能相同
		可以声明多个变量

赋值:
	语法:
		变量名 = 值;
	如:
		age = 18;
		age = "18";		错
	注意:
		等号两边数据类型要相同
		一个变量可以赋值多次

使用:
	语法:
		变量名

	如:
		1,打印age变量
		System.out.println(age);
		System.out.println("age");		注意:使用变量时不要加""号,如果使用了,那么该打印的内容是字符串,与变量无关

特殊情况:
	声明并赋值
		语法:
			数据类型 变量名 = 值;

名词:
	初始化:变量的第一次赋值称为变量的初始化

运算符

算数运算符

+:加法
-:减法
*:乘法
/:除法
%:取余

++:自增
	++在后,先参与运算,在递增
	++在前,先递增,在参与运算符
--:递减
	--在后,先参与运算,在递减
	--在前,先递减,在参与运算符

注意:
	小类型与大类型进行运算结果为大类型
	会余到整数位
	*,/,%优先级相同,高于+,-

	int a = 3;
	int b = 4;
	请计算	(++a) + (a++) + (++b) + (b++) 的结果
	4 + 4 + 5 + 5 = 18

赋值运算符

=:将等号右边的值,赋值给左边的变量
	int a = 10;
	int b = a;
	注意:
		1,等号两边数据类型要相同
		2,如果等号两边数据类型不同,要么是小类型转换为大类型,要么是大类型转换为小类型
			小类型转换为大类型,自动转换
			如:
				double d = 1.0f;
				int a = 'a';
			大类型转换为小类型,强制转换
			语法:
				小类型 变量名 = (小类型) 要转换的值或变量;
			如:
				byte b = (byte) 128;
				char c = (char) 97;

+=:加等
	int a = 1;
	int b = 2;
	//a = a + b;
	a += b;
-=
	int a = 1;
	int b = 2;
	//a = a - b;
	a -= b;
*=
	int a = 1;
	int b = 2;
	//a = a * b;
	a *= b;
/=
	int a = 1;
	int b = 2;
	//a = a / b;
	a /= b;
%=
	int a = 1;
	int b = 2;
	//a = a % b;
	a %= b;

关系运算符

<:小于
>:大于
<=:小于或者等于
>=:大于或者等于
==:
	基本数据类型判断值是否相同
	引用数据类型判断内存地址是否相同
!=:
	基本数据类型判断值是否不相同
	引用数据类型判断内存地址是否不相同

逻辑运算符

&&:短路与
	同真为真,有假为假	
	如:
		10 < 12 && 10 > 20;
||:短路或
	有真为真,全假为假
	如:
		10 < 1 || 10 > 2;
!:非
	非真为假,非假为真
	!(10 < 2) 		true
	!(10 > 2)		false

字符串连接符

+

如:
	"Hello" + "World"		"HelloWorld"
	"World" + "Hello"		"WorldHello"

区分字符串连接符与算法运算符加法,看符号两边是否有字符串.如果有字符串就是字符串连接符,否则是算法运算符加法
如:
	1 + 2 + 3		6		算数运算符
	1 + 2 + "3"		"33"
	"1" + 2 + 3		"123"

注意:所有类型的数据使用字符串连接符,结果都为字符串

三目运算符

名称:
	三元运算符
语法:
	条件表达式?值1:值2;

	条件表达式:结果为boolean型的表达式都是条件表达式
	当条件表达式结果为true,取值1.如果条件表达式结果为false取值2

位运算符

二进制
	0000	0001	0010	0011	0100	0101	0110	0111	1000
八进制
	0	1	2	3	4	5	6	7	10	11	12...
十进制
	00	01	02	03	04	05	06	07	08	09	10
十六进制
	0	1	2	3	4	5	6	7	8	9	a	b	c	d	e	f	10

二进制转换为十进制
	0001 0010
		1 * 2 ^	(5 - 1) + 1 * 2^1 
		16 + 2
		18
	0000 1011
		1 * 2^3 + 0 + 1 * 2^1 + 1 * 2^0
		8 + 0 + 2 + 1
		11
八进制转十进制
	17
		1 * 8^1 + 7 * 8^0
		8 + 7
		15
十六进制转十进制
	AF
	10 * 16 ^1 + 15 * 16^0
	160 + 15
	175

十进制转二进制

十进制转八进制

十进制转十六进行

<<:不带符号向左移
>>:不带符号向右移
>>>:带符号向右移
&:与
|:或
^:异或

语句分类

顺序语句

代码从上向下依次执行

分支语句

在多个分支选择执行其中一个

循环语句

重复执行一段代码

分支语句

作用:判断

分类:

if
switch

if

基础的if结构
	语法:
		if(条件表达式){
			当条件表达式值为true时,执行此处代码
		}

if else结构

if else结构
	语法:
		if(条件表达式){
			当条件表达式值为true时,执行此处代码
		}else{
			当条件表达式值为false时,执行此处代码
		}
	注意:
		1,else可有可无
		2,else只能有一个
		3,else不能单独存在

else if结构

语法:
		if(条件表达式1){
			当条件表达式1为true,执行此处代码
		}else if(条件表达式2){
			当条件表达式2为true,执行此处代码
		}else if(条件表达式3){
			当条件表达式3为true,执行此处代码
		}
		...
		else if(条件表达式n){
			当条件表达式n为true,执行此处代码
		}else{
			当以上条件全为false,执行此处代码
		}
	注意:
		else if可以有多个
		当上面的条件,将不会判断下面的条件
总结
	if的语法:
		if(条件表达式1){
			当条件表达式1为true,执行此处代码
		}else if(条件表达式2){
			当条件表达式2为true,执行此处代码
		}else if(条件表达式3){
			当条件表达式3为true,执行此处代码
		}
		...
		else if(条件表达式n){
			当条件表达式n为true,执行此处代码
		}else{
			当以上条件全为false,执行此处代码
		}
	注意:
		1,else if可以有多个
		2,else if可以一个都没有
		3,else if不能独立存在
		4,else 可有可无,最多只能有一个
		5,当多个条件同时满足时,只会执行最上面的那个

switch

语法:
	switch(变量名){
		case 常量1:
			当变量值等于常量1时,执行此处代码
			int a;
		break;
		case 常量2:
			当变量值等于常量2时,执行此处代码
		break;
		...
		case 常量n:
			当变量值等于常量n时,执行此处代码
		break;
		default:
			当变量值不等于以上常量时,执行的代码
		break;
	}

	常量:代码在编译后无法修改的值或变量称为常量
	break:跳出当前代码块,case中可以没有break,但是如果没有会导致贯穿
	swicth中case后的常量不能相同
	JDK1.5以后switch可以判断字符串内容是否相同
	switch只能判断值相等,if可以判断区间,也可以判断值是否相同

变量的作用域

概念:变量声明的代码块,为这个变量的作用域(就是这个变量可以使用的范围)

Scanner

简介:由JDK提供的一个类
作用:键盘录入
使用:
	1,导包
		语法:import java.util.Scanner;
		书写位置:类上
	2,创建Scanner对象
		语法:
			Scanner 变量名 = new Scanner(System.in);
	3,等待用户输入
		输入字符串
			String 变量名2 = 变量名.next();
			变量名2:就是用户输入的内容
		输入整数
			int 变量名2 = 变量名.nextInt();
			变量名2:就是用户输入的内容

循环语句

作用:重复执行一段代码

分类

while
do while
for

while

语法:
	while(条件表达式){
		当条件表达式为true,执行此处代码
		当此处代码执行完毕后,在判断条件表达式是否为true,如果为true,在此执行此处代码
		如果为false结束循环
	}

do while

语法:
	do{
		先执行此处代码,在判断条件表达式是否为true
		如果为true,在此执行此处代码
		如果为false结束循环
	}while(条件表达式);
while:先判断,在执行
		do while:先执行在判断

for

作用:简化语法
语法:
	for(表达式1;表达式2;表达式3){
		循环体4
	}
	表达式1:初始化变量
	表达式2:循环条件
	表达式3:修改变量
	循环体4:重复执行的代码
执行流程:
	1,2,4,3,2,4,3,2,4,3....2
	注意:表达式1只执行一次

名词解释

死循环:无法结束的循环
循环嵌套:在循环语句中使用循环语句

转意字符

概念:有特殊含义的字符

\t:制表
\":双引号字符
\':单引号字符
\n:换行
\r\n:标准换行

流程控制语句

break:跳出当前循环

continue:跳过本次循环

标记

定义标记
	语法:
		标记名:
使用标记
	语法:
		break 标记名;//跳出标记的循环
		continue 标记名;//跳过本次标记的循环

方法(函数)

引入

描述一个人吃饭的过程

作用

封装一段代码,使其便于使用

优点

1,降低耦合度
2,提高复用率
3,提高代码的编写效率
4,方便使用

步骤

1,定义
2,调用

定义

位置:
	类中,方法以外

1,无参无返回值的方法
	语法:
		public static void 方法名(){
			方法体
		}
	练习:
		定义一个方法计算10+20的结果
2,有参无返回值的方法
	语法:
		public static void 方法名(形参列表){
			方法体
		}
	注意:
		1,形参列表的语法:数据类型 变量名,数据类型变量名,...
		2,多个参数直接使用逗号隔开
		3,参数的数量不限
	练习:
		定义一个方法计算两数之和
3,无参有返回值的方法
	语法:
		public static 返回值类型 方法名(){
			方法体
		}
	注意:
		return:单独使用,表示结束当前方法
		return xxx:表示结束当前方法,并返回xxx的值
		返回值类型:就是返回值的数据类型,要与xxx的数据类型一致
		void:表示没有返回值或返回值为null
		一个方法只能有一个返回值
		一个方法中使用分支语句,导致有多个return xxx,此时要保证返回的数据类型一致
		一个方法如果有返回值类型,一定要保证有返回值,并且返回值的数据类型要与返回值类型一致
4,有参有返回值的方法
	语法:
		public static 返回值类型 方法名(形参列表){
			方法体
		}
	练习:
		定义一个方法,计算两数之和,并返回计算的结果

5,总结
	语法:
		访问权限修饰符 修饰符 返回值类型 方法名(形参列表){
			方法体
		}
		访问权限修饰符:暂时使用public
		修饰符:暂时使用static
		返回值类型:就是返回值的数据类型.如果没有返回值,返回值类型为void.null表示为空
		方法名:自定义,见名知意,小驼峰.一个类中不能出现方法名相同,形参列表也相同的方法
		形参列表:可有可无
			本质:声明的多个变量,使用逗号隔开
		方法体:
			return:结束当前方法
			return xxx:结束当前方法,并返回xxx.注意此时返回值类型要与xxx的数据类型一致.只能返回一个

调用

位置:
	方法中
1,调用无参无返回值的方法
	语法:
		方法名();
2,调用有参无返回值的方法
	语法:
		方法名(实参列表);
	注意:
		实参列表要与形参列表一致(长度一致,顺序一致,数据类型一致)(*)
3,调用无参有返回值的方法
	语法:
		方法名();
		或
		数据类型 变量名 = 方法名();
	注意:
		调用有返回值的方法,可以使用变量接收也可以不接收
		但是调用无返回值的方法,一定不能使用变量接收
4,调用有参有返回值的方法
	语法:
		方法名(实参列表);
		或
		数据类型 变量名 = 方法名(实参列表);
5,总结
	语法:
		1,方法名(实参列表);
		2,数据类型 变量名 = 方法名(实参列表);
	注意:
		1,实参列表要与形参列表一致(长度一致,顺序一致,数据类型一致)
		2,调用无返回值的方法只能使用语法1
		3,调用有返回值的方法可以选择使用语法1也可以选择使用语法2

特殊情况

多重调用

方法调用方法
A,B,C
	A中调用B,在B中调用C

重载

要求:
	1,同一个类中
	2,方法名相同
	3,形参列表不同

递归

方法本身调用本身

数组

作用:容纳一组数据类型相同的数据

名词

长度:一个数组最大可容纳数据的个数
下标(索引):数据在数组中的位置,从0开始~长度-1
元素:数组中存储的数据

特点:

1,长度不可变
2,存储的数据类型一致

步骤:

1,声明
2,创建
3,使用

声明:

语法:
	数据类型[] 数组名;
	数据类型 数组名[];

创建:

静态创建:
	语法:
		数据类型[] 数组名 = {值1,值2,值3,值4,...值n};
	注意事项:
		1,必须在声明时创建
		2,其长度就是创建时值的个数
动态创建:
	语法:
		带值
			数组名 = new 数据类型[]{值1,值2,值3,...};
			注意:
				其长度就是创建时值的个数
		不带值
			数组名 = new 数据类型[长度];

动态创建与静态创建的区别:
	1,静态创建必须在声明时创建,动态创建可以将声明与创建分开,也可以同时进行
	2,内存上来说
		静态创建的内存在常量区
		动态创建的内容在堆内存
	3,静态创建是在代码加载时分配的内存空间,动态创建是在代码运行时分配的空间

注意:
	堆内存中的数据有默认值
		基本数据类型默认为0
		引用数据类型默认为null

使用

基本使用
	改
		修改指定位置的数据
			语法:
				数组名[下标] = 值;
	查
		查询数组长度
			语法:
				数组名.length
		查询数组指定位置的数据
			语法:
				数组名[下标]
			注意:
				下标要在取值范围内,否则会产生数组下标越界异常

扩展
	遍历:将数组或集合中的数据逐个取出
		方式1:普通for循环
		方式2:foreach(只能做遍历)
			foreach语法:
				for(数据类型 变量名:要遍历的数组或集合){

				}
				数据类型:遍历出的数据的数据类型
				变量名:就是遍历出的数据
		注意:foreach(增强for循环)在遍历时的速度是普通for的3倍

	复制:将数组A中的数据,逐个复制到数组中
		思路:
			1,创建新数组
				注意:
					1,新数组长度等于老数组长度
					2,新数组的数据类型与老数组一致
			2,遍历老数组
				使用普通for循环
			3,将老数组的值取出,赋值给新数组对应的位置

	扩容:将数组变大
		思路:
			1,创建一个新数组
				注意:
					1,新数组长度大于老数组长度
					2,新数组的数据类型与老数组一致
			2,遍历老数组
			3,将老数组的值取出,赋值给新数组对应的位置
			4,将新数组赋值给老数组

二维数组

概念:将数组作为数据存储在数组中
步骤:
	1,声明
	2,创建
	3,使用
声明
	数据类型[][] 数组名;
创建
	静态创建
		注意:声明与创建同时进行
		语法:
			数据类型[][] 数组名 = {
				{值1,值2,值3,...},
				{值4,值5,..},
				{值6,值7,值8,值9,...},
				...
			};
	动态创建
		带值
			语法:
				数组名 = new 数据类型[][]{
					{值1,值2,值3,...},
					{值4,值5,..},
					{值6,值7,值8,值9,...},
					...
				};
		不带值
			语法:
				数组名 = new 数据类型[x][y];
				x:二维数组中可容纳的一维数组的个数,必须在创建时说明
				y:一维数组中可容纳的元素的个数,可以不写
注意:
	二维数组的长度指的是其中存储的一维数组的个数

使用:
	改
		修改二维数组中指定的一维数组
			数组名[下标] = 新数组;
			注意:不能使用静态创建
		修改二维数组中指定的位置的元素
			数组名[x][y] = 新值;
			x:元素所在的一维数组在二维数组中的位置
			y:元素在一维数组中的位置
	查
		查询数组长度
			数组名.length
		查询二维数组中指定位置的一维数组
			数组名[下标];
		查询二维数组中指定位置的元素
			数组名[x][y]
			x:元素所在的一维数组在二维数组中的位置
			y:元素在一维数组中的位置
遍历:
	思路:
		1,遍历二维数组,获取一维数组
		2,遍历一维数组

杨辉三角
1	0	0	0	0	0	0
1	1	0	0	0	0	0
1	2	1	0	0	0	0
1	3	3	1	0	0	0
1	4	6	4	1	0	0
1	5	10	10	5	1	0
1	6	15	20	15	6	1
....

数组与方法

例子:定义一个方法计算多数之和
public static void sum(int[] nums){
	int sum= 0;
	for(int i:nums){
		sum = sum + i;
	}
}
int[] nums = {1,2,3,4,5,6,7,8};
sum(nums);

例子:定义一个方法,计算两数之和.要求返回值有加数,被加数,和
public static int[] add(int a,int b){
	int x = a + b;
	int[] nums = {a,b,x};
	return nums;
}

可变参数

作用:解决实参的长度必须与形参一致的问题

语法:数据类型... 变量名

使用位置:形参末尾使用

注意:一个方法只能使用一个可变参数

算法

作用:调高代码的执行效率

评判算法是否优良

时间复杂度
	代码执行时间越短越好
空间复杂度
	代码执行中所需的内存,越少越好

常用的算法

两数交换
	int red = 10;
	int blue = 1;
	int x = red;
	red = blue;
	blue = x;

寻找最大值/最小值
	int[] nums = {1,17,18,19,21,5,66,17,19,0};
	//假设最大值为max
	//注意:该数的初始化值必须是数组中的数
	int max = nums[0];
	//使用假设的数据与数组中其他数据一一对比
	for(int x:nums){
		if(x > max){
			max = x;
		}
	}
	//假设的最大值就是真的最大值

寻找最大值下标/最小值下标
	int[] nums = {1,17,18,19,21,5,66,17,19,0};
	//假设最大值的下标为maxIndex
	int maxIndex = 0;
	//使用假设的最大值下标对应的数据与数组中其他数据一一对比
	for(int i = 0; i < nums.length; i++){
		if(nums[maxIndex] < nums[i]){
			maxIndex = i;
		}
	}
排序
	冒泡排序
		核心思想:相邻比较,交换位置
	选择排序
		核心思想:确定最值与目标位置,交换位置
	JDK提供的方法进行排序
		使用JDK提供的Arrays
			操作:
				排序:sort
					语法:
						Arrays.sort(数组名);
				将数组转换为字符串:toString
					语法:
						Arrays.toString(数组名);
						返回值为转换后的字符串

二分查询
杨辉三角
x
{
0	{1},
1	{1	1}
2	{1	2	1}
3	{1	3	3	1}
4	{1	4	6	4	1}
5	{1	5	10 10	5	1}
}
	0	1	2	3	4	5		y
一维数组在二维数组这种的位置为x
元素在一维数组中的位置为:y
数组名[2][1] = 数组名[1][1] + 数组名[1][0];
数组名[4][2] = 数组名[3][2] + 数组名[3][1];
数组名[x][y] = 数组名[x-1][y] + 数组名[x-1][y-1];

JDK提供的排序

核心思想:快速排序
类:Arrays
提供的方法:
	sort(数组);排序,默认从小到大(升序)
	toString(数组):将数组转换为字符串

查找

顺序查找

核心思想:逐个对比

二分查找

核心思想:折半法
注意:
	1,使用二分查找的数组必须是有序的

数据结构

数组

链表

二叉树

概念:先进后出,水桶
代码模拟:
		ArrayList<Integer> list = new ArrayList<>();
  for (int i = 0; i < 10; i++) {
      list.add(i);
  }
  while (list.size() > 0){
      Integer num = list.remove(list.size() - 1);
      System.out.println(num);
  }
  System.out.println(list);

队列

概念:先进先出,水管
代码模拟:
		ArrayList<Integer> list = new ArrayList<>();
  for (int i = 0; i < 10; i++) {
      list.add(i);
  }
  while (list.size() > 0){
      Integer num = list.remove(0);
      System.out.println(num);
  }
  System.out.println(list);

单链表

概念:上一个节点存储的是值与下一个节点的地址
代码模拟:
public class Demo11 {
public static void main(String[] args) {
  Node<String> n03 = new Node<>("德玛",null);
  Node<String> n02 = new Node<>("蛮王",n03);
  Node<String> n01 = new Node<>("寒冰",n02);

  System.out.println(n01.getV());
  System.out.println(n01.next().getV());
  System.out.println(n01.next().next().getV());
}
}
//节点
class Node<T>{
private T v;//值
private Node n;//下一个值的内存地址

public Node() {
}

public Node(T v, Node n) {
  this.v = v;
  this.n = n;
}

public T getV() {
  return v;
}

public void setV(T v) {
  this.v = v;
}

public Node next(){
  return n;
}
}

编程思想

面向过程

概述:按照事物的发展顺序考虑问题

将大象装进冰箱里
	1,打开冰箱门
	2,放入大象
	3,关闭冰箱门

开发语言:
	C

面向对象

概念:先考虑事物中存在那些对象,在建立对象与对象的关系

将大象装进冰箱里
	1,存在的对象有
		冰箱
		大象
	2,关系
		冰箱开门
		放大象
		冰箱关门

开发语言:
	Java,Python,JavaScript,Object C,C#....

对象的概念

概念:万事万物皆对象
生活中:客观存在的事物皆为对象
代码中:在代码中存在的事物

类的概念

概念:多个对象抽取其共同点形成的概念
生活中:概念
代码中:创建对象的模板

类与对象的关系

生活中:先有对象,后有类
代码中:先有类,后有对象
	一个类可以有多个对象.多个对象可以属于同一个类

类的定义与组成

定义

语法:
	访问权限修饰符 class 类名{

	}
	访问权限修饰符:
		暂时使用public或不写
	类名:
		1,同一个文件夹下类名不能相同
		2,大驼峰

组成

属性:
	如:人的姓名,性别,年龄,肤色等
	作用:描述事物的静态特征
	定义的位置:类中,方法以外
	语法格式:访问权限修饰符 数据类型 属性名;
	别名:全局变量,成员变量
	成员变量与局部变量的区别
		成员变量:
			声明在类中,方法外
			有默认值,基本数据类型,默认为0,引用数据类型默认为null
			作用域:当前类中
			生命周期:随着所属的对象的创建而生成,随着所属的对象的销毁而销毁
		局部变量:
			方法中
			没有默认值
			作用域:当前代码块中
			生命周期:随着方法调用而生成随着方法执行完毕而销毁
	练习:定义一个人类,在使其定义,姓名,性别,年龄属性
	//1,定义一个人类
	public class Person{
		//2,定义属性
		public String name;
		public char sex;
		public int age;
	}


方法:
	如:人会吃饭,喝水,打游戏,学习等
	作用:描述事物的行为(动态特征)
	定义的位置:类中,方法以外
	语法格式:
		访问权限修饰符 返回值类型 方法名(形参列表){
			方法体
		}
		修饰符:暂时不写
	别名:函数,成员函数,成员方法
	练习:定义一个人类,使其会吃饭,会喝水
	//1,定义一个人类
	public class Person{
		public String name;
		//2,定义方法
		public void eat(){
			System.out.println(name+"吃饭");
		}
		public void eat(String foodName){
			System.out.println(name+"吃"+foodName);
		}

		public void drink(){
			System.out.println(name+"喝水");
		}
	}

构造函数:
	本质:特殊的方法
	作用:创建该类对象
	定义位置:类中,方法以外
	语法:
		访问权限修饰符 构造函数名(形参列表){
			方法体
		}
	注意:
		1,构造函数没有返回值类型
		2,构造函数中没有返回值
		3,构造函数名必须与类名一致
		4,使用new关键字调用
		5,如果一个类中有多个构造函数,那么这些构造函数绝对是重载关系
		6,一个类一定会有一个构造函数.如果一个类中没有定义构造函数,系统将会为其提供一个无参构造.如果一个类中有构造函数,系统将不在为其提供无参构造
		7,构造函数不能形成递归

	名词:
		1,无参构造:构造函数没有形参
		2,有参构造:构造函数有形参
		3,全参构造:构造函数的形参一一对应,该类的属性
	如:给人类定义一个构造函
		public class Person{
			String name;
			String sex;
			int age;
			public Person(String n,String s,int a){

			}
		}

对象的创建与使用

创建

语法:
	数据类型 对象名 = new 构造函数(实参列表);
	数据类型:就是该对象所属的类的类名.就是类名


	Cat cat = new Cat();做了什么?
	步骤:
		1,使用new关键字在堆内存中开辟一片空间
		2,给属性赋初值
		3,执行构造函数中的代码
		4,将堆地址赋值给栈中的引用

使用

操作属性

获取属性值
	语法:
		对象名.属性名
修改属性值
	语法:
		对象名.属性名 = 值;

调用方法

语法:
	对象名.方法名(实参列表);

this关键字

含义:谁调用this所在的方法this就表示谁

场景1:当局部变量与成员变量(属性)名称相同时,使用this区分

成员变量(属性)
	this.属性名
局部变量
	变量名

就近使用原则

场景2:在本类方法中使用本类的属性或方法,默认使用this调用,此时this可以忽略不写

场景3:在本类构造函数中调用本类其他构造函数

语法:
	this(实参列表);
注意:
	必须在构造函数第一行使用

面向对象三大特征

封装

概念:包装

优点:

1,方便使用
2,保护内部
3,降低耦合度
4,提高复用率

体现

变量:封装这一个值或内存地址
方法:封装一堆代码
类:封装多个属性,方法与构造函数
...
Java中的封装无处不在

本质:就是一个src下的文件夹
作用:对java文件进行分类存储,使其便于寻找
创建:
	选择src -- 点击鼠标右键 -- 选择new -- 选择package -- 填写包名
包名:
	命名规则:全小写
	潜规则:com.公司名称缩写或项目名称.分类名称
注意:
	.下一级文件夹

关键字:package,说明当前java文件所在的包

导包

作用:在当前java文件中使用其他文件夹下的类,此时需要导包
语法:
	import 包名.类名;

位置:类上

关键字:import

*:所有

访问权限修饰符

作用:限制其修饰的内容使用的范围

关键字				中文名								范围
public			  公共的							  当前项目中
protected		  受保护的							 当前包下或继承关系下可用
不写				 默认的							当前包下
private			  私有的							 当前类中

总结:
	属性使用private修饰
	方法使用public修饰

经验

1,私有化所有属性(使用private修饰所有属性)
2,编写无参构造与全参构造
3,提供公共的get与set方法,使其可以对属性进行操作

继承

概念:

生活中:晚辈继承长辈遗留下的精神或物质遗产

代码中:多个类抽取其共同点形成的类,此时该与类这几个类就可以有继承关系

优点:

子类将拥有父类的所有属性与方法,构造函数除外

1,提高复用率

语法

访问权限修饰符 class 子类名 extends 父类名{
	属性
	方法
	构造函数
}

注意:
	1,一个父类可以有多个子类
	2,一个子类只能有一个父类(单继承)
	3,子类构造函数中默认调用父类无参构造函数
	4,子类构造函数中必须调用父类的构造函数

父类的别名:基类,根类
Object是所有类的父类,如果一个没有明确的父类,默认继承与Object

开闭原则:
	对修改关闭
	对扩展打开

重写

在继承关系中
子类中的方法与父类的方法,方法名形同,形参列表也相同,
子类该方法的访问权限修饰符不能小于父类的
子类该方法的返回值类型与父类的一致

super

含义:谁调用super所在的方法,super就表示谁的父类对象

场景1:当子类重写父类方法后,在子类中使用super区分,是子类重写的方法还是父类提供的方法
super.方法名(实参列表)			父类提供的方法
方法名(实参列表)				子类重写后的方法

场景2:当子类属性名与父类属性名重名时,使用super区分
super.属性名		父类属性
属性名				子类属性
(没人用过)

场景3:调用父类构造函数
super(实参列表);
注意:
	只能在子类构造函数第一行调用

this与super
	this:调用该方法的对象
	super:调用该方法的父类对象

多态

概念:一个事物的多种形态

物的多态
	子类对象转换为父类对象
		自动转换
		语法
			父类名 对象名 = 子类对象;
	父类对象转换为子类对象
		强制转换
		语法:
			子类名 对象名 = (子类名) 父类对象;
		注意:有风险
	instanceof
		作用:判断该对象是否属于该类
		注意:判断的对象与类之间要存在关系
		语法:
			boolean 变量名 = 对象名 instanceof 类名;
			如果结果为true,表示该对象属于该类
			如果结果为false,表示该对象不属于该类

事的多态
	重载
		要求:在同一个类中,方法名相同,形参列表不同
	重写
		要求:在继承关系中,子类方法与父类方法,方法名相同,形参列表相同,返回值类型相同,访问权限修饰符不能减小
		例子:动物会叫,狗也会叫
		注意:
			当子类对象转换为父类对象后,调用重写的方法,依据执行的是子类重写的后的方法

三大修饰符

abstract

含义:抽象的,不可描述的

可以修饰:类与方法

修饰类

特点:不能直接创建对象
语法:
	访问权限修饰符 abstract class 类名{
		属性
		方法
		构造函数
	}
名称:被称为抽象类
注意:
	抽象类中不一定有抽象方法
	子类继承与抽象类,要么重写父类所有抽象方法,要么自己也是抽象类

修饰方法

特点:没有方法体
语法:
	访问权限修饰符 abstract 返回值类型 方法名(形参列表);
注意:
	有抽象方法的类一定是抽象类
	抽象类中可以有多个抽象方法

final

含义:最终的,不可修改的

可以修饰:变量,方法,类

修饰变量

修饰局部变量
	语法:
		final 数据类型 变量名;
		变量名 = 值;
	注意:
		只能赋值一次
		fianl修饰的变量就是常量
修饰成员变量
	语法:
		访问权限修饰符 final 数据类型 属性名 = 值;
	注意:
		1,final修饰的属性必须在声明时赋值
		2,final修饰的属性值不能被修改

修饰方法

作用:不能被重写
语法:
	访问权限修饰符 final 返回值类型 方法名(形参列表){
		方法体
	}

修饰类

作用:不能被继承.这种类被称为最终类
语法:
	访问权限修饰符 final class 类名 ...{

	}

static

含义:静态的,公共的

可以修饰:属性,方法,代码块,内部类

修饰属性

特点:
	该属性属于该类的所有对象,该类的一个对象对其进行修改,该类的所有对象的该属性都将被修改
	可以使用类名直接调用
语法:
	访问权限修饰符 static 数据类型 属性名;

修饰方法

特点:可以使用类名直接调用,也可以使用对象名调用
语法:
	访问权限修饰符 static 返回值类型 方法名(形参列表){
		方法体
	}
注意:
	1,不能使用this或super关键字
	2,不能直接使用本类中其他非静态属性或非静态方法
	3,可以直接使用本类的静态属性或静态方法
	4,非静态方法中可以直接使用静态属性或静态方法

修饰代码块

特点:在类加载时被执行
	注意:一个类在程序运行时,只会被加载一次
语法:
	static{
		代码块
	}
	注意:
		静态代码块中可以使用静态属性与静态方法,不能直接使用非静态属性或非静态方法
		静态代码块与静态属性,谁在前,谁先执行.为了可以在静态代码块中使用静态属性,必须将静态属性声明在静态代码块之前

类加载时机:该类第一次被使用时
	1,第一次创建该类对象时
	2,第一次使用该类调用属性时
	3,第一次使用该类调用方法时
	4,第一次使用反射机制加载该类时

代码块

语法:{}

作用:封装一段代码

使用位置:

类中方法以外
	每次创建该类对象时被调用
	注意:
		在构造函数之前执行
		普通属性与代码块按顺序执行
类中方法中
	相当于没写

继承关系中的执行流程

先父静,在子静

父代码块,父构造函数

子代码块,子构造函数

接口

含义

宏观:规则
微观:功能

使用步骤

1,定义
2,使用

定义

语法:
	访问权限修饰符 interface 接口名{

	}
组成:
	公共静态常量
	公共静态方法
	公共抽象方法
	default修饰的普通方法
注意:
	接口中的属性默认使用public static final修饰
	接口中的方法默认使用public abstract修饰

使用

情况1:接口使用接口
	多继承:一个接口可以继承多个接口
	语法:
		访问权限修饰符 interface 子接口名 extends 父接口名1,父接口名2,...{

		}
	注意:
		不能继承父接口的静态方法,其他的均可继承

情况2:类使用接口
	多实现:一个类可以实现多个接口
	语法:
		访问权限修饰符 class 子类名 extends 父类名 implements 父接口名1,父接口名2,...{

		}
	注意:
		1,一个类可以实现多个接口
		2,子类要么重写所有接口提供的抽象方法,要么子类也是抽象类
		3,子类对象可以转换为多个实现的接口对象
		4,一个接口可以被多个类现实,所以多个类的对象可以转换为同一个接口的对象

接口的特殊使用

常量接口

概念:只有常量的接口称为常量接口

public interface NetType{
	int OK_NET = 200;
	int ERROR_NET_01 = 404;
	int ERROR_NET_02 = 503;
	int ERROR_NET_02 = 303;
}

接口回调

概念:接口对象回来调用接口方法

案例:按钮点击
	按钮类
	点击事件接口
	环境类
		创建点击事件接口对象
		创建按钮对象,传入接口对象
		按钮对象.点击方法

内部类

作用:补齐外部类功能

概念:在类中定义的类称为内部类

如:
public class A {
public class B{

}
}
此时B类就是内部类,A类就是外部类

内部类分类

1,成员内部类
	定义位置:类中,方法以外
	没有使用static修饰
2,静态内部类
	定义位置:类中,方法以外
	使用static修饰
3,局部内部类
	定义位置:类中,方法中
4,匿名内部类(*)
	定义位置:值或实参中

成员内部类

定义位置:类中,方法以外
可以定义什么?
	除静态成员(静态属性与静态方法等)以外皆可定义
如何创建对象?
	情况1:在所在的外部类中创建该内部类对象
		内部类类名 对象名 = new 内部类类名(实参列表);
		注意:只是省略this关键字,所以这种创建方式不能在静态方法中使用
	情况2:在其他类中创建该内部类对象
		外部类类名.内部类类名 对象名 = 外部类对象.new 内部类类名(实参列表);

静态内部类

定义位置:类中,方法外.使用static修饰的成员内部类
可以定义什么?
	所有的都可以定义
如何创建对象?
	外部类类名.内部类类名 对象名 = new 外部类类名.内部类类名(实参列表);

局部内部类

定义位置:类中,方法中
注意:
	1,此时不能使用访问权限修饰符
	2,只能在当前方法中使用
可以定义什么?
	除静态成员(静态属性与静态方法等)以外皆可定义
如何创建对象?
	内部类类名 对象名 = new 内部类类名(实参列表);

匿名内部类

概念:没有类名的内部类称为匿名内部类
定义位置:值或实参中
语法:
	父类名或父接口名 对象名 = new 父类名或父接口名(){
		属性
		方法
	};
注意:
	1,一个类只创建一个对象时,可以使用匿名内部类
	2,不能定义静态的成员与抽象方法
缺点:
	1,代码混乱,降低代码可读性
优点:
	1,编写方便

匿名对象

概念:没有对象名的对象
new 类名(实参列表).方法名();
缺点:只能使用一次
优点:编写方便

包装类

概念:八个基本数据类型对应的引用的数据类型

包装类有

byte			Byte
short			Short
int				Integer
long			Long

float			Float
double			Double

boolean			Boolean
char			Character

提供的方法

static xxx parseXXX();

自动装箱

概念:将基本数据类型转换为其对应的引用数据类型的对象
如:
	Integer i = 10;

自动拆箱

概念:将引用数据类型的对象转换为对应的基本数据类型的变量
如:
	int i2 = i;

整数缓冲区

-128~127
原因:
	因为系统中已经创建了-128~127之间有数的对象,在使用自动装箱时,如果值是在该范围内,直接使用已经创建好的对象,如果超过这个返回需要重新创建对象
	Integer i1 = 127;
	Integer i2 = 127;
	i1 == i2;				true
	i1 = 128;
	i2 = 128;
	i1 == i2;				false

System

含义:系统

本质:由JDK提供的一个类

提供的属性或方法

static native void arraycopy(Object src,int  srcPos,
                       Object dest, int destPos,
                       int length)
作用:将原数组中的一段数据复制到新数组
	1参:原数组
	2参:复制开始的位置
	3参:新数组
4参:新数组开始的位置
5参:复制的长度

static native long currentTimeMillis()
作用:获取当前时间与1970年1月1日00:00:00:000的时间差(格林威治时间)

static void exit(int status)
作用:结束当前程序
	1参:终止状态码
		0:正常退出
		1:异常退出

static void gc()
作用:手动调用垃圾回收机制

Object

概念:所有类的父类

意味:

该类提供的属性与方法是所有类的对象都可以使用的

提供的方法

public boolean equals(Object obj)
	作用:判断调用该方法的对象与传入的对象的内存地址是否相同
	如果子类重写该方法,使用子类对象调用该方法执行的是重写后的代码
	如果要比较子类的对象属性值是否相同,要重写equals方法
	重写步骤:
		1,判断内存地址是否相同
		2,判断传入的对象是否属于该类对象
		3,将传入的对象转换为该类对象
		4,使用调用该方法的对象的属性与传入的对象的属性一一比较

public String toString()
	作用:获取对象的表名.类拼接@字符串,在拼接对象的内存地址的16进制值
	注意:
		Object提供的toString方法返回的是对象的包名.类@对象的内存地址的16进制,可以理解为是对象的信息,但是我们在观察对象时,想看到的是对象的属性值.所以此时我们可以在子类中重写toString方法.重写后对象在调用toString方法,执行的是重写后的toString方法.
		因为打印对象时默认会调用对象的toString方法.那么当子类重写toString方法后,在打印该子类对象,此时执行的是子类重写后的toString方法

public int hashCode()
	作用:获取对象的哈希码值,近似可以理解为对象的内存地址

finalize()
	作用:系统回收该对象的内存时,才会被调用

Math

作用:数学运算与随机数

提供的方法

static double random();
	作用:随机获取0~1之间的数
static int abs(int a)
	作用:获取其指定数据的绝对值
static double floor(double a)
	作用:向下取整
static int max(int a, int b)
	作用:获取两数之间的最大值
static int min(int a, int b)
	作用:获取两数之间的最小值
static double pow(double a, double b)
	作用:计算a的b次幂的结果

字符串相关类

不可变字符串:String

提供的方法

增
	+
删

改
	public String replace(String old,String newStr)
		作用:替换
		1参:要被替换的字符串
		2参:替换后的字符串
查
	public int length()
		作用:获取字符串长度
	char charAt(int index)
		作用:获取字符串中指定位置的字符
	public char[] toCharArray() 
		作用:将字符串转换为字符数组
	public boolean equals(Object anObject)
		作用:比较字符串内容是否相同
	public boolean equalsIgnoreCase(String anotherString)
		作用:忽略大小写比较字符串内容是否相同
	public String trim()
		作用:忽略前后空白
	boolean endsWith(String suffix)
		作用:判断字符串是否以指定的字符串结束
	boolean startsWith(String prefix)
		作用:判断字符串以什么开始
	public String toUpperCase()
		作用:将字符串中的小写字母转换为大写字母
	public String toLowerCase()
		作用:将字符串中的大写字母转换为大写字母
	boolean contains(String s)
		作用:判断s是否在调用该方法的字符串中存在
	public int lastIndexOf(String str)
		作用:获取指定的子字符串在字符串中最后一次出现的位置
	public int indexOf(String str)
		作用:获取指定的子字符串在字符串中第一次出现的位置
	public String substring(int beginIndex)
		作用:截取指定位置的字符串,从开始位置到字符串末尾
		1参:开始位置
	public String substring(int beginIndex, int endIndex)
		作用:截取指定位置的字符串
		1参:开始位置
		2参:结束位置
	public String[] split(String regex) 
		作用:切割
		1参:按什么字符串切割

构造函数

public String(char value[])
	将传入的字符数组转换为字符串
public String(char value[], int offset, int count)

可变字符串

StringBuffer

特点:
	JDK1.0出现
	线程安全的
	效率低

StringBuilder

特性:
	JDK1.5出现
	线程不安全
	效率高java

提供的方法

1,StringBuilder append(Object obj)
	作用:给字符串尾部拼接字符串
2,StringBuilder insert(int offset, String str)
	作用:插入
	1参:插入开始的位置
	2参:插入的数据
3,StringBuilder delete(int start, int end)
	作用:删除指定区间的数据
	1参:开始位置,包含
	2参:结束位置,不包含
4,StringBuilder deleteCharAt(int index) 
	作用:删除指定位置的字符
	1参:指定的位置
5,StringBuilder replace(int start, int end, String str) 
	作用:替换
	1参:要替换的数据的开始位置,包含
	2参:要替换的数据的结束位置,不包含
	3参:替换后的字符串
6,toString():
	作用:将可变字符串转换为不可变字符串

精准计算

对应的类:BigDecimal

构造函数

BigDecimal(Object obj);
注意:一定要传入的是字符串

提供的方法

BigDecimal subtract(BigDecimal subtrahend)
	作用:减法,使用调用该方法的对象的值减去传入的对象的值,返回计算的结果
BigDecimal add(BigDecimal augend)
	作用:加法
BigDecimal multiply(BigDecimal multiplicand)
	作用:乘法
BigDecimal divide(BigDecimal divisor)
	作用:除法
XXX xxxValue();
	作用:获取BigDecimal的值

时间相关类

Date

概念:日期

创建:

public Date():获取当前系统时间
public Date(long date):获取距离1970年1月1日 00:00:00的时间(格林威治时间),参数单位毫秒

方法

public long getTime():获取当前对象距离1970年1月1日 00:00:00的时间差,单位毫秒
public boolean after(Date when):当前时间是否在指定时间之后
public boolean before(Date when):当时时间是否在指定时间之前

Calendar

概念:日历

创建:

static Calendar getInstance()

方法:

get
set
add
getTime

SimpleDateFormat

概念:时间日期格式化

特殊字符

y:年
M:月
d:日
h:十二小时值
H:二十四小时值
m:分钟
s:秒
S:毫秒

编写:2023/04/13 17:16:00
yyyy/MM/dd HH:mm:ss

方法

format:将时间对象转换为指定格式的字符串
parse:将指定格式的字符串转换为时间

泛型

作用:将数据类型作为参数进行传递

语法:

定义
	<泛型名1,泛型名2,..>
	情况1:在方法上
		访问权限修饰符 修饰符 <泛型名1,泛型名2,...> 返回值类型 方法名(形参列表){

		}
	情况2:在类上定义
		访问权限修饰符 class 类名<泛型名1,泛型名2,...>{

		}
使用
	泛型名
	情况1:在方法中使用
		在方法中任意使用数据类型的地方都可以使用该泛型作为数据类型
	情况2:在类中使用
		在类中任意使用数据类型的地方都可以使用该泛型作为数据类型

注意:泛型中只能使用引用数据类型

集合

作用

存储一组数据类型相同的数据

特点

长度可变

名称

长度:集合中存的元素的个数
下标:元素在集合中的位置
元素:集合中存储的数据

体系结构

Collection
	List
		特点:有序(存入顺序与取出顺序一致),有下标,可以重复
		子类:
			ArrayList
				特点:
					JDK1.2出现
					线程不安全的
				数据结构:数组
					特点:
						查询效率高
						增删效率低
			LinkedList
				数据结构:链表
					特点:
						查询效率低
						增删效率高
					单链表与双链表
			Vector
				特点:
					JDK1.0出现
					线程安全
				数据结构:数组
	Set
		特点:无序,无下标,元素不允许重复
		子类:
			HashSet
				底层:HashMap
				数据结构:
					JDK1.8以前数组+链表
					JDK1.8以后数组+链表+红黑树(哈希值)
				红黑树(又名二叉树)
			TreeSet
				数据结构:红黑树
				注意:指定比较规则	
			LinkedHashSet
				特点:有序
				数据结构:
					JDK1.8以前数组+链表+链表
					JDK1.8以后数组+链表+红黑树(哈希值)+链表

Collection提供的方法

增
	boolean add(E e)
		作用:一次添加一个数据
		参数:
			要添加的数据
		返回值:
			是否添加成功
	boolean addAll(Collection<? extends E> c);
		作用:一次添加一组数据
		参数:
			要添加的数据集合
		返回值:
			是否添加成功,注意:哪怕只添加了一个也算成功,全部失败才为失败
删
	boolean remove(Object o)
		作用:一次删除一个数据
		参数:
			要删除的数据
		返回值:
			是否删除成功
		注意:
			如果集合中有多个要删除的数据,只能删除第一个
	boolean removeAll(Collection<?> c)
		作用:一次删除一组输入
		参数:
			要删除的数据集合
		返回值:
			是否删除成功
		注意:
			如果原集合中多次出现删除集合中的数据,那么原集合中的该数据会全部被删除
	void clear()
		作用:清空集合中的数据
查
	int size();
		作用:查询集合长度
	boolean contains(Object o);
		作用:判断集合中是否包含指定元素
	boolean containsAll(Collection<?> c);
		作用:判断集合中是否全部包含指定的集合中的元素
		注意:判断的是是否全部包含
	boolean isEmpty();
		作用:判断集合是否为空集合
		注意:空集合表示集合中没有元素,而不是集合为null
	Iterator<E> iterator()
		作用:获取当前集合的迭代器
		迭代器的方法:
			boolean hasNext();判断下一个是否有值
			E next();移动游标,并返回指向的数据
改
	没有提供
特殊情况:
	遍历
		方案1:迭代器
		方案2:foreach

List提供的方法

增
	void add(int index, E element);
		作用:给指定位置插入一个数据
	void addAll(int index, Collection<E> c);
		作用:给指定位置插入一组数据
删
	E remove(int index);
		作用:删除指定位置的数据
改
	E set(int index, E element);
		作用:修改指定位置的元素
		参数:
			1,指定的位置
			2,修改后的元素
查
	E get(int index);
		作用:获取指定位置的元素

Set没有提供特有方法

HashSet的剔重原理

1,存入对象先判断对象的hashcode值是否与已经存储的数据hashcode值是否相同
2,如果相等,在使用本次存入的对象与集合中的对象使用equals方法一一比较
3,如果equals也相同,认为对象已经存储,将不在存入该对象

TreeSet存储

要求:
	TreeSet存储的数据
	要么拥有比较性(让存储的对象的类实现Comparable),
	要么指定比较器(创建TreeSet时传入Comparator对象)

Map

作用:存储一组键值对应的数据类型的数据

名称

键:key
值:value

体系结构

Map
	HashMap
		特点:使用键值对的中键的hashcode值进行排序,允许空键空值,JDK1.2,线程不安全的
	Hashtable
		特点:使用键值对的中键的hashcode值进行排序,不允许空键空值,JDK1.0,线程安全的
	TreeMap
		特点:要求键要么拥有比较性,要么指定key的比较器
	Properties
		特点:HashMap的子类,可以加载读取文件中的内容,也可以向文件中写入内容
注意:
	key值不能重复

Map提供的方法

增
	V put(K key, V value);
		作用:添加
		注意:
			如果map中不存在该key,返回值为null
			如果map中存在该key那么此时就是替换,返回被替换的值
	void putAll(Map<? extends K, ? extends V> m);
		作用:添加一组键值对
删
	V remove(Object key);
		作用:通过key删除指定的键值对
		返回值:被删除的值
	void clear();
		作用:清空
查
	int size();
		作用:查询map中键值对的个数
	boolean isEmpty();
		作用:判断是否为空map
	boolean containsKey(Object key);
		作用:判断是否包含指定的key
	boolean containsValue(Object value);
		作用:判断是否包含指定的value
	V get(Object key);
		作用:获取key指定的值
	Set<K> keySet();
		作用:获取所有key的集合
	Collection<V> values();
		作用:获取所有值的集合
	Set<Map.Entry<K, V>> entrySet();
		作用:获取所有键值对的集合	
改
	V put(K key, V value);
		注意:如果存储数据时,key已经存在,此时就是修改

字典

概念:以键值对应的方式存储一组数据

体系

Map
	HashMap
		特点:允许空键空值,jdk1.2,线程不安全的
	TreeMap
		特点:key要么拥有比较性,要么在创建TreeMap指定Key比较器
	Hashtable
		特点:不允许空键空值,jdk1.0,线程安全的

异常

概念:程序有问题的地方

分类

错误
	概念:因为硬件问题导致的程序崩溃,称为错误(Error)
	解决:不予处理
异常
	检查时异常
		概念:因语法问题导致的错误
		解决:修改语法
	运行时异常
		概念:但是因为编写时思路问题,或传入的数据导致程序无法正常运行
		解决:更换思路,修改传入的数据,加入容错判断

异常出现后的情况

导致程序非正常结束

体系

Throwable
	Error(错误)
	Exception(异常)
		CheckedException(检查时异常)
		RuntimeException(运行时异常)

解决方案

方式1:try catch
	语法:
		try{
			有异常的代码;
		}catch(异常类型 变量名){
			处理方式
		}catch(异常类型 变量名){
			处理方式
		}...
  catch(异常类型 变量名){
			处理方式
		}finally{
			必须要执行的代码
		}
	注意:
		catch可以有多个,必须先子类在父类,如果没关系,那么不需要关系顺序
		finally可有可无,最多只能有一个

方式2:throw
	语法:
		throw 异常对象;
	使用位置:方法中
方式3:throws
	语法:
		throws 异常类型1,异常类型2,...
	使用位置:形参之后
	注意:先子后父(可以不这么干)

常见的异常

NullPointerException
	名称:空指针异常
	原因:因为使用null调用属性或方法

IndexOutOfBoundsException
	名称:数组下标越界异常
	原因:在操作数组或集合时,下标不在取值范围内

ArithmeticException
	名称:算数异常

OutOfMemoryError
	名称:内存溢出错误

自定义异常

步骤:
	1,创建一个类
	2,使其继承与Exception或Exception的子类
	3,编写其构造函数

线程的初识

作用

使代码可以同时执行多个事物

名词

进程:
	一个正在进行的程序
线程:
	一个执行路径
多线程:
	一个进程中有多个线程
主线程:
	一个进程在创建时自带的一条线程,该线程被称为主线程
子线程:
	除主线程以外的线程都是子线程
守护线程(后台线程):
	特点:如果一个进程的前台线程全都被销毁,此时不管是否有守护线程正在执行,此时进程都将被回收
前台线程
	特点:如果一个进程中有前台线程存活,此时系统将不会回收进程

线程的组成

CPU时间片

线程抢夺到CPU执行权后可执行的时间

内存

一个线程一个栈内存,多个线程共享一个堆内存

逻辑

使用步骤

1,创建
2,使用

线程的创建

方案1:创建Thread的子类对象

方式1:创建Thread的子类对象
	步骤:
		1,创建一个类
		2,使其继承与Thread
		3,重写run方法
			注意:当前线程启动后,将执行run方法中的代码
		4,创建该类对象
	优点:
		可以创建无数个该类对象

方式2:使用匿名内部类的形式创建Thread的子类对象
	步骤:
		Thread 对象名 = new Thread(){
			重写run方法
		};
	优点:
		便于书写
	缺点:
		只能创建一个该线程对象

方案2:将线程(Thread)与线程任务(Runnable)分开

方式1:普通方式创建Runnable的子类对象
	步骤:
		1,创建一个类
		2,使其实现Runnable接口
		3,重写run方法
		4,创建该类对象
		5,在创建线程对象时传入该类对象(线程任务对象)
方式2:使用匿名内部类创建Runnable的子类对象
	步骤:
		1,Runnable 对象名 = new Runnable(){
			重写run方法
		};
		2,创建线程对象时传入该类对象(线程任务对象)

线程的启动

线程对象.start();
注意:
	1,当线程启动后会开启新的执行路径,执行run方法中的代码
	2,如果直接使用线程对象调用run方法,不会开启新的执行路径

线程的销毁

线程已经启动,无法控制,需要等待执行完run方法中的代码

获取当前线程对象

Thread.currentThread();

线程名称

获取线程名称
	线程对象.getName();
修改线程名称
	线程对象.setName(name);
	注意:在启动之前

线程的优先级

作用:提高线程抢夺到CPU执行权的概率

语法:
	线程对象.setPriority(int);
注意:
	1,取值范围1~10
	2,必须在线程启动前

线程休眠

作用:让线程暂时停止运行

方法:
	static void sleep(休眠时间);
注意:
	1,单位毫秒
	2,使用类名调用,使当前线程休眠
	3,线程休眠期间不会抢夺CPU执行权

线程的礼让

作用:将获取到的CPU执行权让出,重新参与抢夺

方法:
	static native void yield();

线程合并

作用:合并线程

方法:
	public final void join()

案例

package com.qf.demo011;

public class Test {
public static void main(String[] args) {
  Thread t01 = new Thread(new Runnable() {
      @Override
      public void run() {
          for (int i = 0; i < 100; i++) {
              try {
                  Thread.sleep(1);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              System.out.println("线程1:" + i);
          }
      }
  });
  Thread t02 = new Thread(new Runnable() {
      @Override
      public void run() {
          for (int i = 0; i < 100; i++) {
              try {
                  Thread.sleep(1);
              } catch (InterruptedException e) {
                  e.printStackTrace();
              }
              System.out.println("线程2:" + i);
              if (i == 50){
                  try {
                  	//将线程1合并到线程2中
                  	//此时先执行完线程1未完成的代码,在执行线程2未完成的代码
                      t01.join();
                  } catch (InterruptedException e) {
                      e.printStackTrace();
                  }
              }
          }
      }
  });
  t01.start();
  t02.start();
}
}

守护线程

简介

又名:后台线程
特点:
	当一个进程中有前台线程存活,此时该进程就不会被系统回收
	如果一个进程中只剩后台线程,此时不管后台线程中的代码是否运行完毕,系统都将回收该进程
方法:
	public final void setDaemon(boolean on);
	true表示守护线程,默认为false,表示前台线程
注意:
	1,创建的线程对象与主线程默认为前台线程
	2,必须在线程启动前

线程的生命周期

创建
就绪
运行
消亡
休眠
	有限期
	无限期

线程安全问题

原因

多个线程操作同一个数据,会导致线程安全问题

解决思路

保证同时只能有一个线程操作该数据

方案

方案1:同步代码块
	语法:
		synchronized(锁对象){
			要同步的代码
		}
	注意:
		1,所有对象都可以作为锁对象
		2,多个线程的锁对象要是同一个对象

方案2:同步方法
	语法:
		访问权限修饰符 synchronized 返回值类型 方法名(形参列表){

		}
	注意:
		1,同步方法的锁对象是this
		2,多个线程的锁对象要是同一个对象

方案3:同步静态方法
	语法:
		访问权限修饰符 synchronized static 返回值类型 方法名(形参列表){

		}
	注意:
		1,同步静态方法的锁对象时该类的类对象
			类对象:当JVM加载类的时候,会生产一个对象,该对象就是该类的类对象
				一个类只有一个类对象
		2,多个线程的锁对象要是同一个对象

死锁

原因

多个线程互相持有对方所需的锁资源

例子

Object A = new Object();
Object B = new Object();
线程1:
	xxx
	synchronized (A){
		xxx
		synchronized (B){
			xxx
		}
	}
线程2:
	xxx
	synchronized (B){
		xxx
		synchronized (A){
			xxx
		}
	}

避免的思路

不要在同步中使用同步

线程间通讯

注意

1,线程间通讯的方法由Object提供
2,只能在同步中使用
3,只能使用所在的同步的锁对象调用

方法

唤醒:
	notify():随机唤醒一个
	notifyAll():唤醒所有
	注意:
		只能唤醒以同一个对象调用wait方法的线程

休眠:
	wait():无限期休眠
	wait(int ms):有限期休眠
	wait(int ms,int ns):有限期休眠
	注意:
		1,参数就是休眠时间,ms毫秒,ns纳秒
	wait与sleep的区别:
		1,wait在休眠期间会释放所持有的锁资源,sleep不会
		2,wait必须在同步中使用,sleep没有限制
		3,wait必须使用所在的同步的锁对象调用,sleep使用Thread类或Thread类的对象调用
		4,wait由Object提供,sleep由Thread类提供

生产者与消费者模式

设计模式

作用:解决特定问题的思路
生产者与消费者模式解决的是进销存业务

生产者与消费者模式解决的问题

工厂的进销存业务

分析

生产的任务
	无限生产
销售的任务
	无限销售
工厂
	属性:
		库存数量
		最大库存数量
		最小库存数量
	方法:
		生成的方法:同步的
			判断库存数量 < 最大库存数量
				true
					继续生产
				false
					唤醒销售
					休眠自身
		销售的方法:同步的
			判断库存数量 > 最小库存数量
				true
					继续销售
				false
					唤醒生产
					休眠自身
环境类
	创建工厂对象
	创建线程对象(传入线程任务(生产任务或销售任务))
	...

	启动

线程池

作用:优化线程

原因:

一个线程大约占1MB的运行内存
大量创建线程时可能会导致内存溢出
大量的创建的线程也导致需要对象线程频繁的创建与回收

思路

1,使用空闲的线程的执行新的任务(线程的复用)
2,使用一个容器来管理线程的创建,回收,复用等

注意:Java中提出线程池来完成以上操作

线程池的体系结构

Executor(接口)
	提供的方法:
		void execute(Runnable command):
			作用:执行线程任务,子接口提供了submit优于该方法
	子类或子接口
		ExecutorService(接口)
			提供的方法:
				void shutdown();
					作用:关闭线程池
				boolean isShutdown();
					作用:判断线程池是否关闭
				Future<T> submit(线程任务)
					作用:提交线程任务
			子类或子接口
				ScheduledExecutorService(接口)
				ThreadPoolExecutor(类)
					构造函数:
						public ThreadPoolExecutor(int corePoolSize,
                        int maximumPoolSize,
                        long keepAliveTime,
                        TimeUnit unit,
                        BlockingQueue<Runnable> workQueue,
                        ThreadFactory threadFactory,
                        RejectedExecutionHandler handler)

                        corePoolSize:核心线程数,线程池中最少有几个线程
                        maximumPoolSize:最大线程数,线程中最多可以容纳几个线程
                        keepAliveTime:销毁时间,当线程执行完任务后,多久销毁
         				  unit:时间单位
         				  workQueue:存储执行的线程任务的集合(队列形式)
         				  threadFactory:创建线程
         				  handler:优化线程,使其线程复用的算法

Executors

作用:创建线程池
原因:因为ThreadPoolExecutor过于麻烦,所以JDK提供该类帮助我们创建线程池
提供的方法:
	1,固定线程池
		特点:线程池中的线程数量恒定,当线程任务小于线程数量时,随机在线程池中挑选线程执行任务.当线程任务大于线程数量,会先执行前面的任务,后等前面任务执行完毕后,使用执行完毕的线程,执行剩余任务
		static ExecutorService newFixedThreadPool(int nThreads)
			nThreads:线程池中线程的数量

	2,可变线程池
		特点:线程池中的线程数量可变
		static ExecutorService newCachedThreadPool()

	3,单例线程池
		特点:一个线程池中只有一个线程
		static ExecutorService newSingleThreadExecutor()

	4,抢占线程池(了解)
		特点:JDK1.8出现的
		static ExecutorService newWorkStealingPool()

	5,调度线程池
		特点:该线程池执行任务可以延迟,也可以延迟重复执行
		static ScheduledExecutorService newScheduledThreadPool(int corePoolSize)
		corePoolSize:线程池中线程的数量

	6,单例调度线程池
		特点:调度线程池中只有一个线程
		static ScheduledExecutorService newSingleThreadScheduledExecutor()

线程池使用

步骤:
	1,创建线程池
	2,提交任务
	3,关闭线程池

调度线程池:ScheduledExecutorService

提供的方法:
		public ScheduledFuture<?> schedule(线程任务,
                                 long delay, TimeUnit unit)
         作用:延迟执行

  public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                            long initialDelay,
                                            long period,
                                            TimeUnit unit);
         作用:延迟重复执行
         1参:执行的任务
         2参:延迟时间
         3参:间隔时间=本次任务开始时间-上次任务开始时间
     				注意:如果上次任务执行时间>间隔时间,那么当上次任务执行完毕后,本次任务直接开始
         4参:时间单位
  public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                               long initialDelay,
                                               long delay,
                                               TimeUnit unit);
         作用:延迟重复执行
         1参:执行的任务
         2参:延迟时间
         3参:间隔时间=本次任务开始时间-上次任务结束时间
         4参:时间单位

Callable

作用:有返回值的线程任务对象

注意:

无法在创建Thread对象时传入,必须配合线程池使用

Lock

作用:简化同步

同步

同步代码块
	synchronize(锁对象){
		//关锁
		代码
		//开锁
	}
同步方法
	访问权限修饰符 synchronize 返回值类型 方法名(形参列表){
		//关锁
		方法
		//开锁
	}
同步静态方法
	访问权限修饰符 synchronize static 返回值类型 方法名(形参列表){
		//关锁
		方法
		//开锁
	}

Lock体系

Lock
	提供的方法:
		void lock():关锁
		void unLock():开锁
		Condition newCondition():获取锁对象
			void await():无限期休眠
			void signal():随机唤醒一个
			void signalAll():唤醒所有
	子类:
		ReentrantLock

ReadWriteLock
	提供的方法:
		Lock readLock():获取读锁
		Lock writeLock():获取写锁
		注意:
			读-写	互斥
			读-读 不互斥
			写-写	互斥
	子类
		ReentrantReadWriteLock

IO流

作用

传输数据

分类

按照流向分类
	输入流
	输出流

按照传输的最小数据单位分类
	字节流
		最小单位:byte
	字符流
		最小单位:char

按照功能分类
	节点流:
		从数据源到程序,或从程序直接到数据源
	包装流(过滤流):
		在节点流的基础是上增强功能
		注意:所有的包装流都使用了装饰者模式

字节流

体系

InputStream(字节输入流顶级接口)
	方法:
		int read():一次读取一个字节,返回值为读取到的字节
		int read(byte b[]):一次读取一组字节数据到数组b中,返回值为读取到的字节长度,当返回值为-1时表示读取结束
		int read(byte b[], int off, int len)
			一次读取一组字节数据到数组b中,从off位置开始存储,存储len个字节
			返回值为读取到的字节长度,当返回值为-1时表示读取结束
		void close():
			关流
OutputStream(字节输出流顶级接口)
	方法:
		void write(int b):一次写入一个字节
		void write(byte b[]):一次写入一组字节
		void write(byte b[], int off, int len):一次写入一组字节,从off位置开始,写入lenge
		void flush():冲刷
		void close():关流

文件字节流
	FileInputStream
		分类:
			输入流:文件到程序
			节点流
	FileOutputStream
		分类:
			输出流:程序到文件
			节点流
内存流
	作用:在读取数据过程中,因数据不全导致的乱码问题
	ByteArrayInputStream
	ByteArrayOutputStream
		特有方法:
			byte toByteArray();将内存流中的数据获取出来

缓冲流
	作用:提高读写效率
	注意:
		包装流

	BufferedInputStream
	BufferedOutputStream
	注意:
		默认缓冲区大小为8kb

对象流
	作用:将对象写入到文件中,或从文件中读取对象
	注意:
		1,读写的对象所属的类要实现序列化接口
		2,一个对象流只能读写一个对象
		3,存储的所有数据都必须进行序列化
		4,static修饰的属性不参与序列化
		5,transient修饰的属性也不参与序列化
	ObjectInputStream
		readObject():读取对象,只读第一个
	ObjectOutputStream
		writeObject():写入对象

文件流

内存流

注意:节点流
ByteArrayInputStream:内存输入流(了解)
	作用:将运行内存中的数据读取到程序中

ByteArrayOutputStream:内存输出流
	作用:将程序中数据存储运行内存中
	注意:
		内存输入流自带内存默认初始大写为32字节,当不够时会自动扩容
	特有方法:
		toByteArray():通过内存输出流获取其存储数据的数组

缓冲流

作用:提高读写效率
注意:过滤流(包装流)
BufferedInputStream
	作用:提高读的效率
BufferedOutputStream
	作用:提高写的效率

注意:
	1,包装流在关闭时,会关闭他所包装的节点流
	2,默认缓冲区为8kb

对象流

作用:读写对象
注意:过滤流(包装流)

ObjectInputStream
	特有方法:
		readObject():读取对象
		注意:要保证文件中有对象
ObjectOutputStream
	特有方法:
		writeObject():写出对象

注意:
	读写的对象所属的类必须实现序列化接口,包括对象的属性的数据类型也需要实现序列化

序列化:
	让对象所属的类实现Serializable接口

	注意:
		1,八个基本数据类型包装类与String都已经实现了Serializable接口
		2,不能序列化的属性有:
			1,使用transient修饰的属性为瞬时属性,不参与序列化
			2,使用static修饰的属性,不参与序列化

字符编码

常用的编码格式是:UTF-8

编码格式

最原始的计算机数据:0,1
所以将01可以排列使其形成二进制
在将2进制转换为10进制

a:97
b:98
c:99
.:
:0
...

ASCAII:因为只有一些国家的文字
Unicode:万国码,在ASCAII上增加多国字符
	一个字符2个字节
GBK:加了一些中文,在Unicode基础上增加中文
	假设:12345:你
UTF-8:加了一些中文,在Unicode基础上增加中文
	假设:12345:爜
	UTF-8:对中文的支持比GBK好

字符流

概念

传输的数据单位最小为字符(char)

字符流体系

Reader
	概念:所有字符输入流的父类
	提供的方法:
		int read();一次读取一个字符,返回值为读取到的字符
		int read(char c[]):
			一次去取一组字符到数组c中,返回值为读取到的字符长度,当为-1时表示读取结束
		int read(char c[], int off, int len)
			一次去取一组字符到数组c中
			从off位置开始存储,存储len个
			返回值为读取到的字符长度
			当为-1时表示读取结束
		void close()
			关闭
Writer
	概念:所有字符输出流的父类
	提供的方法:
		void write(int c)
		void write(char cbuf[])
		void write(char cbuf[], int off, int len)
		void write(String str)
		void flush()
		void close()

	文件流
		FileReader
		FileWriter
	缓冲流
		BufferedReader
			readLine():读取一行
		BufferedWriter
			newLine():写入一个换行
	转换流
		InputStreamReader
		OutputStreamWriter
	标准输出流
		PrintStream
			注意:是字节流

文件流

FileReader
	作用:将文本文件的内容读取到程序中
FileWriter
	作用:将程序中的数据写入到文本文件中
优点:
	相对与字节流读取文本文件,字符流不会出现乱码,因为一次就将一个字符读取结束了.不会像字节流可能会读取一个字符的一半字节

缺点:
	相对与字节流而言,字符流只能操作文本文件

缓冲流

BufferedReader
	作用:提高字符流读取的效率
	默认缓冲区大小:8192字符
	特有方法:
		readLine():一次读一行
BufferedWriter
	作用:提高字符串写出的效率
	默认缓冲区大小:8192字符
	特有方法:
		newLine():给内容中写入一个换行

转换流

InputStreamReader
	作用:将字节流输入流转换为字符输入流
	注意:当读取到的文本文件与代码的编码格式不同时,转换流可以设定读取的编码格式,防止中文乱码.参数为文本文件的编码格式,ANIS==GBK,Eclispe不支持ANIS

OutputStreamWriter
	作用:将字符输出流转换为字节输出流
	注意:当写入到的文本文件与代码的编码格式不同时,转换流可以设定写入的编码格式,防止中文乱码

标准输出流

PrintWriter
	特有方法:
		print();
		println();

File

概念

文件或文件夹对应的类

使用

1,创建File类的对象
2,对调用属性或方法

创建File对象

公共构造函数:
	File(String pathname)
		pathname:文件或文件夹的路径
	File(String parent, String child)
		parent:上级文件夹的路径
		child:当前文件的名称.后缀名
		如
			D:\2304班授课\day20\笔记\day20.md
			D:\2304班授课\day20\笔记 parent
			day20.md			   child

	File(File parent, String child)
		parent:上级文件夹的file对象
		child:当前文件的名称.后缀名

	File(URI uri)
		uri:资源所在位置
		如:
			URI uri = URI.create("D:\\a.txt");
 		File file = new File(uri);

注意:
	路径分为相对路径与绝对路径
	绝对路径:
		从盘符开始书写
		如:D:\\a.txt
	相对路径
		相对于项目路径下
		注意:
			.:当前路径
			..:上级文件夹

属性

public static separator:获取当前系统的路径分割符

方法

mkdir():创建一级文件夹
mkdirs():创建多级文件夹
createNewFile():创建一级文件

delete():删除一级文件或一级文件夹

getParent():获取上级文件夹路径
getParentFile():获取上级文件夹的file对象

getPath():获取当前路径
getAbsolutePath():获取当前文件的绝对路径
getAbsoluteFile():获取绝对路径的文件


isDirectory():判断是否为文件夹
isFile():判断是否为文件
exists():判断文件或文件夹是否存在

length():获取文件大小,单位字节
renameTo():修改文件名称

File[] listFiles();
File[] listFiles(FileFilter ff);
File[] listFiles(FilenameFilter ff);
	获取当前文件夹下的文件或文件夹
	注意:
		FileFilter是文件过滤器
			重写的是boolean accept(File pathname)
			当返回值为true表示可以通过,反之false不通过
		FilenameFilter是文件名称过滤器
			重写的是boolean accept(File f,String name)
			当返回值为true表示可以通过,反之false不通过
			f:父级文件对象
			name:当前文件的名称

网络

简介

网络
计算机网络

什么是网络?

概念:由点和线构成,表示多个对象之间互相联系
计算机网络:
互联网:Interner
万维网:WWW(World Wide Web)
物联网:Iot(Interner of things)
网络模型(了解):
OSI参考模型:
应用层:如http协议,SMTP协议(邮件)...
表示层:将数据格式进行传话与加密.
会话层:维持通讯
传输层:如恢复通讯,数据流重用等事情.UDP,TCP
网络层:ip,计算机在互联网的地址
数据链路层:对其数据进行格式化的要求
物理层:硬件设备,如网线,网线接口等
因为OSI过于理想化,所有没有被实现
TCP/IP模型
应用层
对应OSI模型的应用层,表示层,会话层
对应的协议:HTTP,SMTP,HTTPS
传输层
对应OSI模型的传输层
对应的协议:TCP,UDP协议
网络层
对应OSI模型的网络层
对应的协议:IP
网络接口层
对应OSI模型的数据链路层与物理层
对应协议:以太网协议,ADSL协议等

网络编程需要什么?

IP
端口号
通讯协议

常用名词

互联网(Internet):
点与点相连
万维网(www-world wide web):
端与端相连
物联网(IoT-Internet of things):
物与物相连
网络编程:
让计算机与计算机之间建立连接,进行通讯

OSI网络架构

简介:
Open System Interconnect
开放式系统互连
存在于概念和理论上的一种模型,它的缺点是分层太多,增加了网络工作的复杂性,所
以没有大规模应用

第一层:物理层为设备之间的数据通信提供传输信号和物理介质。(双绞线、 光导纤维)
作用:建立、维护、断开物理连接。
第二层:链路层在物理层上,通过规程或协议(差错控制)来控制传输数据的正确性。(MAC)
作用:接收来自物理层的位流形式的数据,并封装成帧,传送到上一层;同样,也将来自
上层的数据帧,拆装为位流形式的数据转发到物理层;并且,还负责处理接收端发回的确认
帧的信息,以便提供可靠的数据传输。
第三层:网络层负责定义了能够标识所有网络节点的逻辑地址。(IP地址)
作用:逻辑寻址,IP地址,在下两层的基础上向资源子网提供服务
第四层: 传输层负责是否选择差错恢复协议、数据流重用、错误顺序重排。(TCP、 UDP)
作用:提供可靠和不可靠的传输机制,TCP、UDP
第五层:会话层负责使应用建立和维持会话,使通信在失效时继续恢复通信。(断点续传).
作用:建立、终止、管理实体间的会话连接
第六层:表示层负责定义转换数据格式及加密,允许选择以二进制或ASCII格式传输。
作用:封装数据的格式(加密解密、压缩解压缩)
第七层:应用层负责文件访问和管理、可靠运输服务、远程操作服务。(HTTP、 FTP、SMTP)
作用:人与机器电脑交互的窗口

TCP/IP网络框架

TCP协议: Transmission Control Protocol传输控制协议
是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。建立连
接的过程需要三次握手,断开连接的过程需要四次挥手。
UDP协议: User Datagram Protocol用户数据报协议
是一种无连接的传输层协议,提供面向事务的简单不可靠信息传送服务,每个包的大小
64KB。

IP

概念(重点):计算机在互联网中的地址
IPV4
	4个字节,每个字节由8位组成.所以每段的值0~255
		0000 0000 ~ 1111 1111
	192.168.7.151
IPV6
	16个字节,每个字节8位组成,每段32位,所以每段取值范围0~65535

查看当前计算机IP:
	步骤:
		1,打开dos命令框
		2,输入ipconfig
IP地址的分类:
	A类地址:大型网络,主要服务与国家与政府企业
	B类地址:中型网络,主要服务与大型实验室等
	C类地址:个人网络,咱们普通人与普通企业用的网络

特殊IP:(重点)
	127.0.0.1表示本机
	因为不好记,所以变为了英文localhost
	专业名称:回路地址

相关命令:
	ipconfig
		作用:查看当前计算机的ip信息
	ping
		作用:尝试连接对方

InetAddress类:
	作用:表示计算机在网络中的地址
	常用方法:
		见Day23com.qf.ip的Test类
简介:
Internet Protocol Address
互联网协议地址/网际协议地址
分配给互联网设备的数字标签(唯标识)。说人话就是计算机在互联网中的地址
IP地址分为两种:
IPV4: 4字节32位整数,并分成4段8位的进制数,每8位之间用圆点隔开,每8位整数可
以转换为一个0~255的十进制整数。
格式: D.D.D.D
例如: 255.255.255.255
如:10.35.162.64
IPV6: 16字节128位整数,并分成8段十六进制数,每16位之间用圆点隔开,每16位整
数可以转换为一个0~65535的十进制数。
格式: X.X.X.X.X.X.X.X
例如: FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF.FFFF
IPV4应用分类
A类:政府机构,1.0.0.1 ~ 126.255.255.254
B类:中型企业,128.0.0.1 ~ 191.255.255.254
C类:个人用户,192.0.0.1 ~ 223.255.255.254
D类:用于组播,224.0.0.1 ~ 239.255.255.254
E类:用于实验,240.0.0.1 ~ 255.255.255.254
回环地址: 127.0.0.1(localhost),指本机,一般用于测试使用。
查看IP命令: ipconfig
测试IP命令: ping D.D.D.D
对应类:InetAddress
常用方法:
public static InetAddress getLocalHost():获取本机地址
如:
InetAddress localHost = InetAddress.getLocalHost();
System.out.println(localHost);
打印结果:
LAPTOP-RE2FI941/192.168.0.105
public static InetAddress getByName(String host):通过主机名词获取地
址
如:
InetAddress inetAddress = InetAddress.getByName("LAPTOPRE2FI941");
System.out.println(inetAddress);
打印结果:
LAPTOP-RE2FI941/192.168.0.105
注意:
127.0.0.1,Localhost,域名都表示本机
public static InetAddress[] getAllByName(String host):获取所有相关地
址对象
如:
InetAddress[] addresses =
InetAddress.getAllByName("www.baidu.com");
for (InetAddress address : addresses) {
System.out.println(address.getHostAddress()+"--
"+address.getHostName());
}
输出结果:
	14.215.177.39--www.baidu.com
	14.215.177.38--www.baidu.com
public String getHostAddress():获取主机地址
public String getHostName():获取主机名词

Port:端口

端口号:在通信实体上进行网络通讯的程序的唯一-标识。端口分类:
公认端口: 0~1023
注册端口: 1024~49151
动态或私有端口: 49152~65535
常用端口:
MySql: 3306
Oracle: 1521
Tomcat: 8080
SMTP: 25
Web服务器: 80
FTP服务器: 21
概念:程序在计算机中的地址
范围:0~65535
	注意:
		0~1023:一般被系统占用
		1024~49151:注册端口
		49151~65535:动态端口
常见的端口:
	mysql端口号:3306
	Tomcat端口号:8080
	http协议端口号:80
	Oracle端口号:1521
	redis端口号:6379

通讯协议

TCP
	中文名:传输控制协议
	特点:面向连接,安全可靠,效率低,基于字节流进行通讯的,传输数据大小无限制
		三次握手,四次挥手
		第一次握手第一次挥手:客户端向服务器发起请求
		第二次握手第二次挥手:判断是否连接成功
		第三次握手第三次挥手:客户端上传数据或服务器反馈数据
		第四次挥手:客户端断开连接
	俗称:打电话
	如:去朋友家做客
     1,打电话,询问是否方便
         对方接听电话(一次握手),打完电话后会挂断电话(一次挥手)
     2,去朋友家,敲门
         开门(一次握手),朋友倒茶(一次挥手)
     3,开始聚会
         聊天(一次握手,一次挥手)
     4,说拜拜
         一次挥手

	Java中对应的类:
		Socket:客户端
		ServerSocket:服务器

UDP
	中文名:数据包协议
	特点:面向无连接,不安全,效率高,基于数据包格式进行传输,一个数据包最多64kb
	俗称:对讲机

	如:用对讲机通知同事有小偷
	1,直接对着对讲机说有小偷

基于TCP协议的通讯

技术
	服务器
		创建ServerSocket
		等待客户端连接
		关闭资源
	客户端
		创建客户端Socket
		关闭资源
案例1:
	客户端给服务器发一条消息
案例2:
	客户端给服务器发送一条消息,服务器接收后回复一条消息,客户端接收
案例3:
	客户端上传文件给服务器

基于UDP协议的通讯

技术:
	接收端
		DatagramSocket(端口号)
		接收端对象.receive(数据包):接收数据
	发送端
		DatagramSocket()
		发送端对象.send(数据包):用于发送数据包
	数据包
		DatagramPacket

Socket编程

简介

Socket:套接字,网络中的一个节点
通讯要求:IP地址+端口号

TCP与UDP的区别

TCP:面向有连接,安全,可靠的,慢
特点:三次握手,四次挥手
UDP:面向无连接,不安全的,快
特点:面向无连接,不安全,效率高,基于数据包格式进行传输,一个数据包最多64kb

TCP

简介:是一种面向连接的、可靠的、基于字节流的传输层通信协议。数据大小无限制。建立连
接的过程需要三次握手,断开连接的过程需要四次挥手。
注意:分为客户端Scoket与服务器ServerSocket
开发步骤:
服务端:ServerSocket
	1,创建ServerSocket,指定端口
	2,调用accept等待客户端接入
	3,使用输入流,接收客户端请求中的数据
	4,使用输出流,给客户端回馈数据(可选)
	5,关闭释放资源
客户端:Socket
	1,创建Socket对象,指定服务器IP+端口
	2,使用输出流,发起请求,给服务器发生数据
	3,使用输入流,接收服务器返回的数据(可选)
	4,关闭释放资源
代码:
服务器:
import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpServer {
public static void main(String[] args) throws Exception{
//1 创建ServerSocket 并指定端口号
ServerSocket listener=new ServerSocket(8899);
//2 调用accept(),接收客户端请求,阻塞方法(如果没有客户端请求,
则阻塞)
System.out.println("服务器已启动...");
Socket socket=listener.accept();
//3 获取输入流,读取客户端发送的数据
InputStream is=socket.getInputStream();
BufferedReader br=new BufferedReader(new
InputStreamReader(is,"utf-8"));
String data=br.readLine();
System.out.println("客户发送:"+data);
//4 获取输出流,发送数据给客户端[可选]
//5 关闭释放资源
br.close();
socket.close();
listener.close();
}
}
客户端:
import java.io.BufferedWriter;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
public class TcpClient {
public static void main(String[] args) throws Exception{
//1 创建客户端套接字,并指定服务器的地址和端口号
Socket socket=new Socket("192.168.0.103", 8899);
//2 获取输出流,发送数据给服务器
OutputStream os=socket.getOutputStream();
BufferedWriter bw=new BufferedWriter(new
OutputStreamWriter(os,"utf-8"));
bw.write("好久不见");
//3 获取输入流,读取服务器回复的数据[可选]
//4 关闭释放资源
bw.close();
socket.close();
}
}

文件上传

练习:文件上传
服务器:
import java.io.FileOutputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
public class TcpFileServer {
public static void main(String[] args) throws Exception {
//1创建ServerSocket
ServerSocket listener=new ServerSocket(9999);
//2侦听,接收客户端请求
System.out.println("服务器已启动.........");
Socket socket=listener.accept();
//3获取输入流
InputStream is=socket.getInputStream();
//4边读取,边保存
FileOutputStream fos=new FileOutputStream("d:\\002.jpg");
byte[] buf=new byte[1024*4];
int count=0;
while((count=is.read(buf))!=-1) {
fos.write(buf,0,count);
}
//5关闭
fos.close();
is.close();
socket.close();
listener.close();
System.out.println("接收完毕");
}
}
客户端:
import java.io.FileInputStream;
import java.io.OutputStream;
import java.net.Socket;
public class TcpFileClient {
public static void main(String[] args) throws Exception {
//1创建Socket
Socket socket=new Socket("192.168.0.103", 9999);
//2获取输出流
OutputStream os=socket.getOutputStream();
//3边读取文件,边发送
FileInputStream fis=new FileInputStream("d:\\001.jpg");
byte[] buf=new byte[1024*4];
int count=0;
while((count=fis.read(buf))!=-1) {
os.write(buf,0,count);
}
//4关闭
fis.close();
os.close();
socket.close();
System.out.println("发送完毕");
}
}

服务器与客户端一句句循环对话

练习:服务器与客户端一句句循环对话
服务器:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Scanner;
public class TcpServer {
public static void main(String[] args) throws IOException {
ServerSocket serverSocket = new ServerSocket(9999);
System.out.println("服务器已启动");
Socket accept = serverSocket.accept();
System.out.println(accept.getInetAddress()+"来了");
InputStream is = accept.getInputStream();
BufferedReader br = new BufferedReader(new
InputStreamReader(is,"utf-8"));
OutputStream os = accept.getOutputStream();
BufferedWriter bw = new BufferedWriter(new
OutputStreamWriter(os));
Scanner scanner = new Scanner(System.in);
while(true) {
String str = br.readLine();
System.out.println(accept.getLocalAddress()+"说:"+str);
if (str != null && str.equals("886")) {
break;
}
System.out.println("请输入您要回复的内容:");
String str02 = scanner.next();
bw.write(str02);
bw.newLine();
bw.flush();
}
scanner.close();
bw.close();
br.close();
accept.close();
serverSocket.close();
}
UDP(了解)
}
客户端:
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.Scanner;
public class TcpClient {
public static void main(String[] args) throws IOException {
Socket socket = new Socket("192.168.0.105", 9999);
InputStream is = socket.getInputStream();
BufferedReader br = new BufferedReader(new
InputStreamReader(is,"utf-8"));
OutputStream os = socket.getOutputStream();
BufferedWriter bw = new BufferedWriter(new
OutputStreamWriter(os));
Scanner scanner = new Scanner(System.in);
while(true) {
System.out.println("请输入您要说的内容:");
String str02 = scanner.next();
bw.write(str02);
bw.newLine();
bw.flush();
if (str02 != null && str02.equals("886")) {
break;
}
String str = br.readLine();
System.out.println(socket.getLocalAddress()+"说:"+str);
}
scanner.close();
bw.close();
br.close();
socket.close();
}
}

多人聊天

import java.net.*;
import java.io.*;

public class TCPServer {
 private static final int PORT = 12345;
 private ServerSocket serverSocket;

 public TCPServer() throws IOException {
     serverSocket = new ServerSocket(PORT);
     System.out.println("Server started. Listening to port " + PORT + " ...");
     start();
 }

 private void start() throws IOException {
     while (true) {
         Socket clientSocket = serverSocket.accept();
         System.out.println("Client connected: " + clientSocket);
         ClientHandler clientHandler = new ClientHandler(clientSocket);
         clientHandler.start();
     }
 }

 public static void main(String[] args) throws IOException {
     new TCPServer();
 }
}

class ClientHandler extends Thread {
 private Socket clientSocket;
 private PrintWriter out;

 public ClientHandler(Socket socket) {
     this.clientSocket = socket;
 }

 public void run() {
     try {
         BufferedReader in = new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
         out = new PrintWriter(clientSocket.getOutputStream(), true);

         String inputLine;
         while ((inputLine = in.readLine()) != null) {
             if (inputLine.equals("exit")) {
                 break;
             }
             System.out.println("Message received: " + inputLine);
             out.println("Echo: " + inputLine);
         }

         in.close();
         out.close();
         clientSocket.close();
     } catch (IOException e) {
         e.printStackTrace();
     }
 }
}





import java.net.*;
import java.io.*;
import java.util.Scanner;

public class TCPClient {
 private static final int PORT = 12345;
 private static final String SERVER_HOST = "localhost";

 public static void main(String[] args) throws IOException {
     Socket socket = new Socket(SERVER_HOST, PORT);
     PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
     BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));

     Scanner scanner = new Scanner(System.in);
     String inputLine;
     while ((inputLine = scanner.nextLine()) != null) {
         out.println(inputLine);
         String responseLine = in.readLine();
         System.out.println(responseLine);

         if ("exit".equals(inputLine)) {
             break;
         }
     }

     out.close();
     in.close();
     socket.close();
 }
}

UDP

简介:UDP协议是一种不可靠的网络协议,提供面向事务的简单不可靠信息传送服务,每个包的
大小64KB。
注意:分为接收端与发送端
开发步骤:
发送端:
1.创建发送端的Socket对象(DatagramSocket)
2.创建数据,并打包
3.调用DatagramSocket对象的方法发送数据
4.关闭发送端
接收端:
1、创建接收端的Socket对象(DatagramSocket)
2、创建一个数据包,用于接收数据
3、调用DatagramSocket对象的方法接收数据
4、解析数据包,并在控制台显示
5、关闭接收端

代码

代码:
发送端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
public class UdpSend {
public static void main(String[] args) throws IOException {
//1,创建发送端Socket对象
DatagramSocket socket = new DatagramSocket();
//2,准备发送内容
byte[] sendData = "要发送的内容".getBytes();
//3,接收端地址
InetAddress address =
InetAddress.getByName("192.168.0.105");
//4,封装发送信息包
DatagramPacket packet = new DatagramPacket(sendData,
sendData.length, address, 9999);
//5,发送信息
socket.send(packet);
//6,关闭发送端
socket.close();
}
}
接收端:
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
public class UdpGet {
public static void main(String[] args) throws IOException {
//1,创建接收端Socket
DatagramSocket socket = new DatagramSocket(9999);
//2,创建接收数据的包
byte[] b = new byte[1024];
DatagramPacket packet = new DatagramPacket(b, b.length);
//3,等待接收数据
socket.receive(packet);
//4,获取数据
byte[] data = packet.getData();
//5,获取数据长度
int length = packet.getLength();
//6,打印输出
System.out.println("接收的内容:"+new
String(data,0,length));
//7,关闭资源
socket.close();
}
}

反射

类对象

一个类被加载时会生成一个对象,该对象称为该类的类对象
该对象属于Class类的对象

类对象中包含该类的所有信息,如包,父类,实现的接口,类名,属性,方法,构造函数,注解等内容

注意:
	一个类只有一个类对象

如何获取类对象

方式1:类名.class
方式2:对象名.getClass()
方式3:Class.forName("类的全路径")
	类的全路径:类所属的包名+类名

类对象提供的方法

类相关:
	包
		Package getPackage()
	类名
		String getSimpleName()
	类的全路径
		String getName()
	父类的类对象
		Class<? super T> getSuperclass()
	接口的类对象
		Class<?>[] getInterfaces()

属性相关
	获取所有的公共属性,包含父类提供的
		Field[] getFields()
	获取所有的属性,不包含父类提供的
		Field[] getDeclaredFields()
	获取指定的公共属性
		Field getField(String name)
	获取指定的属性
		Field getDeclaredField(String name)
	Field提供的方法
		Object get(Object obj);
			作用:获取指定对象的该属性值
			1参:指定的对象
		void set(Object obj,Object v);
			作用:修改指定对象的该属性值
			1参:指定的对象
			2参:修改后的值
		setAccessible(boolean flag):是否略过访问权限修饰符
			默认为false,表示不略过
			当值为true表示略过

方法相关
	获取所有的公共方法,包含父类提供的
		Method[] getMethods()
	获取所有的方法,不包含父类提供的
		Method[] getDeclaredMethods()
	获取单独一个公共的方法
		Method getMethod(String name, Class<?>... parameterTypes)
		1参:要获取的方法名
		2参~:该方法的形参列表对应的数据类型的类对象
		注意:按顺序书写,基本数据类型的类对象是数据类型.class,其包装类的类对象是类名.class
	获取单独一个方法
		Method getDeclaredMethod(String name, Class<?>... parameterTypes)
		1参:要获取的方法名
		2参~:该方法的形参列表对应的数据类型的类对象
		注意:按顺序书写,基本数据类型的类对象是数据类型.class,其包装类的类对象是类名.class
	Method提供的方法:
		Object invoke(Object obj, Object... args)
			作用:执行该方法
			1参:执行该方法的对象
			2参~:执行该该方法所需的实参列表
			返回值:执行该方法的返回值
		setAccessible(boolean flag):是否略过访问权限修饰符
			默认为false,表示不略过
			当值为true表示略过

构造函数相关
	Constructor<?>[] getConstructors()
		作用:获取该类中所有公共构造函数
	Constructor<?>[] getDeclaredConstructors()
		作用:获取所有构造函数
	Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)
		作用:获取指定的一个构造函数
		参数:
			构造函数对比的形参列表的数据类型的类对象
	Constructor提供的方法
		T newInstance(Object ... initargs)
			作用:创建该类对象
			参数:对应的构造函数的实参列表
		setAccessible(boolean flag):是否略过访问权限修饰符
			默认为false,表示不略过
			当值为true表示略过

枚举

使用步骤

1,定义
2,使用

定义

语法:
	访问权限修饰符 enum 枚举名{
		属性名1,属性名2,属性名3,...属性名n
	}

使用

情况1:使用枚举的属性
	语法:
		枚举名.属性名
情况2:枚举作为形参
	传递实参时必须传入枚举的属性

注解

作用

解释代码的代码,称为注解,又名元代码

注释与注解的区别

注释:不会影响代码
注解:对代码有一定的约束作用

常见的注解

@Override
	作用:说明当前方法为重写的方法
@SuppressWarnings("all")
	作用:忽略警告

元注解
	概念:解释注解的注解
@Target
  作用:注解使用位置
  值:
  TYPE:类,接口,枚举上使用
		FIELD:属性上使用
		METHOD:方法使用
		PARAMETER:参数上使用
		CONSTRUCTOR:构造函数
		LOCAL_VARIABLE:局部变量使用
		ANNOTATION_TYPE:注解使用
		PACKAGE:包使用
		注意:没有写可以在任何地方使用

@Retention
  作用:注解作用时机
  值:
  	SOURCE:java源程序中存在
			CLASS:字节码文件中存在
			RUNTIME:运行时存在

@Documented
  作用:可以生成API文档

@Inherited
  作用:说明当前注解是否可以被子类继承,默认不能被子类继承

自定义注解

语法:
	访问权限修饰符 @interface 注解名{
		数据类型 属性名1() [default 默认值];
		数据类型 属性名2() [default 默认值];
		...
	}

注解的使用

@注解名(属性名 = 属性值,属性名 = 属性值,...);
注意:
	1,当注解中的属性有默认值,可以在使用注解时不用赋值
	2,当注解中所有属性都有默认值或没有属性时,可以省略小括号不写
		@注解名
	3,当注解中只有一个属性,并且该属性的属性名为value,此时在使用注解时可以省略属性名不写
		@注解名(属性值)

设计模式

概念

程序员总结出的解决特定问题的思路

单例模式

特定问题

一个类只能有一个对象

分类

懒汉式
	步骤:
		1,私有化构造函数
		2,提供一个公共的属性,记录该类的唯一对象
		3,提供一个公共的静态方法返回该类创建好的对象
	优点:
		节省内存
	缺点:
		有线程安全问题
饿汉式
	步骤:
		1,私有化构造函数
		2,提供一个公共的属性,记录该类的唯一对象,并创建该对象
		3,提供一个公共的静态方法返回该类创建好的对象
	优点:
		不存在线程安全问题
	缺点:
		浪费内存

线程安全的懒汉式
	代码:
		public class C {
    private static C c;
    private C(){

    }
    public synchronized C getInstance(){
        if (c == null){
            c = new C();
        }
        return c;
    }
}
优点:
	线程安全
缺点:
	效率慢

内部类饿汉式
	代码:
public class D {
    private D(){
    }
    public static D getInstance(){
        return InClass.getD();
    }
    static class InClass{
        private static D d = new D();
        public static D getD(){
            return d;
        }
    }
}

工厂模式

特定问题

特定编号生产特定商品

例子

家具厂
    沙发
    椅子
    床
    衣柜
    茶几
    ...
​
分析:
    类
        家具厂类
            家具接口对象 生产的方法(编号){
                switch(编号){
                    case 1:
​
                }
            }
        家具接口
        沙发类 实现 家具接口
        椅子类 实现 家具接口
        床类 实现 家具接口
        衣柜类 实现 家具接口
        茶几类 实现 家具接口
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值