Java基础知识点汇总

一、 概述

1.1 Java语言发展史

​ Java语言之父:詹姆斯·高斯林(James Gosling)

​ 诞生时间:1995年

​ 发明公司:斯坦福大学网络公司 SUN(Stanford University Network)

​ 跨平台:Java程序可以再任意操作系统上运行,一次编写到处运行,依赖的是Java的虚拟机JVM。

1.2 发行版本

​ JavaSE:标准版,是为开发普通桌面和商务应用程序提供的解决方案,该技术体系是其他两者的基础,可以完成一些桌面应用程序的开发。 

​ JavaEE:企业版,是为开发企业环境下的应用程序提供的一套解决方案,该技术体系中包含的技术如 Servlet、Jsp等,主要针对于Web应用程序开发

​ JavaME:移动版,是为开发电子消费产品和嵌入式设备提供的解决方案

1.3 组成部分

​ JDK : Java开发工具 — JRE + JAVA的开发工具

​ JRE :Java运行时环境 — JVM + 类库

​ JVM:Java虚拟机

二、 基础语法

2.1 注释

2.1.1 单行注释

​ 格式: //注释文字 ( Ctrl + / 添加、取消)

2.1.2 多行注释

​ 格式:/* 注释文字 */ ( Ctrl + Shift + / 添加 )( Ctrl + Shift + \ 取消 )

2.1.3 文档注释

​ 格式:/** 注释文字 */

2.2 关键字

2.2.1 概述

​ Java 规定的有特殊含义的单词

2.2.2 特点

​ 组成关键字的字母全部小写

​ 常见的代码编辑器对关键字有特殊的颜色标记

2.3 常量

2.3.1 概述

​ 在程序执行的过程中,其值不可以发生改变的量

​ 用 public static final 修饰,名称大写,多个单词中间用_连接

2.3.2 分类

​ 字符串常量 :用双引号括起来的内容( “HelloWorld” );

​ 整数常量 : 所有整数 (12 ,-23)

​ 小数常量 :所有小数(12.34)

​ 字符常量 : 用单引号括起来的内容 ( ‘a’ , ‘A’ , ‘0’ )

​ 布尔常量 : 较为特有,只有true和false

​ 空常量 : null

2.4 变量

2.4.1 概述

​ 在程序执行的过程中,在某个范围内其值可以发生改变的量

​ 从本质上讲,变量其实是内存中的一小块区域

2.4.2 定义格式

​ 数据类型 变量名 = 初始化值;

2.5 数据类型

[外链图片转存失败(img-R2sAlDOV-1565402562391)(E:\学习\Typora笔记图片\数据类型.jpg)]

2.5.1 基本数据类型

[外链图片转存失败(img-Kuqa0oAL-1565402562391)(E:\学习\Typora笔记图片\基本数据类型.jpg)]

2.5.2 引用数据类型

​ 类:class

​ 接口:interface

​ 数组:[ ]

2.6 标识符

2.6.1 规则

​ unicode字符(数字,英文大小写,汉字)

​ 下划线 _

​ 美元符号 $

2.6.2 规范

​ 见名知意

2.6.3 驼峰命名法

​ 最好是域名倒过来,要求所有的字母小写

类或者接口

​ 如果是一个单词首字母大写

​ 如果是多个单词每个单词首字母大写(驼峰标识)

方法或者变量

​ 如果是一个单词全部小写

​ 如果是多个单词,从第二个单词首字母大写

常量

​ 如果是一个单词,所有字母大写

​ 如果是多个单词,所有的单词大写,用下划线区分每个单词

2.7 数据类型转换

2.7.1 隐式数据类型转换

​ 1:基本类型参与运算遵循以下原则:char/byte/short -> int -> long -> float -> double

2:小容量类型的数据可以赋值给大容量类型的变量
2.7.2 显式数据类型转换

​ 大容量类型的数据赋值给小容量类型的变量 但是有可能会出现损失精度的问题

2.7.2.1 格式

​ 目标类型 变量名 = ( 目标类型 )(被转换的数据);

2.8 运算符

2.8.1 算术运算符
2.8.1.1 + - * / %

a: / java中两个整数相除得到的结果一定是整数 如果想要得到浮点值 ,就把其中一个数定义为浮点类型

b: / 得到的结果是两个数相除的商值

c: % 得到的结果是两个相除之后的余数

d: + 在整数和小数以及char类型之间是做数学运算

e: 如果字符串后面有+ 那么是做得字符串拼接操作 ,是按照运算的顺序 自左向右运算

​ "5 + 5 : " + 5 + 5 -> “5 + 5 : 55”
"5 + 5 : " + (5 + 5) -> “5 + 5 : 10”

2.8.1.2 自增自减运算符

++ / – 变量自身自加一/自减一

a:如果x单独使用,++在前在后都一样 都是自加一 x++; ++x;

b:如果x出现在表达式或者参与运算

​ 1:++在后 先使用变量自身的值参与运算 然后自加1

​ 2:++在前 先自加1 然后再去参与运算

​ int x = 5;

​ int y = x++ + ++x + x-- + ++x;

​ 5 7 7 7

2.8.2 赋值运算符
2.8.2.1 基本的赋值运算符 =

​ 表示把等号右边的值赋值给等号左边的变量

2.8.2.2 扩展的赋值运算符 += , -= , *= , /= , %=

​ a: += 里面隐含了数据类型的强制转换

​ b: += 除了可以做数学运算 还可以做字符串的拼接

2.8.3 关系运算符

== , != , > , >= , < , <=

​ 关系运算符组成的关系表达式结果一定是布尔类型

2.8.4 逻辑运算符

&& AND 两边条件都为true 结果才为true 遇到false则false
|| OR 两边条件只要有一个为true 结果就是true 遇到true则true
! NOT 取相反的值

注意 : &&和&,||和| 区别 :&& ||能够提高程序的执行效率

2.8.5 三元运算符

​ 数据类型 变量名 = ( 关系表达式 ? 结果1 : 结果2 ) ;

​ 关系表达式结果 true 则 结果1,false 则 结果2

三、 键盘录入

3.1概述

​ 我们目前在写程序的时候,数据值都是固定的,但是实际开发中,数据值肯定是变化的,所以,把数据改进为键盘录入,提高程序的灵活性。

3.2 步骤

3.2.1 导包
improt  java.util.Scanner    //(位置放到 class 定义的上面)
3.2.2 创建对象
Scanner sc = new Scanner(System.in);
3.2.3 接收数据
int x = sc.nextInt();

​ next( ) -> String
nextInt( ) -> int
nextBoolean( ) -> boolean
nextLine( ) -> String

四、 流程控制语句

4.1 顺序结构

​ 自上向下 依次执行

4.2 选择结构

4.2.1 If 语句的结构

首先判断关系表达式看其结果是true还是false

​ 如果是true就执行语句体

​ 如果是false就不执行语句体

4.2.1.2 格式2

首先判断关系表达式看其结果是true还是false

​ 如果是true就执行语句体1

​ 如果是false就执行语句体2

4.2.1.3 格式3

首先判断关系表达式1看其结果是true还是false

​ 如果是true就执行语句体1

​ 如果是false就继续判断关系表达式2看其结果是true还是false

​ 如果是true就执行语句体2

​ 如果是false就继续判断关系表达式…看其结果是true还是false

​ …

​ 如果没有任何关系表达式为true,就执行语句体n+1

4.2.2 switch 语句

4.2.2.1 switch 语句的格式
switch(表达式) {	//表达式的取值:byte,short,int,char,枚举(JDK5),String(JDK7)  
  	case1:
 		语句体1;
  		break;
  	case2:
  		语句体2;
  		break;
  	case3:
 		语句体3;
 		break;
  	...
  	default:
  		语句体n+1;
  		break;
 }

​ 首先计算出表达式的值

​ 其次,和case依次比较,一旦有对应的值,就会执行相应的语句,在执行的过程中,遇到break就会结束

​ 最后,如果所有的case都和表达式的值不匹配,就会执行default语句体部分,然后程序结束掉。

4.3 循环结构

4.3.1 for 循环

4.3.1.1 for 循环语句的格式
for( 初始化语句 ; 判断条件语句 ; 控制条件语句 ) {
    循环体语句;
}
4.3.1.2 for 死循环
for(;;){
	循环体;
}

4.3.2 while 循环

4.3.2.1 while 循环语句的格式
while(判断条件语句) {		//基本格式
    循环体语句;
}
初始化语句;
while(判断条件语句) {		//扩展格式
    循环体语句;
    控制条件语句;
}
4.3.2.2 while 死循环
while(true){
	循环体;
}

4.3.3 dowhile 循环

4.3.3.1 dowhile 循环语句的格式
do {				//基本格式
     循环体语句;
 }while((判断条件语句);
初始化语句;			//扩展格式
do {
     循环体语句;
     控制条件语句;
} while((判断条件语句);

4.3.4 三种循环的区别

虽然可以完成同样的功能,但是还是有小区别:

​ do…while循环至少会执行一次循环体。

​ for循环和while循环只有在条件成立的时候才会去执行循环体

for循环语句和while循环语句的小区别:

​ 控制条件语句所控制的那个变量,在for循环结束后,就不能再被访问到了,而while循环结束还可以继续使用,如果你想继续使用,就用while,否则推荐使用for。原因是for循环结束,该变量就从内存中消失,能够提高内存的使用效率。

4.3.5 循环嵌套

for( 初始化表达式1 ; 条件判断语句1 ; 条件控制语句1 ){
	for( 初始化表达式2 ; 条件判断语句2 ; 条件控制语句2 ){
		循环体;
	}
}
打印直角三角形

外层循环是用来控制打印的总行数
内层循环使用来控制打印每一行上的星号数量
1 * 2 - 1
2 * 2 - 1
3 * 2 - 1
4 * 2 - 1
5 * 2 - 1

for (int i = 1; i <= 5; i++) {// 控制总行数
	for (int j = 1; j <= 2 * i - 1; j++) {
		System.out.print("*");
	}
	System.out.println();
}
打印等腰三角形

外层循环是用来控制打印的总行数
经过观察 每一行上都有空格符
line1 4空格 1个星号
line2 3空格 3个星号
line3 2空格 5个星号
line4 1空格 7个星号
line5 0空格 9个星号

每行的空格数量 = 总行数 - 当前行号

int total = 5;
for (int x = 1; x <= total; x++) {// 外层循环控制总行数
	for (int y = 1; y <= total - x; y++) {
		System.out.print(" ");// 控制每一行上空格的数量
	}
	for (int z = 1; z <= 2 * x - 1; z++) {
		System.out.print("*");// 控制每一行上星号的数量
	}
	System.out.println();
}
打印菱形

一共四行
line1 1空格 7个星号 8 - 1
line2 2空格 5个星号 8 - 3
line1 3空格 3个星号 8 - 5
line1 4空格 1个星号 8 - 7
每行的空格数量 = 当前行号
每行的星号数量 = 总行数2 - (2当前行号 - 1)

int total = 5;
for (int x = 1; x <= total; x++) {// 外层循环控制总行数
	for (int y = 1; y <= total - x; y++) {
		System.out.print(" ");// 控制每一行上空格的数量
	}
	for (int z = 1; z <= 2 * x - 1; z++) {
		System.out.print("*");// 控制每一行上星号的数量
	}
	System.out.println();
}

for (int i = 1; i <= total - 1; i++) {
	for (int j = 1; j <= i; j++) {
		System.out.print(" ");
	}
	for (int k = 1; k <= ((total - 1) * 2) - (2 * i - 1); k++) {
		System.out.print("*");
	}
	System.out.println();
}
打印空心菱形
int total = 5;
for (int x = 1; x <= total; x++) {// 外层循环控制总行数
	for (int y = 1; y <= total - x; y++) {
		System.out.print(" ");// 控制每一行上空格的数量
	}
	for (int z = 1; z <= 2 * x - 1; z++) {
		if (z == 1 || z == 2 * x - 1) {
			System.out.print("*");// 控制每一行上星号的数量
		} else {
			System.out.print(" ");// 控制每一行上空格的数量
		}
	}
	System.out.println();
}
for (int i = 1; i <= total - 1; i++) {
	for (int j = 1; j <= i; j++) {
		System.out.print(" ");
	}
	for (int k = 1; k <= ((total - 1) * 2) - (2 * i - 1); k++) {
		if (k == 1 || k == ((total - 1) * 2) - (2 * i - 1)) {
			System.out.print("*");
		} else {
			System.out.print(" ");
		}
	}
	System.out.println();
}
打印九九乘法表
for(int x=1; x<=9; x++) {
	for(int y=1; y<=x; y++) {
		System.out.print(y+"*"+x+"="+y*x+"\t");
	}
	System.out.println();
}

4.3.6 循环控制

4.3.6.1 break

在单层循环中是:满足条件后结束整个循环 也可以结束switch…case语句

在多层循环嵌套中:结束离他最近的那个循环,如果要指定结束某个循环 ,可以使用带标签名的明明方式

4.3.6.2 continue

满足条件后跳过当前循环 进入下一次循环

五、 Random 随机数

5.1 概述

​ 用于产生一个随机数

5.2 导包

import java.util.Random;

5.3 创建对象

Random r = new Random();

5.4 获取随机数

int number = r.nextInt(10);

产生的数据在 0 到 10 之间,包括 0 ,不包括 10 。

六、 数组

6.1 概念

用来存放同一种类型的,长度固定的容器

可以存放基本类型的数据,也可以存放引用类型的数据

6.2 一维数组

6.2.1 定义格式

数据类型[] 数组名;(推荐使用)
数据类型 数组名[];

6.2.2 初始化

6.2.2.1 概述

​ 就是为数组中的数组元素分配内存空间,并为每个数组元素赋值。

6.2.2.2 动态初始化

初始化时只指定数组长度,由系统为数组分配初始值。

使用动态初始化创建出来的数组对象里面的元素都是本类型的默认值

byte/short/int/long -> 0
float/double -> 0.0
char -> \u0000
boolean -> false
其他引用类型数组 -> null

6.2.2.3 静态初始化

初始化时指定每个数组元素的初始值,由系统决定数组长度。

数据类型[] 数组名 = new 数据类型[]{元素1,元素2,};

6.2.4 存取及常见问题

存元素
数组名[索引] = 数值; 
取元素
数据类型 变量名 = 数组名[索引];
常见问题
ArrayIndexOutOfBoundsException

​ 数组索引越界异常

​ 我们访问了不存在的索引。

NullPointerException

​ 空指针异常

​ null是指不再指向堆内存的数据,而我们还在访问堆内存的数据

6.2.5 数组的遍历

6.2.5.1 长度

​ 用于获取数组中的元素个数

​ 使用格式:数组名.length

6.2.5.2 普通 for 循环
int[] arr = {11,22,33,44,55};
for(int x=0; x<arr.length; x++) {
	System.out.println(arr[x]);
}
6.2.5.3 增强 for 循环
int[] arr = {11,22,33,44,55};
for(Integer i : arr) {
	System.out.println(i);
}
6.2.5.4 区别

​ 普通for可以遍历,但是语法比较繁琐,但是涉及到索引的操作就必须使用它

​ 增强for语法比较简洁,但是没有索引

6.2.5.5 求最值

​ 确定一个参照物,假设数组中的第一个元素是最大值,然后依次和后面个每一个元素进行对比,如果后面的元素比他更大,就给该参照物重新赋值. 求最小值相反,判断后面的元素是否比它更小,如果是就重新赋值

int[] arr = {12,98,45,73,60};
//定义参照物
int max = arr[0];
//遍历数组,获取除了0以外的所有元素,进行比较
for(int x=1; x<arr.length; x++) {
	if(arr[x] > max) {
		max = arr[x];
	}
}
System.out.println("数组中的最大值是:"+max);
6.2.5.6 不死神兔

需求:有一对兔子,从出生后第3个月起每个月都生一对兔子,小兔子长到第三个月后每个月又生一对兔子,假如兔子都不死,问第二十个月的兔子对数为多少?

int[] arr = new int[20];
//给数组中的元素赋值
arr[0] = 1;
arr[1] = 1;
//从第三个月开始,根据规律赋值
for(int x=2; x<arr.length; x++) {
	arr[x] = arr[x-1] + arr[x-2];
}
//输出第二十个月的兔子对数,其实就是输出arr[19]
System.out.println("第二十个月的兔子对数是:"+arr[19]);

6.3 二维数组

6.3.1 定义格式

6.3.1.1 格式1
数据类型[][] 变量名 = new 数据类型[m][n];
int[][] arr = new int[3][2];

m表示这个二维数组有多少个一维数组

n表示每一个一维数组的元素个数

6.3.1.2 格式2
数据类型[][] 变量名 = new 数据类型[m][];

m表示这个二维数组有多少个一维数组

这一次没有直接给出一维数组的元素个数,可以动态的给出。

举例:

int[][] arr = new int [3][];
arr[0] = new int[2];
arr[1] = new int[3]
arr[2] = new int[1];
6.3.1.3 格式3
数据类型[][] 变量名 = new 数据类型[][]{{元素…},{元素…},{元素…}};

简化格式

数据类型[][] 变量名 = {{元素…},{元素…},{元素…}};
int[][] arr =  {{1,2,3},{4,6},{6}};

七、 方法

7.1 概述

​ 能够完成某些

+特定功能的代码块

7.2 定义格式

修饰符 返回值类型 方法名(参数类型 参数名1,参数类型 参数名2) {
	函数体;
	return 返回值;
}

7.3 方法的重载

7.3.1 概述

​ 在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数类型不同即可。

7.3.2 特点

​ 与返回值类型无关,只看方法名和参数列表

​ 在调用时,虚拟机通过参数列表的不同来区分同名方法

7.4 方法的可变长参数

修饰符 返回值类型 方法名(数据类型...参数名){}

​ 可变长参数的长度是不确定的,直到我们调用方法传入具体参数之后才能确定,jvm会把这些参数放入到一个数组中,我们需要在方法中对这个数组进行遍历 取值

7.5 方法的参数类型问题

​ 如果参数是基本类型 形参的改变不会影响到实参

​ 如果参数是引用类型 形参的改变会影响到实参(String除外)

7.6 方法的递归调用

​ 方法自身调用自身

​ 注意要有出口条件 否则会出现栈内存溢出错误

八、 面向对象

8.1 概述

​ 面向对象是一种编程思想,区别于以前的面向过程

  • 面向过程 : 强调是如何去完成每一个步骤,步骤和步骤之间的关系是非常紧密的,耦合度很高
  • 面向对象 : 强调的是哪个对象能够完成该功能,我们应该去找到该对象来实现

8.2 面向对象的思想特点

​ A : 是一种符合我们思考习惯的思想

​ B : 可以将复杂的事情简单化

​ C : 让我们从执行者变成了指挥者

8.3 类和对象

类 : 一系列具有相同属性和行为的事物的合集,他是一种抽象的表示形式

类的组成:成员变量/get/set方法/成员方法/构造方法/成员代码块/静态代码块

对象 : 一个类的具体的体现 把抽象的类变成一个具体的可以描述的事物

8.3.1 创建对象

类名 对象名 = new 类名();

8.3.2 成员变量

​ 和我们学习过的变量的定义是一样的,有两个小区别。

​ 位置不同:类中,方法外

​ 初始化值:成员变量不需要给初始化值也可以使用,因为它有默认值

8.3.3 成员方法

​ 和我们学习过的方法的定义是一样的,有一个小区别。

​ 去掉了修饰符中的static关键字

8.4 关键字和封装

8.4.1 private 关键字

​ 是一个权限修饰符。

​ 可以修饰成员(成员变量和成员方法)

​ 被 private 修饰的成员只在本类中才能访问。

​ 把成员变量用private修饰

​ 提供对应的getXxx()/setXxx()方法

private String name;
	private int age;	
	public void setName(String n) {
		name = n;
	}
	public String getName() {
		return name;
	}	
	public void setAge(int a) {
		age = a;
	}
	public int getAge() {
		return age;
	}

8.4.2 封装

8.4.2.1 封装概述

​ 是面向对象三大特征之一

​ 是面向对象编程语言对客观世界的模拟,客观世界里成员变量都是隐藏在对象内部的,外界无法直接操作和修改。就像刚才说的年龄。

8.4.2.2 封装原则:

​ 将不需要对外提供的内容都隐藏起来。

​ 把属性隐藏,提供公共方法对其访问。

​ 成员变量private,提供对应的getXxx()/setXxx()方法

8.4.2.3 好处

​ 通过方法来控制成员变量的操作,提高了代码的安全性

​ 把代码用方法进行封装,提高了代码的复用性

8.4.3 this 关键字

​ this是一个引用类型,它保存了当前对象的内存地址 指向该对象自身,每一个new出来的对象都有一个属于自己的this
对于方法来说,谁调用该方法,this就代表谁/this还可以用来区分同名的成员变量和局部变量
this(参数…) 调用本类中其他的有参构造

8.5 构造方法

8.5.1 概述

​ 给对象的数据进行初始化

8.5.2 格式

​ 没有返回值 也不能写void
方法名必须和类名一致
如何定义一个类没有提供任何的构造 jvm会默认生成一个无参构造

Student s = new Student();

8.6 继承

8.6.1 概述

  1. 多个类中存在相同的属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需在定义这些属性和行为,只要继承那个类即可
  2. 单独的这个类称为父类,基类或者叫超类,多个类可以称为子类或者派生类
  3. 有了继承以后,我们定义一个类的时候,可以在一个已经存在的类的基础上,还可以定义自己的新成员

8.6.2 格式

public class 子类名 extends 父类名{}

8.6.3 好处和弊端

8.6.3.1 继承的好处
  1. 提高了代码的复用性

    ​ 多个类相同的成员可以放到同一个类中

  2. 提高了代码的维护性

    ​ 如果功能的代码需要修改,修改一处即可

  3. 让类与类之间产生了关系,是多态的前提

8.6.3.2 继承的弊端

​ 好处的第三点同时也是继承的弊端:类与类之间产生了关系,让类的耦合性增强了

​ 设计原则:高内聚低耦合

8.6.4 继承的特点

  1. 只能单继承,不能多继承 但是可以多层继承
  2. 如果一个类继承了某个父类,那么它可以继承该类中非私有的成员
  3. java中如果一个类, 没有显性的定义它的父类,那么默认继承Object类 Object是java中所有类的根类
8.6.4.1 继承中成员变量的特点
  1. 成员变量名称不一样,使用的时候非常简单

  2. 成员变量名称一样的情况:

    ​ 在子类中访问变量:(就近原则)

    ​ 在方法的局部范围找,如果有就使用

    ​ 在子类的成员范围找,如果有就使用

    ​ 在父类的成员范围找,如果有就使用

    ​ 如果还找不到就报错

8.6.4.2 继承中成员方法的特点
  1. 如果成员范围 父类范围都有同名的方法,程序运行时遵循就近原则,先从成员->父类
  2. 如果指明要使用成员范围的方法:this.方法名(); 注意:this可以省略
  3. 如果指明要使用父类范围的方法:super.方法名();

8.6.5 super 关键字

super的用法和this很像

​ this代表本类对象的引用

​ super代表父类存储空间的标识(可以理解为父类对象引用)

用法(this和super均可如下使用)

​ 访问成员变量:this.成员变量 super.成员变量

​ 访问构造方法:this(…) super(…)

​ 访问成员方法:this.成员方法() super.成员方法(

注意:this() 和 super() 不能同时出现,super() 必须放在子类构造方法的第一行,如果是调用父类无参构造,那么可以省略

8.6.6 方法的重写

8.6.6.1 概述

​ 子类中出现了和父类中一摸一样的方法声明

8.6.6.2 应用

​ 当子类需要父类的功能,而功能主体子类有自己特有的内容时,可以重写中的方法,这样重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。

8.6.6.3 注意事项
  1. 必须有继承关系
  2. 子类重写方法 只能修改方法体,方法的声明必须和父类中的方法的声明一致
  3. 私有的方法不能被重写
  4. @Override 注解 表名该方法是对父类方法的重写

8.7 多态

8.7.1 概述

​ 某一个事物,在不同时刻表现出来的不同状态。

8.7.2 前提和体现

  1. 有继承关系
  2. 有方法重写
  3. 有父类引用指向子类对象
父类型 对象名 = new 子类型();

8.7.3 成员的访问特点

8.7.3.1 成员变量

​ 编译看左边,运行看左边

8.7.3.2 成员方法

​ 编译看左边,运行看右边,不能直接使用子类中特有的成员方法

8.7.4 类型转换

向上转型 upcasting 父类型 对象名 = new 子类型 ( ) ;

向下转型 downcasting 子类型 对象名 = (子类型)原始对象名 ;

注意:强转时需要注意:如果两者之间没有继承关系 那么强转时会引发类型转换异常 为了避免异常发生 在做强转之前最好先判断一下两者之间是否存在关系

boolean flag = a instanceof b 

如果 flag 为 true,那么就可以强转,否则不允许强转

8.7.5 内存图

[外链图片转存失败(img-P8RFuIYD-1565402562399)(E:\学习\Typora笔记图片\多态内存图.jpg)]

8.8 final 关键字和 static 关键字

8.8.1 final 关键字

final关键字是最终的意思,可以修饰类,成员变量,成员方法。

​ 修饰类,类不能被继承

​ 修饰变量,变量就变成了常量,只能被赋值一次

​ 修饰方法,方法不能被重写

8.8.2 static 关键字

8.8.2.1 静态的特点
  1. 被类的所有对象共享:这也是我们判断是否使用静态关键字的条件
  2. 可以通过类名调用
  3. 优先于对象存在
  4. 随着类的加载而加载
8.8.2.2 静态方法的访问特点
  1. 静态方法只能访问静态的成员变量和静态的成员方法
  2. 在静态方法中是没有this,super关键字的,静态的内容是随着类的加载而加载,this和super是随着对象的创建而存在。
  3. 先进内存的,不能访问后进内存的

8.9 抽象类

8.9.1 抽象类的格式

public abstract class 类名{}

8.9.2 抽象类的特点

  1. 抽象类不能被实例化 存在意义就是为了被别的类继承

  2. 如果一个类继承了抽象类 必须重写抽象类中所有的抽象方法

  3. 创建子类对象时 可以使用抽象类多态的方式

    父抽象类名 对象名 = new 子类();
    

8.9.3 成员组成

成员变量

​ 可以是变量,也可以是常量

构造方法

​ 有构造方法,但是不能实例化(用于子类访问父类数据的初始化)

成员方法

​ 可以有抽象方法(限定子类必须完成某些动作),也可以有非抽象方法 提高代码复用性

8.10 接口

8.10.1 接口的格式

public interface 接口名{}

8.10.2 接口的实现格式(implements)

public class 类名 implements 接口名 {} 

8.10.3 接口的特点

  1. 接口也是不能被实例化 存在的意义就是为了让别的类实现

  2. 如果一个类实现了一个接口 必须重写该接口中所有的抽象方法

  3. 创建子实现类对象时 可以使用接口多态的方式定义

    父接口名 对象名 = new 子实现类();
    

8.10.4 成员组成

成员变量

​ 只能是常量,默认修饰符 public static final

构造方法

​ 没有,因为接口主要是扩展功能的,而没有具体存在

成员方法

只能是抽象方法,默认修饰符   public   abstract

8.11 类和接口的关系

8.11.1 类与类

​ 继承关系,只能单继承,但是可以多层继承

8.11.2 类与接口

​ 实现关系,可以单实现,也可以多实现。还可以在继承一个类的同时实现多个接口

8.11.3 接口与接口

​ 继承关系,可以单继承,也可以多继承

8.12 包

8.12.1 概述

​ 对定义的类进行分门别类的管理

8.12.2 格式

package 包名; 多级包用 . 分开即可

注意事项:

​ package语句必须是程序的第一条可执行的代码

​ package语句在一个java文件中只能有一个

8.12.3 导包

​ 要引入其他包的类,但是 java.lang 下的类可以直接使用,无需导包

import java.包名.类名;

8.13 权限修饰符

本类同包下的子类和其他类不同包下的子类不同包下的其他类
public
protected
默认修饰符
private

8.14 代码块

//BlockTest静态代码块执行 --- BlockTest的主函数执行了 --- Coder静态代码块执行 --- Coder构造代码块执行 --- Coder无参空构造执行 --- Coder构造代码块执行 --- Coder无参空构造执行

public class BlockTest {
	static {
		System.out.println("BlockTest静态代码块执行");
	}
	{
		System.out.println("BlockTest构造代码块执行");
	}
	public BlockTest(){
		System.out.println("BlockTest无参构造执行了");
	}
	public static void main(String[] args) {
		System.out.println("BlockTest的主函数执行了");
		Coder c = new Coder();
		Coder c2 = new Coder();
	}
}
class Coder {
	static {
		System.out.println("Coder静态代码块执行");
	}
	{
		System.out.println("Coder构造代码块执行");
	}
	public Coder() {
		System.out.println("Coder无参空构造执行");
	}	
}

8.15 内部类

8.15.1 概述

​ 将类写在其他类的内部,可以写在其他类的成员位置和局部位置,这时写在其他类内部的类就称为内部类。

8.15.2 内部类的使用场景

​ 在描述事物时,若一个事物内部还包含其他可能包含的事物,比如在描述汽车时,汽车中还包含这发动机,这时发动机就可以使用内部类来描述。

class 汽车 { //外部类
	class 发动机 { //内部类
}
}

8.15.3 成员内部类

8.15.3.1 概述

​ 在类的成员位置,和成员变量以及成员方法所在的位置是一样的

​ 在内部类当中,可以直接访问外部类的成员,包括私有成员

8.15.3.2 定义格式
class 外部类 { 
	修饰符 class 内部类 {
		//其他代码
	}
}
8.15.3.3 访问方式
外部类名.内部类名 变量名 = new 外部类名().new 内部类名();
8.15.3.4 成员内部类的修饰符

​ 我们可以使用权限修饰符修饰成员内部类,但是如果使用私有来修饰,则无法在其他类中访问

​ 我们可以使用 static 修饰成员内部类,不用再创建外部类的对象了

​ 另外还可用 abstract ,final 修饰成员内部类(不常用)

8.15.4 局部内部类

8.15.4.1 概述

​ 局部内部类,定义在外部类方法中的局部位置。与访问方法中的局部变量相似,可通过调用方法进行访问

​ 在方法内,出了方法之后就不能使用

8.15.4.2 定义格式
class 外部类 { 
	修饰符 返回值类型 方法名(参数) {
		class 内部类 {
			//其他代码
		}
	}
}
8.15.4.3 访问方式

​ 在外部类方法中,创建内部类对象,进行访问

8.15.5 匿名内部类

8.15.5.1 概述和特点

​ 可以把匿名内部类看成是一个没有名字的局部内部类

​ 定义在方法当中

​ 必须在定义匿名内部类的时候创建他的对象

8.15.5.2 格式
new/接口(){
	//如果是创建了继承这个类的子类对象,我们可以重写父类的方法
    //如果是创建了实现这个接口的子类对象,我们必须要实现该接口的所有方法
};

原理:创建了继承这个类的子类对象或者是创建了实现这个接口的子类对象

8.15.5.3 应用场景

​ 作为参数进行传递,只用一次

九、 常用API

9.1 Object 类

​ 是类层次结构的根类,所有的类都直接的或者间接的继承自该类

9.1.1 toString() 方法

​ 默认打印的是当前对象的内存地址值

​ 重写后:打印的是该对象的属性值信息

9.1.2 equals() 方法

​ 默认比较的是两个对象的内存地址

​ 重写后:比较的是两个对象的属性值是否全部相同 如果是 就认为这两个对象是同一个

9.2 String 类

9.2.1 概述

​ 本质是一个字符数组,而且该字符数组是被final修饰,不可修改的,也就意味着字符串是不可变的,任何做的拼接的操作都是会产生新的字符串对象

9.2.2 构造方法

String(String original):把字符串数据封装成字符串对象

String(char[] value):把字符数组的数据封装成字符串对象

String(char[] value, int index, int count):把字符数组的一部分数据封装成字符串对象

直接赋值:String s = “hello” ; (最常用) 所有字符串字面值(“abc”),都是String 类的对象,是对象就能调用String类的方法

​ 任何类型要转换成字符串,都可以使用拼接空串("")的方式

9.2.4 成员方法

char charAt(int index):返回指定索引处的 char 值。

String concat(String str):将指定字符串连接到此字符串的结尾。

boolean contains(CharSequence s):当且仅当此字符串包含指定的 char 值序列时,返回 true。

boolean endsWith(String suffix):测试此字符串是否以指定的后缀结束。

boolean startsWith(String suffix):测试此字符串是否以指定的前缀开始。

boolean equals(Object anObject):将此字符串与指定的对象比较。

boolean equalsIgnoreCase(String anotherString):将此 String 与另一个 String 比较,不考虑大小写。

byte[] getBytes():使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。

int indexOf(int ch):返回指定字符在此字符串中第一次出现处的索引。

int indexOf(String str) :返回指定子字符串在此字符串中第一次出现处的索引。

int lastIndexOf(int ch) 返回指定字符在此字符串中最后一次出现处的索引。

int lastIndexOf(String str): 返回指定子字符串在此字符串中最右边出现处的索引。

int length() :返回此字符串的长度。

boolean matches(String regex) :告知此字符串是否匹配给定的正则表达式。

String replace(char oldChar, char newChar) :返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。

String replaceAll(String regex, String replacement): 使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。

String[] split(String regex) :根据给定正则表达式的匹配拆分此字符串。

String substring(int beginIndex) :返回一个新的字符串,它是此字符串的一个子字符串。

String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串的一个子字符串。

char[] toCharArray():将此字符串转换为一个新的字符数组。

String toLowerCase():使用默认语言环境的规则将此 String 中的所有字符都转换为小写。

String toUpperCase(): 使用默认语言环境的规则将此 String 中的所有字符都转换为大写。

String trim() :返回字符串的副本,忽略前导空白和尾部空白。

public static String valueOf(int i):返回 int 参数的字符串表示形式。

9.2.5 模拟登录练习

​ 模拟登录,给三次机会,并提示还有几次

String username = "admin";
String password = "admin";

for(int x=0; x<3; x++) {
    //键盘录入用户名和密码
    Scanner sc = new Scanner(System.in);
    System.out.println("请输入用户名:");
    String name = sc.nextLine();
    System.out.println("请输入密码:");
    String pwd = sc.nextLine();

    //拿键盘录入的用户名和密码去跟已经存在的用户名和密码进行比较
    if(username.equals(name) && password.equals(pwd)) {
        System.out.println("登录成功");
        break;
    }else {
        if((2-x) == 0){
            System.out.println("你的帐号被锁定,请与管理员联系");
        }else {
            System.out.println("登录失败,你还有"+(2-x)+"次机会");
        }
    }
}

9.3 StringBuilder 类(字符串缓冲区)

9.3.1 概述

​ 使用StringBuilder的原因:如果有很多字符串数据需要做拼接操作,那么内存中会产生很多垃圾字符串,而我们最终只是要一个结果,因此频繁的拼接字符串会让内存产生很大的开销,因此我们就可以使用java提供的可变长字符串。

9.3.2 构造方法

public StringBuilder()
public StringBuilder(String str)

9.3.3 成员方法

public String toString():返回此序列中数据的字符串表示形式。

public StringBuilder append(任意类型):添加数据,并返回对象本身。

public StringBuilder reverse():字符串本身进行反转

9.4 正则表达式(常见规则)

​ 规则字符在java.util.regex Pattern类中

9.4.1 字符

​ x 字符 x。举例:'a’表示字符a

​ \\反斜线字符。

​ \n 新行(换行)符

​ \r 回车符

9.4.2 字符类

​ [abc] a、b 或 c(简单类)

​ [^abc]任何字符,除了 a、b 或 c(否定)

​ [a-zA-Z] a到 z 或 A到 Z,两头的字母包括在内(范围)

​ [0-9] 0到9的字符都包括

9.4.3 预定义字符类

​ . 任何字符。我的就是.字符本身,怎么表示呢? .

​ \d 数字:[0-9]

​ \w 单词字符:[a-zA-Z_0-9],在正则表达式里面组成单词的东西必须有这些东西组成

9.4.4 边界匹配器

​ ^ 行的开头

​ $ 行的结尾

9.4.5 Greedy 数量词

​ X? X,零次或一次

​ X* X,零次或多次

​ X+ X,一次或多次

​ X{n} X,恰好 n 次

​ X{n,} X,至少 n 次

​ X{n,m} X,至少 n 次,但是不超过 m 次

9.4.6 应用

判断功能

public boolean matches(String regex)

分割功能

public String[] split(String regex)

替换功能

public String replaceAll(String regex,String replacement)

9.5 Arrays 工具类

9.5.1 冒泡排序

9.5.1.1 概述

​ 就是相邻的两个元素进行两两比较,把元素值大的元素依次向后排.

9.5.1.2 原理图解

[外链图片转存失败(img-GaMAt3GF-1565402562401)(E:\学习\Typora笔记图片\冒泡排序.jpg)]

9.5.1.3 代码实现
public class ArrayDemo {
	public static void main(String[] args) {
		//定义一个int类型的数组
		int[] arr = {24,69,80,57,13};
		sort(arr);				//调用sort()方法
		System.out.println("排序后:");
		printArray(arr);		//调用pritArray()方法
	}
    //冒泡排序
	public static void sort(int[] arr) {
		for(int x=0; x<arr.length-1; x++) {
			for(int y=0; y<arr.length-1-x; y++) {
				if(arr[y] > arr[y+1]) {
					int temp = arr[y];
					arr[y] = arr[y+1];
					arr[y+1] = temp;
				}
			}
		}
	}
    //遍历输出
	public static void printArray(int[] arr) {
		System.out.print("[");
		for(int x=0; x<arr.length; x++) {
			if(x==arr.length-1) {
				System.out.print(arr[x]);
			}else {
				System.out.print(arr[x]+", ");
			}
		}
		System.out.println("]");
	}
}

9.5.2 Arrays 类的概述和使用

​ Arrays类提供了对数组操作的各种方法。

public static String toString(int[] a)		//把数组转成字符串

public static void sort(int[] a)			//对数组进行升序排序,字符串数组也可以进行排序

9.5.3 Arrays 类的构造方法

​ Arrays类中有构造方法,只不过构造方法被private修饰,外界是无法使用的。

​ 因为外界无法使用,所以帮助文档中就看不到。

private Arrays() {}			//构造方法
Arrays类的这种设计是常用的工具类的设计思想:

​ 构造方法私有。

​ 成员都用static修饰。

9.6 包装类

9.6.1 概述

​ 为了对基本数据类型进行更多更方便的操作,Java就针对每一种基本数据类型提供了一个对应的引用类型。

​ 基本数据类型包装类最常见的用法就是用于和字符串之间进行相互转换。

9.6.2 基本类型包装类

基本数据类型包装类举例
byteByte10,20
shortShort10,20
intInteger10,20
longLong10L,20L
floatFloat12.3F
doubleDouble23.4D
charCharacter‘a’
booleanBooleantrue/false

9.6.3 Integer 类

9.6.3.1 概述

​ Integer类在对象中包装了一个基本类型 int 的值。

9.6.3.2 构造方法
Integer(int value) 

Integer(String s)      

​ 注意:这个字符串必须由数字字符组成

9.6.4 int – String 之间的转换

int类型和String类型的相互转换(其他基本数据类型同int)

//int	--	String
public static String valueOf(int i)		
    		//String类中的静态(参数可以是其他基本数据类型)
//String   --	int
public static int parseInt(String s)	
    		//Integer类中的静态(其他包装类中(除了Character)也有parseXXX()方法)
    		//我们无法做到将一个字符串专成一个字符

9.6.5 自动装箱和拆箱

9.6.5.1 自动装箱
public static Integer valueOf(int i)	//把基本数据类型转换为对应的包装类类型     
9.6.5.2 自动拆箱
public int intValue()	//把包装类类型转换为对应的基本数据类型
9.6.5.3 注意事项

​ 开发中的原则:只要是对象,在使用前就必须进行不为null的判断。

9.6.5.4 代码示范
public class IntegerTest3 {
	public static void main(String[] args) {
		// 自动装箱:把基本数据类型转换为对应的包装类类型
		int num = 100;
		// public static Integer valueOf(int i)
		Integer i = Integer.valueOf(num);
		// 自动拆箱:把包装类类型转换为对应的基本数据类型
		// public int intValue()
		int num2 = i.intValue();

		Integer ii = 100;// Integer ii = Integer.valueOf(100);
		//进行不为null判断
         if (ii != null) {
			ii += 100;// ii = Integer.valueOf(ii.intvalue()+100);
			System.out.println(ii);
		}
	}
}

9.7 Date 类

9.7.1 概述

​ Date表示特定的瞬间,精确到毫秒

9.7.2 构造方法

Date()					//根据当前时间创建的日期对象

Date(long date)			//根据给定的毫秒值创建对象,从1970 年 1 月 1 日 00:00:00

9.7.3 成员方法

public long getTime()  			//获取的是毫秒值。从1970年1月1日 00:00:00开始的。
    
public void setTime(long time)	//设置时间,给的是毫秒值。

9.8 SimpleDateFormat 类

9.8.1 概述

SimpleDateFormat:是一个以与语言环境有关的方式来格式化和解析日期的具体类。

9.8.2 使用

​ 它允许进行格式化(日期 -> 文本)、解析(文本 -> 日期)

格式化(日期 -> 文本): Date -- String
		public final String format(Date date)
解析(文本 -> 日期):  String -- Date
		public Date parse(String source)

9.8.3 构造方法

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")  //给定格式

9.9 System 类(了解)

9.9.1 概述

​ System 类包含一些有用的类字段和方法。它不能被实例化。

9.9.2 成员方法

static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length) :
//从src源数组的srcPos索引开始,复制length个元素;从destPost位置开始将这些元素放至到dest数组中

static long currentTimeMillis() 	  //返回以毫秒为单位的当前时间
    
static void exit(int status)		 //终止当前正在运行的 Java 虚拟机
    
static void gc() 					//运行垃圾回收器

9.10 Calendar 类(了解)

9.10.1 概述

​ Calendar是日历类,在Date后出现,替换掉了许多Date的方法。该类将所有可能用到的时间信息封装为静态成员变量,方便获取。

9.10.2 创建对象

static Calendar getInstance()    //使用默认时区和语言环境获得一个日历

Calendar c = Calendar.getInstance();		//返回当前时间

9.10.3 常用方法

void set(int field, int value) 	 	//把指定的字段修改成指定的值

void add(int field, int amount)		//在指定的字段上加上指定的值

int get(int field) // 返回给定日历字段的值

9.11 Math 类

9.11.1 常用方法

static double PI

static double abs(double a)  	//返回绝对值

static double ceil(double a) 	//向上取整

static double floor(double a)   //向下取整

static long round(double a) 	//四舍五入

static double max(double a, double b)
    
static double random() 			//返回一个随机数,大于零且小于一

十、 集合

10.1 概述

​ 集合是一个容器,是用来存储和获取数据的。长度可变。

10.3 Collection 集合

10.3.1 概述

​ Collection 是单列集合的顶层接口。

​ Collection 表示一组对象,这些对象也称为 collection 的元素。

​ 一些 collection 允许有重复的元素,而另一些则不允许。

​ 一些 collection 是有序的,而另一些则是无序的。

​ JDK 不提供此接口的任何直接

10.3.2 成员方法

boolean add(E e)		//添加元素

boolean remove(Object o)	//从集合中移除元素

void clear()	//清空集合中的元素

boolean contains(Object o)	//判断集合中是否存在指定的元素

boolean isEmpty()	//判断集合是否为空

int size()	//集合的长度,也就是集合中元素的个数

10.3.3 迭代器遍历 Iterator

10.3.3.1 使用
Iterator<E> iterator()		//返回在此 collection 的元素上进行迭代的迭代器。   
						  //通过集合对象调用iterator()方法得到迭代器对象
10.3.3.2 成员方法
E next()				//返回迭代的下一个元素。
boolean hasNext()		//如果仍有元素可以迭代,则返回 true。
10.3.3.3 存储自定义对象并遍历
public class CollectionTest {
	public static void main(String[] args) {
		//创建集合对象
		Collection<Student> c = new ArrayList<Student>();
		//创建元素对象
		Student s1 = new Student("林青霞",30);
		Student s2 = new Student("张曼玉",35);
		Student s3 = new Student("王祖贤",33);		
		//把元素添加到集合
		c.add(s1);
		c.add(s2);
		c.add(s3);		
		//遍历集合
		Iterator<Student> it = c.iterator();
		while(it.hasNext()){
			Student s = it.next();
			System.out.println(s.getName()+"---"+s.getAge());
		}
	}
}

10.4 List 集合

10.4.1 概述

​ 有序的 collection(也称为序列)。

​ 此接口的用户可以对列表中每个元素的插入位置进行精确地控制。

​ 用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。

10.4.2 特点

  1. 有序(存储和取出元素的顺序一致)
  2. 存储的元素可以重复

10.4.3 特有成员方法

void add(int index,E element):在指定位置添加元素

E remove(int index):删除指定位置的元素,返回删除的元素值

boolean removeAll(Collection<?> c):移除此 collection 中那些也包含在指定 collection 中的所有元素(可选操作)

E get(int index):获取指定位置的元素

E set(int index,E element):修改指定位置的元素,返回原参数值

10.4.4 列表迭代器(ListIterator)

10.4.4.1 概述

ListIterator listIterator():返回此列表元素的列表迭代器

public interface ListIterator extends Iterator

10.4.4.2 特有功能
E previous():返回列表中的前一个元素。

boolean hasPrevious():如果以逆向遍历列表,列表迭代器有多个元素,则返回 true

注意:ListIterator可以实现逆向遍历,但是要求先正向遍历,才能逆向遍历。(没啥用)

10.4.5 ConcurrentModificationException(修改并发异常)

10.4.5.1 产生原因

​ 迭代器依赖于集合而存在,在判断成功后,集合中添加了新的元素,而迭代器并不知道,所有就报错了。

​ 其实这个问题说的是:迭代器遍历集合中的元素的时候,不要使用集合对象去修改集合中的元素。

10.4.5.2 解决方案

1.迭代器遍历的时候,我可以通过列表迭代器修改集合中的元素

​ 元素是跟在刚才迭代的元素后面的

ListIterator<String> lit = list.listIterator();
while(lit.hasNext()) {
	String s = lit.next();
	if(s.equals("world")) {
		lit.add("javaee");
	}
}

2.集合遍历的时候,我可以通过集合对象修改集合中的元素

​ 元素是在最后添加的

for(int x=0; x<list.size(); x++) {
	String s = list.get(x);
	if(s.equals("world")) {
		list.add("javaee");
	}
}

10.5 ArrayList 集合

10.5.1 List 集合子类特点

​ ArrayList:底层数据结构是数组,查询快,增删慢

​ LinkedList:底层数据结构是链表,查询慢,增删快

10.5.2 ArrayList 集合遍历

10.5.2.1 普通 for 循环
for(int x=0; x<array.size(); x++) {
	String s = array.get(x);
	System.out.println(s);
}
10.5.2.2 增强 for 循环
for(String s : array) {				//for ( 容器中元素的数据类型 变量名 : 容器)
	System.out.println(s);
}
10.5.2.3 迭代器循环
Iterator<String> it = array.iterator();
while(it.hasNext()){
	String s = it.next();
	System.out.println(s);
}

10.6 LinkedList 集合(了解)

10.6.1 特有功能

public void addFirst(E e):将指定元素插入此列表的开头

public void addLast(E e):将指定元素添加到此列表的结尾

public E getFirst():返回此列表的第一个元素

public E getLast():返回此列表的最后一个元素

public E removeFirst():移除并返回此列表的第一个元素

public E removeLast():移除并返回此列表的最后一个元素

10.7 Set 集合

10.7.1 Set 集合的特点

​ 元素唯一,存储元素无序,一个不包含重复元素的 collection

10.7.2 HashSet 集合类

​ 它不保证 set 的迭代顺序;特别是它不保证该顺序恒久不变

public class SetDemo {
	public static void main(String[] args) {
		//创建集合对象
		Set<String> set = new HashSet<String>();
		//添加元素
		set.add("hello");
		set.add("world");
		set.add("java");
		//唯一
		set.add("world");	
		//遍历集合
		for(String s : set) {
			System.out.println(s);
		}	
	}
}

10.7.3 HashSet 保证元素唯一性的原理

​ 通过查看add方法的源码,我们知道了添加功能的执行过程中,是进行了数据的判断的。

​ 这个判断的流程是:

​ 首先比较对象的哈希值是否相同,这个哈希值是根据对象的hashCode()计算出来的。

​ 如果哈希值不同,就直接添加到集合中

​ 如果哈希值相同,继续执行equals()进行比较,

​ 返回的是true,说明元素重复,不添加。

​ 返回的是false,说明元素不重复,就添加。

​ 如果我们使用HashSet集合存储对象,你要想保证元素的唯一性,就必须重写hashCode()和equals()方法

public class Student {
	private String name;
	private int age;
	public Student() {
	}
	public Student(String name, int age) {
		this.name = name;
		this.age = age;
	}
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		this.age = age;
	}
	//重写hashCode()方法
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + age;
		result = prime * result + ((name == null) ? 0 : name.hashCode());
		return result;
	}
	//重写equals()方法
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Student other = (Student) obj;
		if (age != other.age)
			return false;
		if (name == null) {
			if (other.name != null)
				return false;
		} else if (!name.equals(other.name))
			return false;
		return true;
	}
}

10.7.4 TreeSet(了解)

11.7.4.1 概念

​ 底层是二叉树结构,根节点、左子树、右子树

11.7.4.2 存储规则

​ 使用要存入的元素,减去集合中已有的元素

​ 如果是正数,就放在集合中元素的右边

​ 如果是负数,就放在集合中元素的左边

​ 如果是零,就不会存储

11.7.4.3 取

​ 左中右

10.7.5 LinkedHashSet

  1. ​ 保证元素唯一
    . 保证怎么存就怎么取
//List进行去重,顺序没变
//创建LinkedHashSet
LinkedHashSet<Integer> set = new LinkedHashSet<>();
//将list集合中的所有元素都添加到set中
set.addAll(list);
// 清空list集合
list.clear();
//将set集合中的所有元素添加到list集合中
list.addAll(set);

总结:Set 集合相关操作均可由 Arraylist 集合完成

10.8 Map 集合

10.8.1 概述

​ 将键映射到值的对象(键值对)。一个映射不能包含重复的键;每个键最多只能映射到一个值。

10.8.2 创建 Map 集合对象

public class MapDemo {
	public static void main(String[] args) {
		//创建集合对象
		Map<String,String> map = new HashMap<String,String>();	
		//添加元素
		//put(K key,V value):添加元素。
		map.put("it001", "林青霞");
		map.put("it002", "张曼玉");
		map.put("it003", "王祖贤");	
		//输出集合对象
		System.out.println(map);
	}
}

10.8.3 成员方法

V put(K key,V value):添加元素

V remove(Object key):根据键删除键值对元素

void clear():移除所有的键值对元素

boolean containsKey(Object key):判断集合是否包含指定的键

boolean containsValue(Object value):判断集合是否包含指定的值

boolean isEmpty():判断集合是否为空

int size():返回集合中的键值对的对数

10.8.4 获取功能

V get(Object key):根据键获取值

Set<K> keySet():获取所有键的集合

Collection<V> values():获取所有值的集合

10.8.5 Map 集合的遍历

10.8.5.1 键找值
//获取所有键的集合
Set<String> set = map.keySet();
//遍历键的集合,获取到每一个键
for(String key : set) {
	//根据键去找值
	String value = map.get(key);
	System.out.println(key+"---"+value);
}
10.8.5.2 键值对对象找键和值
Set<Map.Entry<K,V>> entrySet()		//获取所有键值对对象的集合
//获取键值对对象的集合
Set<Map.Entry<String,String>> set = map.entrySet();
//遍历键值对对象的集合,得到每一个键值对对象
for(Map.Entry<String,String> me : set) {
	//根据键值对对象获取键和值
	String key = me.getKey();
	String value = me.getValue();
	System.out.println(key+"---"+value);
}

10.8.5.3 遍历方式图解

[外链图片转存失败(img-OBUpun8i-1565402562405)(E:\学习\Typora笔记图片\Map遍历图解.jpg)]

10.8.6 Map 集合体系结构

[外链图片转存失败(img-WTcJPHoS-1565402562406)(E:\学习\Typora笔记图片\Map集合的体系.png)]

treemap 可以排序(根据键)

hashtable 不咋用了

properties NB!!!属性文件

Properties p = new Properties();
p.load("XXX.properties");
Object obj = p.getProperties(String str);

10.9 Collections 工具类

static void swap(List list, int i, int j):将指定列表中的两个索引进行位置互换

static void sort(List<T> list):按照列表中元素的自然顺序进行排序

static void shuffle(List list):(傻否)随机置换,打乱顺序

static void reverse(List list):反转

static void fill(List list, Object obj):使用指定的对象填充指定列表的所有元素

static void copy(List dest, List src):是把源列表中的数据覆盖到目标列表
									//注意:目标列表的长度至少等于原列表的长度
static int  binarySearch(List list, Object key):使用二分查找法查找指定元素在指定列表的索引位置

十一、 IO流

IO :可以完成数据的传输

11.1 异常

11.1.1 概念

​ 异常:就是程序出现了不正常的情况。

​ 例如:ArithmeticException:当出现异常的运算条件时,抛出此异常。例如,一个整数“除以零”时,抛出此类的一个实例。

产生原因:

throw new ArithmeticException();

11.1.2 异常体系

​ Throwable 类是 Java 语言中所有错误或异常的超类。

​ Error 是 Throwable 的子类,用于指示合理的应用程序不应该试图捕获的严重问题。也就是说针对程序发生了Error的情况,Java程序本身是无能为力的,比如说:硬件层面的问题,内存不足等。所以,针对Error的问题我们不处理。

​ Exception 类及其子类是 Throwable 的一种形式,它指出了合理的应用程序想要捕获的条件。 也就是说针对程序发生了Exception的情况,是我们需要处理的问题。

​ Exception的分类:

​ 运行期的异常(RunTimeException):在编译期是不处理的,在程序运行时候出现了问题,需要我们回来修改代码。

​ 编译期的异常(非RunTimeException):在编译期就必须处理,否则程序不能通过编译,就更不能正常的执行了。

11.1.3 JVM默认处理方式

​ 处理方案:

​ A:把异常的名称,异常的原因,异常出现的位置等信息在控制台输出

​ B:让程序停止执行

11.1.4 try…catch 异常处理

11.1.4.1 格式
try {
  	可能出现异常的代码;
}catch(异常类名  变量名) {				//一个赋值的过程:NullPointException e = new NullPointException();
  	异常的处理代码;
}
11.1.4.2 处理异常
public void printStackTrace():把异常的错误信息输出在了控制台。
11.1.4.3 try…catch 与默认差别

​ 首先要明确try…catch处理方式的特点,产生了问题,是自己将问题处理掉,不影响后续代码的运行。

​ JVM默认处理方式是将程序终止,,并将异常信息打印在控制台。

11.1.5 编译、运行时异常

Java中的异常被分为两大类:编译时异常和运行时异常。所有的RuntimeException类及其子类的实例被称为运行时异常,其他的异常都是编译时异常

  • ​ 编译时异常:Java程序必须显示处理,否则程序就会发生错误的一个提示,无法通过编译,编译时就有异常报出来,共同特点:Unhandled Exception

  • ​ 运行时异常:Java程序无需显示处理,也可以和编译时异常一样处理。运行时异常都是程序员犯的一些错误,建议修改代码

11.1.6 throws 异常处理

throws 异常类名		//这个格式必须跟在方法的括号的后面

​ 编译时异常时必须要进行处理的,两种处理方案:try…catch…或者throws

​ 如果你采用了throws这种方案,将来谁调用,还得进行处理。

运行时异常可以不用处理,出现问题后我们需要回来修改代码。

11.1.7 多异常处理

​ 对代码进行异常检测,并对检测的异常传递给catch处理。对每种异常信息进行不同的捕获处理。

try{
	throw new Exception();//产生异常,直接捕获处理
	}catch(XxxException e){
//处理方式	
	}catch(YyyException e){
//处理方式	
	}catch(ZzzException e){
//处理方式	
	}

注意:这种异常处理方式,要求多个catch中的异常不能相同,并且若catch中的多个异常之间有子父类异常的关系,那么子类异常要求在上面的catch处理,父类异常在下面的catch处理。

11.1.8 try…catch…finally

//boolean b = true;			
//if(b) {
//    return;
//}
//若不想执行下面的代码,可用上述 if 语句实现

try {
    System.out.println(10 / 0);
}catch(Exception e) {
    System.out.println("执行了catch");
    return;	//除了关闭虚拟机 System.exit(0); ,剩下的都会执行finally后边的语句
}finally {
    System.out.println("finally执行了!");		//依然会执行
}

11.1.8 自定义异常(了解)

​ throws:处理异常的一种方式,把异常抛出,由调用者来处理

​ throw:制造异常的方式,并且结束方法

​ 注意:如果抛出(throw)的是编译时期异常,必须在方法声明处抛出(throws)

​ 如何自定义一个异常类呢?

​ 非常简单,写一个类去继承Exception或者RuntimeException,然后实现多个构造即可

public class ExceptionDemo7 {
	public static void main(String[] args) {
		try {
			checkScore(110);
		} catch (Exception e) {
			//System.out.println(e.getMessage());
			e.printStackTrace();
		}
	}

	public static void checkScore(int score) throws Exception {
		if(score < 0 || score > 100) {
			throw new RuntimeException("考试成绩不符合要求");
			//throw new Exception("考试成绩不符合要求");
		} 
		System.out.println("考试成绩符合要求");
	}	
}

11.1.9 Throwable

11.1.9.1 常用方法

String getMessage():原因

String toString():类型和原因
    
void printStackTrace():类型原因和位置

11.2 File 类

11.2.1 概述

​ 文件和目录路径名的抽象表示形式,也就是说文件和目录是可以通过File封装成对象的

11.2.2 构造方法

File(String pathname):通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。

File(String parent, String child):根据 parent 路径名字符串和 child 路径名字符串创建一个新 File 实例。

File(File parent, String child):根据 parent 抽象路径名和 child 路径名字符串创建一个新 File 实例

11.2.3 创建方法

public boolean createNewFile():创建文件
 	如果文件不存在,创建文件并返回true
 	如果文件存在,创建文件失败并返回false
  
public boolean mkdir():创建目录
	如果目录不存在,创建目录并返回true
 	如果目录存在,创建目录失败并返回false
 
public boolean mkdirs():创建多级目录

11.2.4 路径

​ 绝对路径:是以盘符开始的路径。

​ 相对路径:不以盘符开始。相对于当前的项目而言,在项目的目录下。

11.2.5 删除功能

public boolean delete():删除文件和目录

​ 如果一个目录中有内容(目录,文件),就不能直接删除。应该先删除目录中的内容,最后才能删除目录。删除的内容不走回收站。

11.2.6 判断功能

public boolean isDirectory():判断是否是目录

public boolean isFile():判断是否是文件

public boolean exists():判断是否存在

11.2.7 获取功能

public String getAbsolutePath():获取绝对路径

public String getPath():获取路径(根据构造时传入的路径返回)

public String getName():获取路径中最后一个代表的文件(文件夹)的名称

11.3 IO 流的分类

​ 按照类型分:

​ 字节流

​ 字符流 (字符流数据通过Windows自带的记事本软件打开是可以读懂里面内容的)

​ 按照流向分:

​ 输入流:用来读取数据的:

​ 输出流:用来写出数据的

11.4 字节流&字符流的抽象父类

字节流:

​ InputStream 字节输入流

​ OutputStream 字节输出流

字符流:

​ Reader 字符输入流

​ Writer 字符输出流

11.5 字节流

11.5.1 FileOutputStream 写数据

11.5.1.1 概述

​ OutputStream:此抽象类是表示输出字节流的所有类的超类

​ FileOutputStream:文件输出流是用于将数据写入File

11.5.1.2 构造方法
FileOutputStream(String name):创建一个向具有指定名称的文件中写入数据的输出文件流。
11.5.1.3 写数据的方式
public void write(int b):一次写一个字节

public void write(byte[] b):一次写一个字节数组

public void write(byte[] b,int off,int len):一次写一个字节数组的一部分

byte[] getBytes():将字符串转换为字节数组
11.5.1.4 案例代码
public class FileOutputStreamDemo2 {
	public static void main(String[] args) throws IOException {
		//创建字节输出流对象
		//FileOutputStream(String name) 
		FileOutputStream fos = new FileOutputStream("b.txt");
		//new File(name)
//		FileOutputStream fos = new FileOutputStream(new File("b.txt"));
		
		//FileOutputStream(File file) 
//		File file = new File("b.txt");
//		FileOutputStream fos = new FileOutputStream(file);
//		FileOutputStream fos = new FileOutputStream(new File("b.txt"));
		
		//public void write(int b):一次写一个字节
//		fos.write(65);
		
		//public void write(byte[] b):一次写一个字节数组
//		byte[] bys = {65,66,67,68,69};
//		fos.write(bys);
		//需求:我如果是一个字符串的数据,能写吗?
		//String -- byte[]
		//String类中有一个方法:public byte[] getBytes()
//		byte[] bys = "ABCDE".getBytes();
//		fos.write(bys);
//		fos.write("ABCDE".getBytes());		
		//public void write(byte[] b,int off,int len):一次写一个字节数组的一部分
		fos.write("ABCDE".getBytes(),0,3);		
		//释放资源
		fos.close();
	}
}
11.5.1.5 换行和追加写数据

不同的操作系统,针对换行的符号识别是不一样的。

  1. windows:\r\n
  2. linux:\n
  3. mac:\r
fow.write("\r\n".getBytes())

数据的追加写入:

​ 用构造方法带第二个参数是true的情况即可

FileOutputStream(String name,true)
11.5.1.6 加入异常处理

​ try{

​ 可能发生问题的代码

​ }catch(){

​ 处理异常代码

​ }finally{

​ 一定会被执行的代码. (通常用于释放资源, 做善后的动作)

​ }

public class FileOutputStreamDemo4 {
	public static void main(String[] args) {
		FileOutputStream fos = null;
		try{
			//FileOutputStream fos = new FileOutputStream("d.txt");
//			fos = new FileOutputStream("z:\\d.txt");
			fos = new FileOutputStream("d.txt");
			fos.write("hello".getBytes());
		}catch(IOException e) {
			e.printStackTrace();
		}finally {
			if(fos!=null) {
				//释放资源
				try {
					fos.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
		}
	}
}
11.5.1.7 自动关流
try (FileOutputStream fos = new FileOutputStream(("aaa.txt"),true) {
    fos.write(100);
}

11.5.2 FileInputStream 读数据

​ 输入流在创建的时候,如果关联的文件不存在,会报出异常

11.5.2.1 一次读取一个字节
public class FileInputStreamDemo {
	public static void main(String[] args) throws IOException {
		//创建字节输入流对象
		FileInputStream fis = new FileInputStream("a.txt");
		int by;
		// 用by不断的记录读取到的每一个数据
		while((by=fis.read())!=-1) {
			System.out.print((char)by);
		}
		//释放资源
		fis.close();
	}
}
11.5.2.2 一次读取一个字节数组
public class FileInputStreamDemo2 {
	public static void main(String[] args) throws IOException {
		//创建字节输入流对象
		FileInputStream fis = new FileInputStream("b.txt");
		byte[] bys = new byte[1024]; //1024或者1024的整数倍
		int len;
		//将数据读取到数组中, 并用len记录读取到的有效字节个数
		while((len=fis.read(bys))!=-1) {
			System.out.print(new String(bys,0,len));
		}
		//释放资源
		fis.close();
	}
}

11.5.3 字节缓冲流

11.5.3.1 概述

​ BufferedOutputStream:字节缓冲输出流

​ BufferedInputStream:字节缓冲输入流

​ 字节缓冲区流仅仅提供缓冲区,而真正的底层的读写数据还得需要基本的流对象进行操作。

11.5.3.2 案例代码
public class BufferedStreamDemo {
	public static void main(String[] args) throws IOException {
		// BufferedOutputStream(OutputStream out)
		// FileOutputStream fos = new FileOutputStream("a.txt");
		// BufferedOutputStream bos = new BufferedOutputStream(fos);
		// 上面的两句等价于下面的这一句
		// BufferedOutputStream bos = new BufferedOutputStream(new
		// FileOutputStream("a.txt"));
		// bos.write("hello".getBytes());
		// bos.close();

		// BufferedInputStream(InputStream in)
		BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
		//方式1:一次读取一个字节
		int by;
		while((by=bis.read())!=-1) {
			System.out.print((char)by);
		}
		
		//方式2:一次读取一个字节数组
		byte[] bys = new byte[1024];
		int len;
		while((len=bis.read(bys))!=-1) {
			System.out.print(new String(bys,0,len));
		}
		
		bis.close();
	}
}

11.6 转换流(字符流)

11.6.1 字节流的问题

​ 字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。

​ 文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。

汉字存储的规则:

​ 左边的字节数据肯定是负数,右边的字节数据可能是负数,也可能是正数,大部分情况下是负数。

11.6.2 转换流的组成部分

​ 转换流 = 字节流 + 编码表

11.6.3 编码表

11.6.3.1 常见编码表

ASCII :美国标准信息交换码, 用一个字节的7位表示数据

ISO-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII

GB2312 : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ASCII

UTF-8 : 是一种可变长度的字符编码, 用1-3个字节表示数据, 又称为万国码, 兼容ASCII,用在网页上可以统一页面中的中文简体繁体和其他语言的显示

11.6.3.2 编码和解码(String)
//编码
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException	

//解码
public String(byte[] bytes, String charsetName)

11.6.4 构造方法

11.6.4.1 字符输出流

  public OutputStreamWriter(OutputStream out)
  		根据默认编码把字节流的数据转换为字符流
  public OutputStreamWriter(OutputStream out,String charsetName)
  		根据指定编码把字节流数据转换为字符流
  
11.6.4.2 字符输入流
public InputStreamReader(InputStream in):用默认的编码读数据

11.6.5 OutputStreamWriter 写数据

public void write(int c):写一个字符

public void write(char[] cbuf):写一个字符数组

public void write(char[] cbuf,int off,int len):写一个字符数组的一部分

public void write(String str):写一个字符串

public void write(String str,int off,int len):写一个字符串的一部分

11.6.6 InpurStreamReader 读数据

public int read():一次读取一个字符

public int read(char[] cbuf):一次读取一个字符数组

11.6.7 字符流改进

​ 转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类。

字符流子类
OutputStreamWriterFileWriter
InputStreamReaderFileReader

11.6.8 字符缓冲区流

11.6.8.1 BufferedWriter

​ 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

​ 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。

构造方法:

BufferedWriter(Writer out)
11.6.8.2 BufferedReader

​ 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

​ 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

构造方法:

BufferedReader(Reader in)
11.6.8.3 特殊功能
BufferedWriter
void newLine()//写入一个行分隔符,这个行分隔符是由系统决定的
BufferedReader
String readLine()//包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null
	BufferedInputStream bis = new BufferedInputStream(new FileInputStream("a.txt"));
	//方式1:一次读取一个字节
	int by;
	while((by=bis.read())!=-1) {
		System.out.print((char)by);
	}
	
	//方式2:一次读取一个字节数组
	byte[] bys = new byte[1024];
	int len;
	while((len=bis.read(bys))!=-1) {
		System.out.print(new String(bys,0,len));
	}
	
	bis.close();

11.6 转换流(字符流)

11.6.1 字节流的问题

​ 字节流一次读取一个字节的方式读取带有汉字的文件是有问题的,因为你读取到一个字节后就转为字符在控制台输出了,而汉字是由2个字节组成的,所以这里会出问题。

​ 文件复制的时候,字节流读取一个字节,写入一个字节,这个没有出现问题,是因为最终底层会根据字节做拼接,得到汉字。

汉字存储的规则:

​ 左边的字节数据肯定是负数,右边的字节数据可能是负数,也可能是正数,大部分情况下是负数。

11.6.2 转换流的组成部分

​ 转换流 = 字节流 + 编码表

11.6.3 编码表

11.6.3.1 常见编码表

ASCII :美国标准信息交换码, 用一个字节的7位表示数据

ISO-8859-1 : 欧洲码表, 用一个字节的8位表示数据, 兼容ASCII

GB2312 : 中文码表的升级版, 融合了更多的中文文字符号, 兼容ASCII

UTF-8 : 是一种可变长度的字符编码, 用1-3个字节表示数据, 又称为万国码, 兼容ASCII,用在网页上可以统一页面中的中文简体繁体和其他语言的显示

11.6.3.2 编码和解码(String)
//编码
public byte[] getBytes(String charsetName) throws UnsupportedEncodingException	

//解码
public String(byte[] bytes, String charsetName)

11.6.4 构造方法

11.6.4.1 字符输出流

  public OutputStreamWriter(OutputStream out)
  		根据默认编码把字节流的数据转换为字符流
  public OutputStreamWriter(OutputStream out,String charsetName)
  		根据指定编码把字节流数据转换为字符流
  
11.6.4.2 字符输入流
public InputStreamReader(InputStream in):用默认的编码读数据

11.6.5 OutputStreamWriter 写数据

public void write(int c):写一个字符

public void write(char[] cbuf):写一个字符数组

public void write(char[] cbuf,int off,int len):写一个字符数组的一部分

public void write(String str):写一个字符串

public void write(String str,int off,int len):写一个字符串的一部分

11.6.6 InpurStreamReader 读数据

public int read():一次读取一个字符

public int read(char[] cbuf):一次读取一个字符数组

11.6.7 字符流改进

​ 转换流的名字比较长,而我们常见的操作都是按照本地默认编码实现的,所以,为了简化我们的书写,转换流提供了对应的子类。

字符流子类
OutputStreamWriterFileWriter
InputStreamReaderFileReader

11.6.8 字符缓冲区流

11.6.8.1 BufferedWriter

​ 将文本写入字符输出流,缓冲各个字符,从而提供单个字符、数组和字符串的高效写入。

​ 可以指定缓冲区的大小,或者接受默认的大小。在大多数情况下,默认值就足够大了。

构造方法:

BufferedWriter(Writer out)
11.6.8.2 BufferedReader

​ 从字符输入流中读取文本,缓冲各个字符,从而实现字符、数组和行的高效读取。

​ 可以指定缓冲区的大小,或者可使用默认的大小。大多数情况下,默认值就足够大了。

构造方法:

BufferedReader(Reader in)
11.6.8.3 特殊功能
BufferedWriter
void newLine()//写入一个行分隔符,这个行分隔符是由系统决定的
BufferedReader
String readLine()//包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回null
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值