Java基础

Java基础

第1章Java语言概述

1.1 基础常识

软件:应用软件和系统软件
和用户的交互方式:图形化界面 vs 命令行

计算机硬件介绍:
计算机硬件介绍:

Dos命令:
在这里插入图片描述

1.2 Java语言版本迭代概述

Sun公司1995年发布了Jdk1.0

Jdk1.5以后更命为5.0
JavaSE : 核心类库 + 图形化界面开发的API
JavaEE : 企业级开发(后台开发)
JavaME:手机开发,但是已经被Android所替代
JavaCard :一些小内存的设备上使用

1.3 Java语言应用的领域

大数据,后台开发,Android , 智能家电,车载应用

1.4 Java语言的特点

面向对象:封装性,继承性,多态性
健壮性 : ①去掉了C和c++的指针 ②增加了垃圾回收机制(GC)
跨平台性:一次编译到处运行。依赖于JVM

1.5 开发环境的搭建

1.5.1 JDK、JRE、JVM的关系

在这里插入图片描述

1.5.2 JDK的下载、安装

在这里插入图片描述

1.5.3 环境变量的配置

为什么要配置环境变量?

为了在任何目录下都可以访问得到Java开发工具集

如何配置?
在这里插入图片描述

1.6 开发体验——HelloWorld

1.6.1编写

创建一个以.java结尾的文件,该文件叫做源文件

1.6.2编译:

(Javac 源文件名.java ) 进行编译可以生成一个或多个字节码文件。

1.6.3 运行:

(Java 字节码文件名 ) 运行该程序

1.7 常见问题的解决

在这里插入图片描述

1.8 注释

单行注释: //
多行注释: /* /
文档注释:/
* */ (java特有的)

注意:
①多行注释不能嵌套使用
②不会将注释编译到字节码文件中
说明:
①用来对方法类,或者某些语句进行说明。
②可以用来调试代码。
③文档注释可以被javadoc所解析生成文档说明

1.9总结第一个程序

①.一个源文件中可以有多个类,多个类的类名不能相同,只能有一个类被public所修饰且类名和源文件名需要保持一致。
②.java严格区分大小写。
③.每行代码写完以后要以";"结尾。
④.以.java结尾的文件叫做源文件。以.class结尾的文件叫做字节码文件。

1.10Java API 文档(Application Programming Interface)

类似于新华字典。Orcal公司编写的一套关于java的说明文档

1.11良好的编程风格

在这里插入图片描述

第2章基本语法上(变量与运算符)

2.1关键字与标识符

2.1.1 java关键字的使用

关键字:
定义:被java赋予了特殊的含义的字符串(单词)
特点:所有字母全部是小写

2.1.2 保留字

Java现版本暂未使用,将来的版本中可能会作为关键字使用

2.1.3 标识符的使用

标识符:凡是需要自己命名的地方都叫做标识符

2.1.4 标识符的规则与规范

定义合法标识符规则:
由26个英文字母大小写,0-9 ,_或 $ 组成
数字不可以开头。
不可以使用关键字和保留字,但能包含关键字和保留字。
Java中严格区分大小写,长度无限制。
标识符不能包含空格。

Java中的名称命名规范:
包名:多单词组成时所有字母都小写:xxxyyyzzz
类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyZzz
变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz
常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ

注意:要做到见名知义

2.2 变量的使用

2.2.1按数据类型分类

基本数据类型 vs 引用数据类型(接口,类,数组)

基本数据类型:
byte(1字节 1字节 = 8位 -128 ~ 127)
short(2字节)
int(4字节)
long(8字节)
float(4字节)
double(8字节)
char(2字节)
boolean

2.2.2定义变量的格式:

格式: 变量的类型 变量名 = 变量值;

例:

int a = 10;

int b;
b = 10;

int aa,bb,cc;
aa = bb = cc = 10;

2.2.3变量使用的注意点:

1.变量应该先声明再使用
2.同一作用域内的变量名不能相同
3.变量的作用域就是在声明它的那对大括号内

2.3变量间的运算

2.3.1基本数据类型间运算

一 基本数据类型之间的运算(7种 不包括(boolean))

1.自动类型提升:
小容量的变量和大容量的变量做运算结果用大容量的类型来接收。
byte,short,char -> int -> long -> float -> double

2.强制类型转换:自动类型提升的逆过程
注意:容量指的是变量的值的范围

2.3.2 String与基本数据类型(8种)间运算

字符串的赋值方式:

String s = “xiaoloongge”;
String str = new String(“xiaoloongge”);

说明:
1.String与基本数据类型只能做连接运算
2.String与基本数据类型运算结果还是String

2.4运算符

2.4.1算术运算符:

+(正) -(负) + - * / % 前++ 后++ 前-- 后-- +(连接符)

代码:

		int n = -5;
		System.out.println(n);
		//除法
		int a = 12;
		int b = 5;
		int c = a / b; //2

		//需求 :得到浮点数
		double d = a / b; //2.0
		d = a / (b + 0.0); //2.4
		d = (a + 0.0) / b; // 2.4
		d = a * 1.0 / b; //2.4
		d = 12 / 5  * 5; //10.0

		int dd = 12  * 5 / 5; //12  建议:再做算术运算的时候如果即有乘法又有除法,建议先做乘法运算

		System.out.println(dd);

		//取模 用法:1.判断是否可以整除
		System.out.println(1 % 2);
		System.out.println(2 % 2);
		System.out.println(3 % 2);
		System.out.println(4 % 2);
		System.out.println(5 % 2);
		System.out.println(6 % 2);
		System.out.println(7 % 2);
		System.out.println(8 % 2);
		System.out.println(9 % 2);

		System.out.println("-------------------------");
		//取模结果的正负和被模数有关,被模数是正的结果就是正的,反之就是负的。
		System.out.println(-1 % 2); // -1
		System.out.println( 1 % -2); // 1
		System.out.println( -1 % -2); // -1


		System.out.println("--------------------------");

		//后++  先赋值再自身加1
		int aa = 10;
		int bb = aa++;
		System.out.println("aa=" + aa + "  bb=" + bb); //aa=11  bb=10
		//前++ 先自身加1再赋值
		int aa2 = 10;
		int bb2 = ++aa2;
		System.out.println("aa2=" + aa2 + "  bb2=" + bb2); //aa2=11  bb2=11

		//后-- 先赋值再自身减1
		int aa3 = 10;
		int bb3 = aa3--;
		System.out.println("aa3=" + aa3 + "  bb3=" + bb3); //aa3=9  bb3=10
		
		//前-- 先自身减1再赋值
		int aa4 = 10;
		int bb4 = --aa4;
		System.out.println("aa4=" + aa4 + "  bb4=" + bb4); //aa4=9  bb4=9

		System.out.println("-----------------------------");

		int number1 = 12;
		int number2 = 5;
		double dou = number1 / (double)number2;
		System.out.println(dou);

2.4.2赋值运算符:

在这里插入图片描述

赋值运算符: = +=, -=, *=, /=, %=

在这里插入图片描述

①编译不通过,因为short进行运算时会先提升为int类型
②编译通过,不会改变原来的数据类型。

注意:
赋值运算有强制转换功能,可以避免类型提升.会有溢出风险
如:

byte a = 127;
a += 1; //相当于a = (byte)(a + 1)
System.out.println(a);//a = -128

2.4.3比较运算符:

特点:结果为boolean类型

2.4.4逻辑运算符:

在这里插入图片描述
特点:
1.逻辑运算符 运算的是boolean类型
2.逻辑运算符的结果为boolean类型
总结:
&&和& :符号两边的表达式的结果都为true的时候运算符结果为true
|和|| : 符号两边的表达式的结果都为false的时候运算符结果为false
! : 取反
^ : 相同为假,不同为真。
[面试题] & 和 && 的区别?| 和 ||的区别?
& 和 &&的区别? – 两边都为true结果才为true(左边为false结果一定为false)

左边的式子的结果为true & 和 && 右边的式子都会执行。
左边的式子的结果为false
& 右边的式子仍然会执行
&& 右边的式子不再执行
| 和 || 的区别? – 两边都为false结果才为false(左边为true结果一定为true)
左边的式子的结果为false | 和 || 右边的式子都会执行。
左边的式子的结果为true
| 右边的式子仍然会执行
|| 右边的式子不再执行

2.4.5位运算符:

<< : 左移 : 在一定范围内每向左移一位原来的数乘以2
>> : 右移 : 在一定范围内每向右移一位原来的数除以2
>>> : 无符号右移

>>和>>>的区别?
>> 如果是正数最高位用0补,如果是负数最高位用1补
>>> 无论是正数还是负数最高位都用0补

2.4.6三元运算符:

格式 : (条件表达式)?表达式1 :表达式2;
说明 :
1.条件表达式的结果只能为boolean。如果条件表达式结果为true那么结果为表达式1,反之结果为表达式2.
2.三元运算符可以嵌套使用但是不建议
3.表达式1和表达式2的类型必须一致 (如果可以自动类型提升那么就可以)
不行的案例 : 表达式1为int 表达式2为String
可行的案例 : 表达式1为int 表达式2为double 结果用double接收
4.三元运算符一定可以使用if-else来替换,反之不成立。两者都可以的时候建议使用三元运算符,因为三元运算符的效率略高一些。
代码:

//需求:求两个变量的最大值
int m = 10;
int n = 10;
int maxNumber = (m > n) ? m : n;

String str = (m > n) ? "m" : "n"; //条件不满足是  m 小于等于 n 结果都为false

System.out.println("maxNumber = " + maxNumber);
System.out.println("str = " + str);

//需求:求三个数的最大值
int a = 10;
int b = 20;
int c = 30;

//int max = (a > b)? a : b;
//max = (max > c)? max : c;

第3章基本语法下

3.1分支结构

3.1.1 if-else结构

格式1:
if(条件表达式){
执行语句;
}

格式2:二选一
if(条件表达式){
执行语句1;
}else{
执行语句2;
}

格式3:多选一
if(条件表达式1){
执行语句1;
}else if(条件表达式2){
执行语句2;
}

else{
执行语句n;
}

说明:
1.条件表达式的结果必须为boolean
2.else可以省略
3.如果执行语句只能一行代码,则可以省略大括号。(不建议)
4.多个条件表达式的关系如果为包含关系,范围小的在上边,范围大的在下边。
如果是互斥关系,那么谁上谁下都可以。

代码:

//if
	boolean handsome = false;
	if(handsome){
		System.out.println("我们结婚吧!!!");
	}

	System.out.println("-------------------------");

	//if - else

	boolean hasMoney = false;

	if(hasMoney){
		System.out.println("今晚我是你的人");
	}else{
		System.out.println("我不是那种人");
	}

	System.out.println("-------------------------");
	// if - else if - else
	
	int age = 100;

	if(age < 18){
		System.out.println("就不要看片了");
	}else if(age < 30){
		System.out.println("还是不要看片了没事多陪陪媳妇吧");
	}else if(age < 50){
		System.out.println("年轻看片多了,年纪大了就多运动吧");
	}else{
		System.out.println("还是在家里睡觉吧");
	}
	

	System.out.println("程序执行完毕");

3.1.2 switch-case结构
格式:

switch(表达式){
	
	case 常量1:
		执行语句1;
		break;
	case 常量1:
		执行语句1;
		break;
	case 常量1:
		执行语句1;
		break;
	......
	default:
		执行语句N;
		break;
	
	}

说明:
1.根据switch中的表达式的值依次进行case匹配,一旦匹配成功,则执行该case中的执行语句。如果在执行过程中遇到break则跳出switch-case结构。如果没有break继续向下执行,执行到switch-case结构中最后的语句,再跳出switch-case结构。如果没有匹配成功则执行defult中的代码。
2.break是可选的。break用来跳出switch-case结构。
3.default的位置是灵活的。
4.表达式的类型只能是 byte short int char 枚举 String
5.case后面只能跟常量 (1,2,100 ,‘a’ ,“aaa”) 且所有case子句中的值应是不同的

3.2 循环结构

四个条件:
①初始化条件
②循环条件
③循环体
④迭代条件

3.2.1 for循环

格式:
for(初始化条件; 循环条件;迭代条件){
循环体;
}

执行顺序: 1 – 2 – 3 – 4 – 2 – 3 – 4 … 2

代码:

int sum = 0; //用来统计偶数的个数
		int sumNumber = 0; //用来统计所有偶数的和
		for(int i = 1; i <= 100; i++){

			//判断是否是偶数
			if(i % 2 == 0){
				sum++;
				sumNumber += i;  // sumNumber = sumNumber + i;
				System.out.println(i);
			}
			
		}

3.2.2 while循环

格式:
初始化条件;
While(循环条件){
循环体;
迭代条件;
}

注意:迭代条件一定要写否则就成了死循环

代码:

		//初始化条件
		int i = 1;
		
		int number = 0; //偶数的个数

		int sum = 0; //偶数的总和
		
		while(i <= 100){ //循环条件
			//循环体
			if(i % 2 == 0){
				number++;
				sum += i;
				System.out.println(i);
			}

			i++; //迭代条件  -  如果没有迭代条件就会变成一个死循环
		}

3.2.3 do-while循环

格式:
初始化条件:
do{
循环体;
迭代条件;
}while(循环条件);

[面试题] while和do-while的区别?
while可能一次循环体也不执行。do-while至少执行一次循环体.

代码:

int i = 1;

		int number = 0; //偶数的个数
		int sum = 0; //偶数的总和

		do{
			if(i % 2 == 0){
			
				number++;
				sum += i;
				System.out.println(i);
			}

			i++;
		
		}while(i <= 100);

##3.3 死循环
格式 :

for(;😉{}
while(true){}
do{}while(true);

如何终止循环:
①使用break关键字
②将循环条件的结果改为false

代码:

/*
		for(;;){
			System.out.println("小泽我爱你");
		}
		*/

		/*
		while(true){
			System.out.println("我爱你小泷");
		}

		*/

		//退出死循环的方式

		boolean boo = true;
		while(boo){
			System.out.println("我爱你小泷");
			boo = false;
		}

		//break 用来结束当前循环
		while(true){
			System.out.println("我爱你小泷");
			break; //用来结束当前循环
		}
		

3.4嵌套循环

嵌套循环 :一个循环a中还有一个循环b a循环叫做外层循环b循环叫内层循环

执行的次数 = 外层循环的次数 * 内层循环的次数

说明 :
①外层循环一次内层循环一轮。

② 外层循环控制行,内层循环控制列。

代码:

//需求:每次只能输出一个*  输出 *****

		for(int i = 0; i < 5; i++){
			System.out.print("*");
		}

		System.out.println("------------------------------");
		/*

			需求:输出 图形

			*****
			*****
			*****
			*****
			*****
		*/
		for(int i = 0; i < 5; i++){
			for(int j = 0; j < 5; j++){
				System.out.print("*");
			}
			System.out.println();
		}

		/*
			需求:
						i       j
			*			1       1
			**			2       2
			***         3       3
			****        4       4
			*****       5       5

		*/
		for(int i = 1; i <= 5; i++){
		
			for(int j = 1; j <= i; j++){
				
				System.out.print("*");
			
			}
			System.out.println();
		}




		/*
			需求:
							i     j
			*****			1     5
			****			2     4
			***				3	  3
			**				4     2
			*				5     1

		*/

		for(int i = 1; i <= 5; i++){
		
			for(int j = 1; j <= 6 - i; j ++){
				System.out.print("*");
			}
			System.out.println();
		}

		System.out.println("----------------------------------");
		/*
			需求:
						i   j   k
			----*       1   4   1
			---* *      2   3   2
			--* * *     3   2   3
			-* * * *    4   1   4
			* * * * *   5   0   5

		*/

		for(int i = 1; i <= 5; i++){
		
		
			for(int j = 1; j <= 5 - i; j++){
			
				System.out.print(" ");
			}


			for(int k = 1; k <= i; k++){
			
				System.out.print("* ");
			}
		
			System.out.println();
		
		}

3.5break和continue的使用

break: 1.用在switch-case中用于结束switch-case结构.
	   2.用在循环语句中用于结束当前(本层)循环.
	   3.在嵌套循环中-结束的是包含它的那个循环的本层循环

continue: 
		1.只能在循环语句中使用。用于结束当次循环。
		2.在嵌套循环中-结束的是包含它的那个循环的当次循环	

标签 :

	l : for(int i = 1; i <= 5; i++){

	for(int j = 1; j <= 5; j++){
	
		if(j == 2){
			
			break l; //结束含有标签的那层循环
		//编译错误  break continue后面不能直接再跟语句因为根本不会执行到
			//System.out.println("aaaaaaaaaaaaaaaaa"); 
			
		}

		System.out.println("j=" + j);
	}

	System.out.println("i=" + i);
}

第4章面向对象上

4.1类与对象

4.1.1 面向对象学习的三条主线:

1.java类及类的成员
2.面向对象的三大特征
3.其它关键字

4.1.2面向对象与面向过程(理解)

面向过程:面向过程,强调的是功能行为
面向对象:将功能封装进对象,强调具备了功能的对象

4.1.3面向对象中两个重要的概念:

类:对一类事物的描述,是抽像的概念上的定义
对象:具体的实实在在的个体。(对象是由类派生出来的。new出来的)

4.1.4 面向对象思想落地实现的规则一

1.创建一个java类
2.在类中提供必要的属性和方法
3.通过类创建对象。 Person p = new Person();
4.调用对象中的属性和方法 。对象名.方法名 、 对象名.属性名

4.1.5对象的创建与对象的内存解析

在这里插入图片描述

4.1.6.匿名对象:

匿名对象:我们也可以不定义对象的句柄,而直接调用这个对象的方法。这样的对象叫做匿名对象

使用场景:常常作为实参进行传递。

例:
new Person();

4.2类的结构之一:属性

4.2.1 变量的分类

安照数据类型 :基本数据类型 vs 引用数据类型
按照位置来分 : 成员变量 vs 局部变量

4.2.2 局部变量和成员变量的相同和不同

相同点:
1.都是先声明后使用
2.都有作用域
3.声明的格式 : 变量的类型 变量名 = 变量值

不同点:
1.位置不同
*成员变量 :在类中,方法构造器等结构外。

  • 局部变量 :在构造器和方法等结构中声明的变量,构造器和方法的形参。
    2.默认值不同:
    成员变量:
    基本数据类型
    byte short int long -> 0
    float double -> 0.0
    char -> \u0000
    boolean -> false
    引用数据类型 : null
    局部变量:没有默认值
    3.内存的位置不同
  • 局部变量:在栈中
  • 成员变量 : 在堆中
    4.权限修饰符不同:
  • 局部变量:没有权限修饰符
  • 成员变量 :可以使用四种权限修饰符 。
    private 缺省的 protected public

4.2类的结构之一:方法

4.2.1 方法

方法的格式:
权限修饰符 返回值类型 变量名(形参列表){
方法体;
}
方法的说明:
1.权限修饰符 : private 缺省的 protected public
2.返回值类型 :只有两种 - void(没有返回值) / 具体的类型(基本数据类型和引用数据类型)具体的类型 : 那么方法的最后必须是 “return 具体的类型”.
3.方法名 : 遵守标识符的规则和规范。要做到见名知义。
4.形参列表 :可以是0个 1个或多个 。多个之间用","隔开.
(变量类型 变量名,变量类型 变量名 …)
形参属于局部变量。
5.方法体:方法的具体功能的实现。只能调用方法的时候才会执行方法体。
return关键字:
1.在方法中使用
2.如果方法没有返回值,那么”return”用来结束当前的方法
3.如果方法有返回值,”return 具体的数据”用来返回数据并结束当前方法

4.2.2 方法的重载

方法的重载的概念:
同一个类中相同的方法名不同的形参列表构成重载
举例:

// 需求:计算两个数(int类型)的和
public void add(int a, int b) {
	System.out.println("int int int");
	System.out.println(a + b);
}


// 需求 :计算两个数(double类型)的和
public void add(double a, double b) {
	System.out.println(a + b);
}

public void add(int a, double b) {

}

//构成重载
public void add(double b,int a){
	
}

如何确定类中某一个方法的调用:方法名 + 形参列表
说明:
1.方法的重载和权限修饰符,返回值类型,形参列表变量名都没有关系
2.形参列表不同指的是形参的类型和个数

4.2.3 值传递

形参:方法声明时的参数
实参:方法调用时实际传给形参的参数值
总结:
①基本数据类型: 传递的是变量中具体的数值
②引用数据类型: 传递的是对象的地址值
图示:

在这里插入图片描述

在这里插入图片描述

4.3面向对象的特征一:封装与隐藏

4.3.1 为什么要使用封装性?

当我们给对象中的属性进行赋值时,只能对属性的类型和数值范围进行限制。但是在实际中往往我们还会有其它的限制条件。那么这些限制条件不能在属性的声明处加以限制。所以我们采用以下方式。
1.将属性私有化,不让对象可以直接调用属性并给属性赋值。
2.提供公共的方法,可以通过方法给属性进行赋值,并在方法中可以加以其它的限制条件。

4.3.2 封装性的体现

封装性思想具体的代码体现:

class Person{
	
	private int age;
	
	
	public void setAge(int age){
				
		if (age < 0 || age > 120) {
			System.out.println("非法操作");
			return;
		}
			
		this.age = age;
		
	}
	
	
	public int getAge(){
		return age;
	}
	
}

封装性的体现(狭义上)
1.将属性私有化
2.提供公共的set/get方法
封装性的体现(广义上)
1.可以修饰属性的四种权限修饰符 - private 缺省的 protected public
2.类的成员可以使用四种权限修饰符 - 属性,方法,构造器,内部类
3.类只能被public和缺省的所修饰
4.3 类的成员之:构造器
作用:1.创建对象 2.给对象进行初始化
格式:
权限修饰符 类名(形参列表){初始化语句;}
说明:
1.在一个类中如果没有显示的声明构造器,那么系统创建对象的时候会默认为我们提供一个空参的构造器。
2.如果在类中显示的声明了构造器,那么系统就不会再为我们提供空参的构造器了
3.一个类中可以有多个构造器,多个构造器之间构成重载
总结:创建对象必调构造器

4.3 属性的赋值顺序

赋值方式 : 1.默认值 2. 显示赋值 3. 对象.属性、对象.方法 4.构造器赋值
赋值顺序 :1 – 2 – 4 - 3

4.3 关键字:this

this关键字表示:当前对象
this可以用来调用 :属性,方法,构造器
this调用属性和方法:
在方法和构造器中,调用属性时往往我们会省略掉"this."。但是如果方法和构造器中的形参的名字和属性的名字一致时,我们必须使用 this.属性名 来和 形参加以区分。
this调用构造器 :
1.格式:this(形参列表) - 用来调用本类中的其它构造器
2.this(形参列表) 必须放在构造器的首行(一个构造器中最多只能有一个this(形参列表))
3.如果一个类中的构造器有n个 ,那么最多只能有n-1个this(形参列表)

4.3 关键字:import和package

  • 关键字 package :
    1.java为了对所有的类进行统一管理,所以有了包的概念
    2.不同包中的类的类名可以相同
    3.每一个"."代表一层目录
    4.包名 : com.公司名.项目名.模块名
    5.package必须声明在源文件的首行
  • 关键字import
    1.在源文件中使用import显式的导入指定包下的类或接口
    2.声明在包的声明和类的声明之间。
    3.如果需要导入多个类或接口,那么就并列显式多个import语句即可
    4.举例:可以使用java.util.*的方式,一次性导入util包下所有的类或接口。
    5.如果导入的类或接口是java.lang包下的,或者是当前包下的,则可以省略此import语句。
    6.如果在代码中使用不同包下的同名的类。那么就需要使用类的全类名的方式指明调用的是哪个类。
    7.import static组合的使用:调用指定类或接口下的静态的属性或方法
    8.如果已经导入java.a包下的类。那么如果需要使用a包的子包下的类的话,仍然需要导入。

第5章 数组

数组是多个相同类型数据的组合,实现对这些数据的统一管理;
数组中的元素可以是任何数据类型,包括基本类型和引用类型;
数组属引用类型,数组型数据是对象(object),数组中的每个元素相当于该对象的成员变量;

5.1 一维数组

5.1.1 数组的声明和初始化

声明方式:
String[] names;
int numbers[]; //不建议使用
静态初始化:
String[] names = new String[]{“aa”,”bb”}
int[] numbers = {1,2,3,4} //声明和赋值不能分开写
动态初始化:
String[] names = new String[5];
说明:无论是静态初始化还是动态初始化一旦数组创建成功
那么数组的长度不可变。

5.1.2 调用数组中的元素

String[] names = new String[5];

  1. 数组的索引(下角标)是从0开始的.
  2. 取值
    String name = names[0];
  3. 赋值
    names[0] = “cc”;

5.1.3 数组的属性 – length (数组的长度)

int len = names.length

5.1.4 数组的遍历

for(int i = 0; i < names.length; i++){
System.out.println(names[i]);
}

5.1.5 数组元素的默认值

byte short int long - 0
float double – 0.0
char - \u0000
boolean – false
引用数据类型 :数组,类,接口 - null

5.1.6 数组的内存分析

在这里插入图片描述

5.2 二维数组

5.2.1数组的声明和初始化

第一个[]指的是二维数组中的第几个元素
第二个[] 指的是该数组元素的第几个元素
数组的声明:
String[][] persons;
String[] persons[]; //不建议使用
String persons[][];//不建议使用
静态初始化:
String[][] persons = new String[][]{{“小泽”,“110”},{“小苍”,120}}
String[][] persons = {{“小泽”,“110”},{“小苍”,120}}
动态初始化:
//二维数组的长度是2,每个元素的长度还是2
String[][] persons = new String[2][2];
String[][] persons = new String[2][];
persons[0] = new String[3];
persons[1] = new String[2];

5.2.1调用数组中的元素

String[][] persons = {{“张三”,“18”},{“李四”,“20”}};
//0指的是二维数组中的第几个元素
//1 指的是该数组元素的第几个元素
System.out.println(persons[0][1]); //18

5.2.1数组的属性

String[][] persons = {{“张三”,“18”},{“李四”,“20”}};

二维数组的长度 : persons.length
二维数组元素的长度 : persons[0].length

5.2.1数组的遍历

for(int i = 0; i < persons.length; i++){
	for(int j = 0; j < persons[i].length; j++){
		System.out.println(persons[i][j]);
}
}

5.2.1二维数组元素的默认值

二维数组元素的默认值是 : null
二维数组的元素是一维数组,数组是引用数据类型所以默认值是null

5.2.1二维数组的内存分析在这里插入图片描述

5.3数组常见算法

/*
	 * 遍历
	 */	
	public void listArray(int[] numbers) {
		for (int i = 0; i < numbers.length; i++) {
			System.out.print(numbers[i] + " ");
		}
	}

	/*
	 * 求数组中的最大值
	 */
	public int getMaxNumber(int[] numbers) {
		// 求数组元素的最大值
		int max = numbers[0]; // 不要写0
		for (int i = 1; i < numbers.length; i++) {
			if (numbers[i] > max) {
				max = numbers[i];
			}
		}
		return max;
	}

	/*
	 * 求数组元素的最小值
	 */
	public int getMinNumber(int[] numbers) {
		// 求数组元素的最小值
		int min = numbers[0];
		for (int i = 1; i < numbers.length; i++) {
			if (numbers[i] < min) {
				min = numbers[i];
			}
		}
		return min;
	}

	/*
	 * 求数组元素的和
	 */
	public int sum(int[] numbers) {
		int sum = 0;
		for (int i = 0; i < numbers.length; i++) {
			sum += numbers[i];
		}
		return sum;
	}

	/*
	 * 求平均数
	 */
	public int average(int[] numbers) {
		int sum = sum(numbers);
		return sum / numbers.length;
	}

	/*
	 * 数组的复制
	 */
	public int[] copy(int[] numbers) {
		// 数组的复制
		int[] nCopy = new int[numbers.length]; // 创建一个新的数组
		for (int i = 0; i < numbers.length; i++) {
			nCopy[i] = numbers[i];
		}
		return nCopy;
	}

	/*
	 * 数组的反转
	 */
	public void reverse(int[] numbers) {

		for (int i = 0, j = numbers.length - 1; i < numbers.length / 2; i++, j--) {
			int temp = numbers[i];
			numbers[i] = numbers[j];
			numbers[j] = temp;
		}

		for (int i = 0; i < numbers.length; i++) {
			System.out.print(numbers[i] + " ");
		}

	}

	/*
	 * 线性查找 : 如果没有找到返回-1
	 * 
	 * numbers : 数据源 findNumber : 需要查找的数据
	 */
	public int findNumber(int[] numbers, int findNumber) {
		int index = -1; // 查找到元素所在的索引值
		for (int i = 0; i < numbers.length; i++) {
			if (findNumber == numbers[i]) {
				index = i;
			}
		}
		return index;
	}

	public void bubbleSort(int[] n,String str) {

		if ("asc".equals(str)) {
			// 从小到大
			for (int i = 0; i < n.length - 1; i++) {

				for (int j = 0; j < n.length - 1 - i; j++) {

					if (n[j] > n[j + 1]) {
						int temp = n[j];
						n[j] = n[j + 1];
						n[j + 1] = temp;
					}
				}
			}
		} else if("desc".equals(str)) {
			// 从大到小
			for (int i = 0; i < n.length - 1; i++) {

				for (int j = 0; j < n.length - 1 - i; j++) {

					if (n[j] < n[j + 1]) {
						int temp = n[j];
						n[j] = n[j + 1];
						n[j + 1] = temp;
					}
				}
			}
		}

	}

5.4 Arrays工具类的使用

在这里插入图片描述

5.5数组常见异常

第一种 : 下角标越界
第二种 : 空指针异常

代码:

		int[] numbers = new int[2];
		
		//下面的两个方式都会发生下角标越界
//		System.out.println(numbers[2]);
//		System.out.println(numbers[-2]);
		
		
		//空指针异常
//		int[] n = null;
//		n[0] = 5;
		
		//空指针异常
		/*
		String[] s = new String[2];
		String str = s[0]; //因为 s[0]元素是个null
		System.out.println(str.toLowerCase()); 相当于 null.toLowerCase();
		*/
		
		
		//空指针异常
		/*
		String[][] s = new String[2][];
		s[0][0] = "aa";
		*/

5.6可变个数形参

格式:方法名(变量的类型 … 变量名)
说明:
1.可变形参的个数可以是0个 1个 或者多个
2.形参列表如果是相同类型的可变形参和数组那么不构成重载。 (int … args)可以理解成int[] args
3.在形参列表中 可变形参只能放在最后一个
4.形参列表中只能有一个可变形参

第6章 面向对象下

6.1 面向对象特性之 : 继承性

6.1.1 为什么要有类的继承性?(继承性的好处)

①减少了代码的冗余,提高了代码的复用性;
②更好的扩展性
③为多态性的使用提供了前提

6.1.2 继承的格式:

A extends B
A 子类 (SubClass)
B 父类(SuperClass) 超类,基类

6.1.2子类继承父类以后有哪些不同?

子类继承父类以后,就拥有了父类中的属性和方法.
当父类中的属性被私有化后,子类就不能直接调用了。但我们还是认为子类继承到了父类中的被私有化的属性。我们可以通过间接的方式进行调用。

6.1.3 java中继承性的说明

1.子类除了可以继承父类中的属性和方法外,还可以自己再定义其它的属性和方法
2.一个子类只可以有一个父类,一个父类可以有多个子类。(java的类是单继承的)
3.子类和父类的概念是相对而言的。如果A类的父类是 B类,B类的父类是C类。 B类是A类的直接父类,C类是A类的间接父类。
4.子类不仅可以继承直接父类的属性和方法,还可以继承间接父类中的属性和方法。
5.我们不认为类中的构造器可以被继承

6.2 方法的重写

6.2.1什么是方法的重写 :

定义 :子类可以对父类中同名同参的方法进行覆盖(覆写)

6.2.2方法重写后的调用 :

当子类重写了父类的方法后。通过子类对象调用父类的方法,实际上调用的是子类重写父类后的方法。

6.2.3 说明

权限修饰符 返回值类型 方法名(形参列表){
方法体;
}
子类重写的方法 父类被重写的方法
1.子类重写的方法和父类被重写的方法,方法名和形参列表必须一致。
2.子类重写的方法的权限修饰符 不小于 父类被重写方法的权限有修饰符
3.子类重写的方法的返回值类型 不大于 父类被重写方法的返回值类型
(子类重写的方法的返回值类型和父类被重写的方法的返回值类型 如果不是void
那么需要有子父类关系(如果是相同的类型也可以))
①父类被重写方法的返回值类型是void那么子类重写的方法的返回值类型必须是void
②父类被重写方法的返回值类型是 int 子类重写的方法的返回值类型是double(不可以,没有子父类关系)
③ A类继承B类,B类继承C类。父类被重写的方法返回值类型是B类 那么子类重写的方法的返回值类型只能是B类或A类
4.子类方法抛出的异常不能大于父类被重写方法的异常

6.2.4 注意

1.父类中的被私有化的方法,我们不认为子类可以重写
2.子类和父类同名同参的方法,要么同时加static,要么同时不加static.如果加上static那么子类和父类同名同参的方法不是重写的方法.

6.3 关键字super

super可以调用:属性,方法,构造器
super调用属性和方法:
当有了继承以后。我们就可以在方法和构造器中,使用"super.“调用父类中的方法和属性.往往我们都会省略掉"super.”.但是如果子类重写了父类以后,或者子类中的属性名和父类中的属性名相同时。那么我们就必须显示的调用“super.”来指明调用的是父类中的属性和方法
super调用构造器:
格式 :super(形参列表)
说明 :
1.格式:super(形参列表) 用来调用父类中的指定的构造器
2.super(形参列表)必须放在构造器的首行
3.一个构造器中只能有一个super(形参列表)
4.一个构造器中super(形参列表),this(形参列表)只能有一个
5.如果子类中的构造器中没有显示的调用this(形参列表)和super(形参列表)那么默认调用的是super();

6.4 子类对象实例化过程(理解)

图示 :

过程上:子类通过继承父类,就可以获取父类中的属性和方法。那么通过子类对象就可以调用父类中的属性和方法
结果上:子类继承父类以后。子类一定会调用到 直接父类,间接父类…Object中的空参构造器。那么所有的父类都会被JVM加载到内存中。然后子类就可以调用到这些父类中的属性和方法。
注意:虽然父类都会被JVM加载到内存中,但是从始之终我们认为只创建了子类一个对象

6.5 面向对象的特性之:多态性

6.5.1多态性的理解:

一类事物的多种形态

6.5.2广义上多态性的体现:

①方法的重写,重载
②子类对象的多态性

6.5.3狭义上多态性的体现:

①子类对象的多态性

6.5.4何为子类对象多态性:

父类的引用指向子类的对象

6.5.5多态性的应用:

虚拟方法调用:编译看左边,运行看右边
编译时:看的是父类(调用的是父类中的方法)
运行时:看的是子类(调用的方法是子类重写父类中的方法)

6.5.6多态性的说明:

思考?什么是多态性?
父类的指向子类的对象,编译看左边,运行看右边
思考?属性有没有多态性?
没有
思考?如果需要调用子类中的特有的属性和方法怎么办?
向下转型(注意使用instancof判断对象的类型)

6.5.7多态性使用的前提:

①要有继承性
②要有方法的重写

6.5.8.关于向上转型与向下转型:

向上转型: 多态
向下转型: 将父类的引用强制转换成子类的对象
图:
在这里插入图片描述

为什么要使用向下转型?
父类的引用指向子类的对象。编译看左边运行看右边。实际上子类中的属性和方法都被加载到了内存中。因为编译看左边不能调用子类中特有的属性和方法。那么只能通过向下转型的方式来进行调用子类中特有的属性和方法。
说明:
①向下转型可能会出现: 类型转换异常
②向下转型可以使用:
强制类型转换符 – (强转的类型)
③向下转型需要判断:instanceof
a instanceof A : a是否是A类型的实例

6.5.9.面试题:多态是编译时行为还是运行时行为?

运行时行为

6.6 Object

6.6.1Object类的说明

①Object是所有类的基类
②Object中有9个方法,一个空参的构造器

6.6.2 equals方法

一  Object中equals方法的 实现
 public boolean equals(Object obj) {
    return (this == obj);
 }

二 像系统中的String ,Date 等类 都重写了equals方法 .
用来比较内容。

三 一般情况下我们调用equals方法,都是用来比较对象的内容。所以往往我们都会在自定义类中重写equals方法,用来比较属性的内容。

6.6.3 toString方法

一 Object中的toString方法

  • public String toString() {
    return getClass().getName() + “@”
    + Integer.toHexString(hashCode());
    }

二 像系统中的String ,Date 等类 都重写了toString方法 .用来输出对象中属性的值。

三 一般情况下我们调用toString方法,都是用来输出对象的内容。所以往往我们都会在自定义类中
重写toString方法,用来输出属性的内容。

6.6.4 面试题?==和equals的区别?

== 比较的是基本数据类型的话,比较的是具体的数值
== 比较的是引用数据类型的话,比较的是地址值(两个地址是否指向同一块内存)

equals 如果没有重写equals方法那么调用的是Object中的equals比较的还是地址值如果重写了equals方法,那么就安照重写后的内容进行比较。(通常重写equals比较的都是内容)

==和equals的区别
最大的区别是一个是方法一个是运算符
==是一个比较运算符,基本数据类型比较的是值,引用数据类型比较的是地址值。
(比较地址值即是指是否为同一个对象的引用)
equals()是一个方法,只能比较引用数据类型。重写前比较的是地址值,重写后比一般是比较对象的属性。

6.7关键字Static

6.7.1可以用来修饰的结构

属性,方法,代码块,内部类

6.7.2 static修饰属性

1.同一个类的多个对象各自拥有一份实例变量,多个对象共同拥有一份类变量。
2.当其中的一个对象对类变量进行修改,那么其它的对象看到的是修改后的结果。
3.类变量是随着类的加载而加载,实例变量是随着对象的创建而加载。

  •  		类的加载早于对象的创建。
    

4.类的加载只加载一次。
5.如何调用类变量:对象名.类变量名 类名.类变量名
6.类变量在方法区的静态域中,实例变量在堆中。

6.7.3 static修饰方法

1.静态方法随着类的加载而加载
2.调用静态方法 : 对象名.静态方法名 类名.静态方法名
3.静态方法中不能调用非静态方法和实例变量。因为类的加载优先于对象的创建。非静态方法中可以调用静态方法和类变量。
4.静态方法中可以使用super和this吗?不能

6.7.4 内存解析

6.7.5 什么时候使用static修饰属性和方法

static修饰属性:
①多个对象共同拥有一份属性的时候
②声明为常量时
static修饰方法:
① 调用类变量的时候
②当定义成工具类中的方法的时候

6.8类的结构:代码块

1.代码块的作用:用来对类和对象进行初始化
2.分类:静态代码块 vs 非静态代码块
格式:
静态代码块:static{}
非静态代码块: {}
注意:代码块只能被static修饰
3.说明
静态代码块:
1.作用 : 用来对类进行初始化
2.静态代码只执行一次。随着类的加载而加载。
3.静态代码块优先于非静态代码块执行。
4.静态代码块不可以调用实例变量和非静态方法
5.多个静态代码块从上到下依次执行
非静态代码块:
1.作用:用来对对象进行初化
2.随着对象的创建而执行
3.非静态代码块优先于构造器的执行
4.可以调用类变量和静态方法
5.多个非静态代码块从上到下依次执行

6.9属性的赋值顺序

属性赋值的方式 :
1.默认值 2.显示赋值 3.代码块赋值 4构造器赋值 5.对象.方法名 、对象名.属性名
顺序 :1 – 2 、3 - 4 – 5
注意:2和3谁在上谁先赋值

6.10 关键字final

Final修饰类 : 不能被继承。例:String,StringBuffer
Final修饰属性 :一般作为常量。且只能赋值一次
Final修饰方法 : 不能被重写
Final修饰的属性的赋值方式 :
显示赋值,代码块赋值,构造器赋值

第7章 高级类特性

7.1 关键字:abstract

1.abstract可以修饰:类,方法
2.abstract修饰方法 : 抽像方法
abstract修饰类: 抽像类
abstract不可以和哪些关键字一起使用:
3.说明:
abstract修饰类:

  •  1.抽像方法所在的类必须是抽像类
    
  •  2.抽像类不可以被实例化
    
  •  3.抽像类中不一定有抽像方法。但是抽像方法所在的类必须是抽像类
    

abstract修饰方法:

  •  1.抽像方法没有方法体
    
  •  2.非抽像子类继承抽像类必须重写抽像类中的所有抽像方法
    
  •  	直接抽像父类如果重写了间接抽像父类中的抽像方法。那么非抽像子类可以不用重写。
    
  •  3.非抽像子类只能重写了抽像父类中的抽像方法才可以实例化。如果不想重写抽像父类中的抽像方法。那么该子类也可以声明成抽像类。
    

4.abstrcat不可以和哪些关键字一起使用
final private static
4:代码

abstract class  GeomericObject{
	/*
	 * 几何图形的面积
	 */
	public abstract double findArea(); //抽像方法
	//如果想让子类必须重写父类中的某个方法,那么这个方法也可以设计成抽像方法
	public abstract void setRadius();
}

/*
 * 三角形
 * 
 * 1.抽像类不可以被实例化
 * 2.抽像子类继承抽像父类可以不重写抽像方法
 */
abstract class Triangle extends GeomericObject{
	
	/*
	 * 思考?抽像类不能被实例化,那么抽像类中还有构造器吗?
	 * 有构造器,因为子类对象的实例化过程。
	 */
	
	@Override
	public double findArea() {
		// TODO Auto-generated method stub
		return 0;
	}
}

/*
 * 非抽像子类必须重写抽像父类中的所有的抽像方法,
 * 		直接抽像父类如果重写了间接抽像父类中的抽像方法。那么非抽像子类可以不用重写。
 */
class A extends Triangle{

	@Override
	public void setRadius() {
		// TODO Auto-generated method stub
		
	}
	
}

7.2 模板方法的设计模式

/*
 * 用来计算代码运行的时间
 */
abstract class ComputerCode {

	public void code() {
		// 开始的时间
		long startTime = System.currentTimeMillis();
		// 计算的代码
		codeTime();
		// 结束时间
		long endTime = System.currentTimeMillis();
		// 求时间差
		System.out.println("time=" + (endTime - startTime));
	}
	
	public abstract void codeTime();
}

class A extends ComputerCode{

	@Override
	public void codeTime() {
		for (int i = 1; i <= 1000; i++) {
			if(i % 2 == 0){
				System.out.println("aaa=" + i);
			}
		}
	}
	
}

class B extends ComputerCode{

	@Override
	public void codeTime() {
		for (int i = 1; i <= 1000; i++) {
			if(i % 2 != 0){
				System.out.println("bbb=" + i);
			}
		}
	}
	
}

7.3 关键字:interface

一 接口的声明格式 :
权限修饰符 interface 接口名{
}
二 说明

  •   1.类和接口是并列关系
    
  •  2.格式 :权限修饰符  interface 接口名{}
    
  •  3.接口中只能声明常量和抽像方法(jdk1.7之前(包含1.7))
    
  •  4.类和接口之间的关系: 类   implements 接口A,接口B 
    
  •  		实现的关系,一个类可以实现多个接口。
    
  •  5.接口和接口之间的关系 :接口A extends 接口B ,接口C
    
  •  		继承的关系,而且是多继承
    
  •  6.接口不可以被实例化,接口中没有构造器
    
  •  7.接口和类之间的多态性
    

三 接口和类的多态性

public class InterfaceTest2 {

	public static void main(String[] args) {
		
		Computer computer = new Computer();
		
		Mouse mouse = new Mouse();
		
		computer.work(mouse);
		
		System.out.println("-----------------");
		
		//匿名对象
		computer.work(new Printer());
		
		System.out.println("-------------------");
		
		//匿名实现类的对象
		USB keyboard = new USB() {
			
			@Override
			public void start() {
				System.out.println("键 盘开始工作了");
			}
			
			@Override
			public void stop() {
				System.out.println("键 盘停止工作了");
			}
		};
		
		computer.work(keyboard);
		
		//匿名实现类的匿名对象
		computer.work(new USB() {
			
			@Override
			public void start() {
				System.out.println("摄像头开始工作了");
			}
			
			@Override
			public void stop() {
				System.out.println("摄像头停止工作了");
			}
		});
	}
}

class Computer{
	
	public void work(USB usb){
		usb.start();
		System.out.println("-----------工作中-----------");
		usb.stop();
	}
}


interface USB{
	
	void start();
	void stop();
}


class Mouse implements USB{

	@Override
	public void start() {
		System.out.println("------鼠标开始工作了--------");
	}

	@Override
	public void stop() {
		System.out.println("------鼠标停止工作了--------");
	}
	
}

class Printer implements USB{

	@Override
	public void start() {
		System.out.println("------打印机开始工作了--------");
	}

	@Override
	public void stop() {
		System.out.println("------打印机停止工作了--------");
	}
	
}

7.4 关键字:工厂方法的设计模式

interface IWorkFactory{
	Work getWork();
}

class TeacherWorkFactory implements IWorkFactory{

	@Override
	public Work getWork() {
		
		return new TeacherWork();
	}
	
}

class StudentWorkFactory implements IWorkFactory{

	@Override
	public Work getWork() {
		return new StudentWork();
	}
	
}

interface Work{
	void doWork();
}

class StudentWork implements Work{

	@Override
	public void doWork() {
		System.out.println("学生在学习");
	}
	
}

class TeacherWork implements Work{

	@Override
	public void doWork() {
		System.out.println("苍老师在讲课");
	}
	
}

7.5 关键字:内部类

一 定义 :
在一个类A中再声明一个类B,那么类A叫做外部类,类B叫做内部类。
二 内部类的分类
成员内部类 vs 局部内部类
成员内部类(静态内部类 vs 非静态内部类)
三 说明

  • 内部类作为一个成员来讲:
  •  	1.可以使用四种权限修饰符
    
  •  	2.可以使用static关键字修饰
    
  •  	3.可以调用外部类的成员
    
  • 内部类作为一个类来讲:
  •  	1.可以被继承
    
  •  	2.可以定义属性,方法,构造器。
    

四 如何创建内部类对象
静态内部类 : new 外部类名.内部类名()
非静态内部类 : new 外部类名().new 内部类名()
五 如何调用外部类的成员
静态内部类 :外部类名.属性名
非静态内部类 : 外部类名.this.属性名
六 局部内部类

/*
	 * 思考?如何在方法外获取方法内的局部内部类的对象
	 * 
	 * 1.定义一个方法可以认识的接口
	 * 2.局部内部类实现该接口
	 * 3.该方法的返回值为接口的类型
	 * 4.返回该局部内部类的对象
	 */
	public P show(){
		//局部内部类
		class Student implements P{
			public void say(){
				System.out.println("aaa");
			}
		}
		
		return new Student();
		
	}
interface P{
	void say();
}

7.6 关键字:枚举

一 定义
一个类的对象是可数多个的,这样的类我们称为枚举类
二 如何自定义枚举类

/*
 * 自定义枚举类
 */
class Season{
	//1.私有化构造器
	private Season(String seasonName,String seasonDes){
		this.seasonDes = seasonDes;
		this.seasonName = seasonName;
	}
	
	private String seasonName;
	private String seasonDes;
	/*
	 * 快捷键 ctrl + shift + x 全部变为大写
	 * 快捷键 ctrl + shift + y 全部变为小写
	 */
	//2.创建四个对象
	public static final Season SPRING = new Season("春天","春眠不觉晓");
	public static final Season SUMMER = new Season("夏天","夏天蚊子咬");
	public static final Season AUTUMN = new Season("秋天","秋天落叶多");
	public static final Season WINTER = new Season("冬天","冬天不洗澡");
	
	
	public String getSeasonName() {
		return seasonName;
	}
	public String getSeasonDes() {
		return seasonDes;
	}
	
	
	
}

三 如何使用enum关键字定义枚举类

enum Season{
	SPRING,SUMMER,AUTUMN,WINTER;
}

四 常用API
在这里插入图片描述

五 枚举的对象实现接口中的方法

enum Season2 implements Show {

	SPRING("春天"){
		@Override
		public void info() {
			System.out.println("春天");
		}
	},
	SUMMER("夏天"){
		@Override
		public void info() {
			System.out.println("夏天");			
		}
	},
	AUTUMN("秋天"){
		@Override
		public void info() {
			System.out.println("秋天");			
		}
	},
	WINTER("冬天"){
		@Override
		public void info() {
			System.out.println("冬天");			
		}
	};
	
	/*
	 * 构造器只能为private
	 */
	private Season2(String name){
		
	}	
}

7.7 关键字:注解

一 定义:
可以用来对程序的一些结构(类,属性,包名,构造器)进行补充说明,而不改变原来的结构。
二 JDK内置的三个注解

  • @Override :限定重写父类方法, 该注解只能用于方法
  •  @Deprecated: 用于表示某个程序元素(类, 方法等)已过时
    
  •  @SuppressWarnings : 抑制警告
    

三 自定义注解
格式 :
权限修饰符 @interface 注解名{
}
代码:

@interface MyAnn2{
	int age() default 20; //默认值为20
	String name();
}

第8章 Java常用类

8.1包装类

一 八个包装类
在这里插入图片描述

二 基本数据类型,包装类,String三者之间的转换
在这里插入图片描述

8.1String类

  •   1.String类是final修饰的不能被继承
    
  •  2.String实现了Serializable接口,可以被序列化。
    
  •  3.String实现了Comparable接口,用来比较大小的
    
  •  4.String实现了CharSequence接口,可以获取字符串的长度,可以获取字符串上的某一个字符
    
  •  5.String的底层是一个字符数组,并且该数组是final修饰的。
    
  •  6.字符串是不可变的字符序列
    

8.2String常用API在这里插入图片描述

8.3 StringBuffer和StringBuilder

8.3.1 String,StringBuffer,StringBuilder三者之间的区别?

String : 底层是用一个char[]存储数据的而且该数组被final修饰,是一个不可变的字符序列
StringBuffer:底层是一个char[],可变的字符序列,线程安全的,效率低
StrinbBuilder:底层是一个char[],可变的字符序列,线程不安全的,效率高

8.3.2 StringBuffer构造器说明

 * new StringBuffer() : 创建一个长度为16的数组
 * new StringBuffer(20) : 创建一个长度为20的数组
 * new StringBuffer("aaaaa") :创建一个字符串长度 + 16的数组
  • 说明:
    •  当我们向一个长度为16的数组中添加第17个元素时。StringBuffer底层会进行扩容。
      
    •  扩容为原来长度的2倍+2
      
    • 构造器使用说明:
    •  1.如果知道添加元素的长度建议使用new StringBuffer(20) 
      
    •  2.如果不知道添加元素的数量 建议使用 new StringBuffer()
      
    •  3.知道目前先添加元素的内容可能后边还有追加用   new StringBuffer("aaaaa")
      
    • 注意 : 构造器中不能写null 否则会报空指针异常

8.3.3常用方法

在这里插入图片描述

8.4 时间日期API

8.4.1 Date

  • java.util.Date
    *
    •  两个构造器
      
    •  		new Date() : 获取当前时间
      
    •  		new Date(long time) : 获取毫秒数对应的时间
      
    •  两个方法
      
    •  		toString() : 显示时间
      
    •  		getTime() : 获取时间对应的毫秒数
      
    • java.sql.Date
    •  一个构造器
      
    •  		new Date(long time) :获取对应毫秒数的日期
      
    •  两个方法
      
    •  	 toString() : 显示日期
      
    •  	 getTime() : 获取日期对应的毫秒数
      

8.4.2 java.text.SimpleDateFormat:格式化时间

  • java.text包下都是关于 国际化的类。
  • 两个方法
    1. format(Date date) : 将时间转成字符串
    1. parse(String str) : 将字符串转成时间
      注意 : 不同格式之间不能相同进行转换(字符串转成时间)
      代码:
SimpleDateFormat sdf3 = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
		//2018-07-13T11:53:02.387+0800
		String time3 = sdf3.format(date);
		System.out.println(time3);
		System.out.println("--------------------------");
		SimpleDateFormat sdf4 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		//2018-07-13 14:19:44
		String time4 = sdf4.format(date);
		System.out.println(time4);
		//将字符串转成时间
		Date date2 = sdf4.parse("2018-07-13 14:19:44");
		System.out.println(date2.toString());

8.4.3日历类(了解

Calendar instance = Calendar.getInstance();
		
//		System.out.println(instance.getClass().getName());
		
		//在今天的天数上 + 1  (正数是添加,负数是减少)
		instance.add(Calendar.DAY_OF_MONTH, 1);
		
		//获取今天是当月的第几天
		int day = instance.get(Calendar.DAY_OF_MONTH);
		System.out.println(day);
		
		//将当天是当月的第几天修改成第1天
		instance.set(Calendar.DAY_OF_MONTH, 1);
		
		day = instance.get(Calendar.DAY_OF_MONTH);
		System.out.println(day);
		
		//获取日历对应的时间
		Date date = instance.getTime();
		System.out.println(date.toString());

8.5 其它类

8.5.1 Math:用于数学计算

在这里插入图片描述

8.5.2 BigInteger

说明 :Integer类作为int的包装类,能存储的最大整型值为,BigInteger类的数值范围较Integer类、Double类的数值范围要大得多,可以支持任意精度的整数。

8.5.3 BigDecimal

说明:一般的Float类和Double类可以用来做科学计算或工程计算,但在商业计算中,要求数字精度比较高,故用到java.math.BigDecimal类。BigDecimal类支持任何精度的定点数。

第9章 异常处理

9.1 异常体系结构

* 	|----- Throwable
 * 	
 * 		|----- Error :没有针对性的代码可以处理
 * 
 * 		|----- Exception :有针对性的代码进行处理
 *RuntimeException下的所有异常都是运行时异常)
 * 			|----- 运行时异常 : 在代码运行时发生的异常,可以不用处理
 * 				算术运算异常 - ArithmeticException
 * 				空指针异常 - nullPointerException
 * 				下角标异常 - ArrayIndexOutofBoundsException
 * 			|------ 编译时异常 :在代码编译时发生的异常,必须进行处理,否则不能运行
* 				 解析异常 : ParseException

图片:
在这里插入图片描述
在这里插入图片描述

9.2异常的处理

9.2.1 try-catch-finally

*1.trt中就写可能发生的异常的代码
*2.当执行try中的代码时,一旦发生异常。会创建异常对应的异常类的对象并抛出。会根据catch后面的异常类型依次进行匹配.一旦匹配成功,则执行异常处理的相应的代码。同时跳出try-catch结构,代码继续向下执行。

  •  	如果匹配不成功,则抛出异常给方法的调用者同时终止程序的运行。
    

*3.catch可以有多个。如果多个异常类是子父类关系,那么子类在上父类在上。如果不是子父类关系谁上谁下都可以
*4.try中的代码一旦出现异常,try中出现异常代码下面的代码将不再执行
*5.try - catch结构外不能调用try中声明的变量。因为作用域的问题
*6.finally是可选的。finally中的代码一定会执行
*7.常见异常信息 e.getMessage() e.printStackTrace()

代码:

try {
		
		System.out.println(1 / 0);
		
	} catch (ArithmeticException e) {
		//打印异常信息
		String string = e.getMessage();
		System.out.println("message= " + string);
		
		e.printStackTrace();
	} finally{
		System.out.println("我必须执行");
	}
	
	System.out.println("程序执行完毕");

9.2.2 throws

格式 :方法名()throws 异常类型1,异常类型2…{}
throws :
抓到异常后自己不处理,异常向上抛,让方法的调用者进行处理
throws和try-catch-fianlly的区别?
1.throws并没有真正的解决异常,最后还是需要try-catch-finally去处理异常。
2.try-catch-finally是真正的将异常进行处理。
throws和try-catch-finally的使用场景?
1.当我们真正的要求解决异常的时候使用try-catch-finally
2.当我们需要调用多个方法时,并且可能会出现异常。那么多方法建议将异常向上抛,抛给方法调用者。

9.2.3 手动抛出异常类对象 – throw

抛 :
当java程序运行时,一旦出现异常。Jvm会创建对应的异常类的对象。并抛出。抛出给方法调用者。同时终止程序的运行。
①系统向往抛异常 ②手动向往抛异常 throw
手动抛出异常throw
格式 : throw new 异常类型();

9.2.4自定义异常类

1.继承Exception那么就是编译时异常。继承RuntimeException那就是运行异常
2.写两个构造器。一个空参的。一个有参的参数为String
3.需要显示声明一个序列版本号 ,可以不声明系统会自动补充一个。
private static final long serialVersionUID = 5162710183389028792L;
代码:
public class MyException extends RuntimeException{

private static final long serialVersionUID = 51629028792L;

public MyException(){
	
}

public MyException(String s){
	super(s);
}

}

第10章 集合

10.1 数组和集合

一 内存中对数据进行存储和管理的“容器”:数组,集合
二 数组存储的特点和缺点
1.数组的特点
①数组的长度不可变
②声明数组时的类型决定了数组元素存储的类型
2.数组的弊短
①数组的长度不可变,不能很好的进行扩容
②数组中的属性和API比较少。比如缺少 ,增,删,改,查等方法
③数组只可以用来存放有序的且可重复的数据。对无序的且不可重复的要求无能为力。
三 集合存储的优点:
1.集合的长度是可变的。
2.集合用于处理的API非常丰富,比如,增,删,改,查
3.集合底层的数据结构非常多。比如,数组,链表,红黑树

10.2 Collection接口

一 单列集合框架结构:Collection
二 Collection接口常用方法:
在这里插入图片描述

三 Collection集合与数组间的转换
数组—>集合:Arrays.asList(T…t)
集合—>数组:toArray()
四 使用Collection集合存储数据,要求数据所在的类满足:
需要重写equals()

10.3 Iterator接口

10.3.1遍历Collection的两种方式:

①增强for循环
②Iterator迭代器

10.3.2 java.utils包下定义的迭代器接口:Iterator

1.作用:用来遍历集合中的元素
2.如何获取实例:集合的对象名.iterator()
3.常用方法:
hasNext():是否还有下一个元素
next():①指针下移 ②获取指针指向的元素
4.举例:

Collection c = new ArrayList();

		c.add(123);
		c.add("aaa");
		c.add("ccc");
		c.add(789);

		// 获取到Iterator实现类的对象
		Iterator iterator = c.iterator();

		while (iterator.hasNext()) {
			System.out.println(iterator.next());
		}

5.图示说明:

10.3.3增强for循环:(foreach循环)

格式:
for(元素的类型 临时变量 : 数组、集合的对象名){
}
遍历集合:

Collection c = new ArrayList();
		c.add(123);
		c.add("ccc");
		c.add(789);
		
		
		for(Object obj : c){
			System.out.println(obj);
		}

遍历数组:

String[] str = {"aa","bb","cc"};
		
		for (String string : str) {
			System.out.println(string);
		}

10.4 Collection子接口-List接口

一 存储的数据特点:有序且可重复
二 常用方法:(记住)
在这里插入图片描述

三 常用实现类:
ArrayList : List的主要实现类。底层是使用数组实现的。线程是不安全的效率高。查找快,增删慢。
Vector : Vector是古老的实现类,底层也是使用数组实现的,线程安全效率低。查找快,增删慢。
LinkedList : 底层是使用双向链表实现的。查找慢,增删快。
四 存储的元素的要求:
自定义类需要重写equals方法
五 ArrayList
①ArrayList的说明:
new ArrayList() :底层创建一个长度为10的数组
② 如何向ArrayList中添加数据?
当我们通过一个空参的构造器创建一个对象时,底层会为我们创建一个长度为10的数组。当我们向数组添加第11个元素时,底层会进行扩容。扩容为原来数组长度的1.5倍。再将原来数组的数据放到
新的数组中。

10.4 Collection子接口-Set接口

10.4.1存储的数据特点:无序的,不可重复的

  • 无序性 :指的不是随机性。根据hashCode()方法算出来的哈希值,来决定元素存储的位置。
  • 不可重复性 :指是调用equals()方法后,如果返回的是true则认为两个值是相同的。如果返回的结果是false那么认为两个值不相同。

10.4.2 HashSet元素添加方式:

当我们向HashSet中添加元素a时。先根据a所在类的hashCode方法算出一个哈希值,来决定该数据在数组中存放的位置。如果该位置上没有其它元素则直接放入。如果该位置上有其它元素b。那么将会调用a所在类的equals方法
和b进行比较。如果返回值为true则认为两个数据相同则不再放入。如果返回false则以链表的形式将数据a放入该位置。b —> a
补充:当链表的数据超过8时将用红黑树的结构替换链表。

10.4.3常用方法: (没有额外的再增加其它的方法)

10.4.4常用实现类:

HashSet,LinkedHashSet,TreeSet

10.4.5存储元素所在类的要求:

HashSet , LinkedHashSet : 重写equals和hashCode方法
TreeSet : 自定义类实现Comparable或者创建Comparator实现类的对象。

10.4.6TreeSet的使用:

说明:
1.TreeSet的底层的数据结构是红黑树

2.TreeSet可以对元素安某个属性进行排序
3.TreeSet中添加的元素必须是相同的类型
思考?
1.如果即有自然排序又有定制排序谁起作用? 定制排序
2.自然排序和定制排序哪个更好? 定制排序,因为定制排序使用起来更灵活

10.4.7 LinkedHashSet的使用说明:

继承了HashSet,同样也是无序的且不可重复的。
但是可以安照添加元素的顺序进行遍历。因为底层维护了一张链表用来记录元素添加的顺序。

10.4.8HashSet的实现原理?

当我们向HashSet中添加元素a时。先根据a所在类的hashCode方法算出一个哈希值,来决定该数据在数组中存放的位置。如果该位置上没有其它元素则直接放入。如果该位置上有其它元素b。那么将会调用a所在类的equals方法
和b进行比较。如果返回值为true则认为两个数据相同则不再放入。如果返回false则以链表的形式将数据a放入该位置。b —> a
补充:当链表的数据超过8时将用红黑树的结构替换链表。

10.5 Map接口(双列集合框架)

10.5.1 存储数据特点:存取的是键值对

图示:
在这里插入图片描述

10.5.2 常用实现类:

在这里插入图片描述

10.5.3 常用方法

在这里插入图片描述

说明 :
1.可以把Map中所有的key看成是Set的集合,无序且不可重复。
如果key中的元素是自定义类需要-重写hashCode和equals方法
2.可以把Map中所有的value看成是Collection的集合,无序且可重复。
如果value中的元素是自定义类那么需要重写equals方法
3.可以把Map中键值对(Entry)看成是一个Set集合,无序且不可重复。entry的位置是根据key的位置来决定的。
10.5.4 面试题
①[面试题1]:HashMap和Hashtable对比?
HashMap: Map的主要实现类,线程不安全的,效率高。
可以存储null的key和value
Hashtable: 线程安全的,效率低。不可以存储null的key和value
②[面试题2]:HashMap的底层实现原理?
当我们向HashMap中添加元素(K1,v1)时,先根据k1的hashCode方法算出的哈希值,来决定存储的位置。如果该位置上没有其它元素则直接存入。如果该位置上已经有其它元素(k2,v2)。那么将会调用k1的equals方法
和k2进行比较。如果返回值是true,说明key值相同那么将v1替换v2。如果返回值是false说明key不相同。那么将以链表的形式将(k1,v1)和(k2,v2)链接到一起。当链表的数据达到8时将链表替换成红黑树。

10.5.5 结构说明

new HashMap() :
new HashMap(); 底层创建了一个Node类型的数组,长度为16,加载因为子为0.75。当集合中的元素超过12时便会扩容,扩容为原来的2倍
说明:
1.HashSet的底层就是一个HashMap.向HashSet中添加的元素,实际上是添加到HashMap中的key里HashSet的特性就是HashMap中key的特性。
2.LinkedHashSet 底层就是LinkedHashMap
3.TreeSet的底层其实就是TreeMap

10.5.6 读取配置文件的操作实现

		//第一步创建对象
		Properties properties = new Properties();
		//第二步创建输入流的对象
		FileInputStream fis = new FileInputStream("person.properties");
		//第三步 加载流
		properties.load(fis);
		//第四步 读取配置 文件
		String username = properties.getProperty("username");
		String password = properties.getProperty("password");
		
		System.out.println(username + " " + password);
		
		//第五步 关流
		fis.close();

10.5.7 Collections工具类的使用

在这里插入图片描述
在这里插入图片描述

第11章 泛型

11.1泛型在集合中的使用

11.1.1在集合中使用泛型之前的例子

List list = new ArrayList();
		
//		list.add(123);
//		list.add("aaa");
//		list.add(new Person());

在这里插入图片描述

11.1.2在集合中使用泛型例子1

List<String> list = new ArrayList<String>();
	list.add("aaa");
	list.add("bbb");

11.1.3在集合中使用泛型例子2

Map<String,Integer> map = new HashMap<String,Integer>();
		map.put("aa", 111); 
		Set<Entry<String,Integer>> entrySet = map.entrySet();
		for (Entry<String, Integer> entry : entrySet) {
			System.out.println(entry.getKey());
			System.out.println(entry.getValue());
		}

在这里插入图片描述

11.2自定义泛型类,泛型接口,泛型方法

11.2.1自定义泛型类

public class Person<T> {

	T t;

	public T getT() {
		return t;
	}

	public void setT(T t) {
		this.t = t;
	}
	
	
}

思考?如何让子类指明父类的泛型类型
1.子类继承父类后,可以直接指明父类的泛型类型。
例 : public class Women extends Person
2.子类继承父类后,不指明父类的泛型类型,而是在创建子类对象时指明父类的泛型类型
例 :public class Women extends Person
Women w = new Women<>();

11.2.2自定义泛型接口

public interface English<T> {

	void setT(T t);
}

11.2.3自定义泛型方法

格式 : 权限修饰符 E 方法名(E e){

	}
	<E> : 告诉编译器参数中的E是一个泛型
	 E : 泛型的类型

当我们向方法中传入数据,数据的类型是什么,那么泛型的类型就是什么。

说明:
1.在try-catch结构中 : 捕获的异常类型不能使用泛型
2.不能将泛型类指明的泛型 ,用static修饰。不能在静态方法中使用。
3.泛型方法可以是静态方法

public  <E> E setE(E e){
		return e;
}

11.3泛型与继承的关系

1.如果 A 类 是B 类的父类 那么 A 和B 存在子父类关系。
2.如果 A 类 是B 类的父类那么G 和 G不存在子父类关系

11.4通配符 - ?

11.4.1通配符的使用说明:

说明:
通配符: ? ?是所有泛型的父类。
1.使用通配符<?>的集合只能存储null 2.使用通配符<?>的集合可以遍历所有的数据,类型都是Object

11.4.2通配符的限制说明:

? extends Number : 只能接收Number及Number子类的泛型类型
? super Number : 只能接收Number及Number父类的泛型类型
? extends Comparable : 只允许泛型为实现Comparable接口的实现类的类型

第12章 IO流

12.1File类

12.1.1.File类的理解

1.File用来表示一个文件(.txt .mp3 .mp4 .avi)还可以代表一个目录
2.File只可以用来创建目录文件等操作。没有向文件写内容的功能。
3.File类是在java.io包下的
4.往往我们把File看成是流的端点
5.往往我们将File的对象作为参传传递给流的对象的构造器中。

12.1.2.如何实例化

//表示的就是aaa.txt这个文件
File file = new File("E:\\io\\aaa.txt"); 
//相当于是 E:\\io\\aaa.txt
new File("E:\\io","aaa.txt");

绝对路径:包含盘符在内的完整路径
相对路径:相对于当前项目的路径

12.1.3.常用方法

在这里插入图片描述
注意:蓝色字体的API要掌握

12.2 IO流概述

12.2.1.流的分类

1)流的流向:输入流,输出流
2)流中数据单位:字节流,字符流
3).流的角色不同:节点流,处理流
图示:
在这里插入图片描述

12.2.2.流的体系结构

在这里插入图片描述

12.3节点流(文件流

//第一步 创建File对象
		File reader = new File("456.txt"); //读取的内容
		File writer = new File("789.txt"); //接收内容的文件
		
		//第二步创建流
		FileInputStream fis = new FileInputStream(reader);
		FileOutputStream fos = new FileOutputStream(writer);
		
		//第三步 一边读一边写
		byte[] b = new byte[500];
		int len = 0;
		
		while((len = fis.read(b)) != -1){
			//写数据
			fos.write(b, 0, len);
		}
		
		//关流
		fis.close();
		fos.close();

字符流:

File file = new File("bbb.txt");
		File file2 = new File("ccc.txt");
		
		FileReader reader = new FileReader(file);
		FileWriter writer = new FileWriter(file2);
		
		char[] c = new char[100];
		int len = 0;
		while((len = reader.read(c)) != -1){
			writer.write(c, 0, len);
		}
		
		writer.close();
		reader.close();

12.4缓冲流的使用

public void copy(String src,String desc){
		//第一步创建File对像
		File reader = new File(src); //读的内容
		File writer = new File(desc); //写的内容
		FileInputStream fis = null;
		FileOutputStream fos = null;
		BufferedInputStream bis = null;
		BufferedOutputStream bos = null;
		try {
			//第二步创建流
			fis = new FileInputStream(reader);
			bis = new BufferedInputStream(fis);
			fos = new FileOutputStream(writer);
			bos = new BufferedOutputStream(fos);
			//第三步 一边读一边写
			byte[] b = new byte[1024]; //用来接收数据使用的
			int len = 0; //用来表示文件是否读取完毕
			while ((len = bis.read(b)) != -1) {
				//写数据
				bos.write(b, 0, len);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}finally{
			//第四步 关流
			try {
				if(bos != null){
					bos.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				if(bis != null){
					bis.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			
			try {
				if(fis != null){
					fis.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
			try {
				if(fos != null){
					fos.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

File file = new File("aaa.txt");
		File file2 = new File("fff.txt");
		
		
		FileReader reader = new FileReader(file);
		FileWriter writer = new FileWriter(file2);		
		BufferedReader br = new BufferedReader(reader);
		BufferedWriter bw = new BufferedWriter(writer);
		
		/*
		char[] c = new char[100];
		int len = 0;
		while((len = br.read(c)) != -1){
			bw.write(c, 0, len);
		}
		*/
		
		String str = null;
		while((str = br.readLine()) != null){
			bw.write(str);
		}
		
		bw.close();
		br.close();
		writer.close();
		reader.close();

12.5转换流的使用

作用:

  1. 读取时,将字节流转成字符流,写入时,将字符流转成字节流
    2.将读取的文件内容的编码集(gbk),在写入到另一个文件时将编码集进行改变(utf-8)。
    注意:文件内容的编码集格式必须和InputStreamReader设置的编码集格式一样。

代码:

	//创建字节流
	FileInputStream fis = new FileInputStream("char8.txt");
	//读取内容时 - 将字节流转成字符流
	InputStreamReader isr = new InputStreamReader(fis,"gbk");
	
	
	//创建字符流
	FileOutputStream fos = new FileOutputStream("999.txt");
	//写入内容时 - 将字符流转成字节流
	OutputStreamWriter osw = new OutputStreamWriter(fos,"utf-8");
	
	char[] c = new char[100];
	int len = 0;
	while((len = isr.read(c))!=-1){
		osw.write(c, 0, len);
	}
	
	osw.close();
	isr.close();
	fos.close();
	fis.close();

图示:
在这里插入图片描述

12.6编码集

在这里插入图片描述

12.7其它流的使用(了解)

12.7.1 标准输入输出流

		//将字节流转成字符流
		InputStreamReader isr = new InputStreamReader(System.in);
		//创建BufferedReader
		BufferedReader br = new BufferedReader(isr);
		
		while(true){
			//一行一行的读取内容
			String str = br.readLine();
			
			if("e".equals(str) || "exit".equals(str)){
				break;
			}
			//转成大写进行输出
			System.out.println(str.toUpperCase());
		}
		
		//关流
		br.close();
		isr.close();

12.7.2 打印流

FileOutputStream fos = null;
	try {
		fos = new FileOutputStream(new File("text.txt"));
	} catch (FileNotFoundException e) {
		e.printStackTrace();
	} 
	
	// 创建打印输出流,设置为自动刷新模式(写入换行符或字节 '\n' 时都会刷新输出缓冲区)
	PrintStream ps = new PrintStream(fos, true);
	
	
	if (ps != null) { // 把标准输出流(控制台输出)改成文件
		//将输入到控制台的那个对象(那根管道) 换成指向text.txt文件的那根管道了
		System.setOut(ps); //只能赋值一次
	}
	
	
	for (int i = 0; i <= 255; i++) { // 输出ASCII字符
		System.out.print('a');
		
	}
	ps.close();
}

12.7.3 数据流

注意:
1.读取文件时,文件中应该先写入内容
2.写入文件内容的类型要和读取文件内容的类型保持一致 (否则会出现乱码 或者 异常)

@Test
	public void test() throws Exception{
		
		FileInputStream fis = new FileInputStream("data.txt");
		DataInputStream dis = new DataInputStream(fis);
		
		//读取内容
		String name = dis.readUTF();
		int age = dis.readInt();
		char sex = dis.readChar();
		
		System.out.println(name + " " + age + " " + sex);
		
		//关流
		dis.close();
		fis.close();
	}
	
	
	@Test
	public void test2() throws Exception{
		FileOutputStream fos = new FileOutputStream("data.txt");
		DataOutputStream dos = new DataOutputStream(fos);
		//写内容
		dos.writeUTF("aaa");
		dos.writeInt(123);
		dos.writeChar('?');
		
		//关流
		dos.close();
		fos.close();
	}

12.8 对象流的使用

说明:
1.需要被序列化的对象,必须实现Serializable接口
2.类中的属性,除了基本数据类型外。引用数据类型都必须也实现Serializable
3.显示的声明一个serialVersionUID
注意:static 修饰的 和 transient 修饰的属性不能序列化
序列化:用ObjectOutputStream类保存基本类型数据或对象的机制
反序列化:用ObjectInputStream类读取基本类型数据或对象的机制
代码:

/*
	 * 序列化
	 */
	@Test
	public void test() throws Exception{
		
		FileOutputStream fos = new FileOutputStream("123.txt");
		ObjectOutputStream oos = new ObjectOutputStream(fos);
		
		Person person = new Person("cc",16,new Address("国王街",38));
		oos.writeObject(person);
		
		oos.close();
		fos.close();
	}
	
	/*
	 * 反序列化
	 */
	@Test
	public void test2() throws Exception{
		
		FileInputStream fis = new FileInputStream("123.txt");
		ObjectInputStream ois = new ObjectInputStream(fis);
		
		Object obj = ois.readObject();
		Person person = (Person) obj;
		System.out.println(person.toString());
		System.out.println(person.address.doorID);
		
		ois.close();
		fis.close();
	}

12.9 RandomAccessFile类的使用

需求:在 abcdefg中 c的后面插入DDD结果为abcDDDdefg
* 1.将指针移动到c的后面
* 2.读取c后面的所有数据,并用临时变量进行存储
* 3.指针回移
* 4.写入要插入的内容
* 5.写入临时保存的所有数据
代码:

		RandomAccessFile raf = new RandomAccessFile("111.txt", "rw");
		
//		 * 1.将指针移动到c的后面
		raf.seek(3);
//		 * 2.读取c后面的所有数据,并用临时变量进行存储
		String str = raf.readLine();
//		 * 3.指针回移
		raf.seek(3);
//		 * 4.写入要插入的内容
		raf.write("DDD".getBytes());
//		 * 5.写入临时保存的所有数据
		raf.write(str.getBytes());
		
		raf.close();

第13章 多线程

13.1 基本概念

13.1.1 程序:为了完成某项特定任务,使用某种语言,编写一组指令的集合。

13.1.2 进程:一个正在进行中的程序

13.1.3 线程:在一个进程中,执行的一套功能流程,称为线程。在一个进程中,执行的多套功能流程,称为多线程。

13.2 为什么使用多线程

13.2.1 抢占式策略系统

系统会为每个执行任务的线程,分配一个很小的时间段,当该时间段用完后,系统会强制剥夺其 cpu 的使用权,交给其他的线程执行任务。

1.提高程序效率,提高效率的方式是尽可能的利用 cpu 的资源
2.提高用户体验

13.3 创建执行线程的方式(四种)

13.3.1 创建执行线程的方式一

  1. 声明一个类继承 Thread 类
  2. 重写 Thread 的run() 方法,同时编写线程执行体
  3. 创建该子类的实例
  4. 调用 start() 方法启动线程,默认调用 run()

13.3.2 创建执行线程的方式二

  1. 声明一个类实现 Runnable 接口
  2. 实现接口中的 run() 方法,同时编写线程执行体
  3. 创建该实现类的实例
  4. 将该实例作为参数,传递给 Thread 的构造器
  5. 调用 Thread 类的 start() 方法启动线程,默认执行 run() 方法

13.3.3 继承 Thread 类与实现 Runnable 接口的区别

  1. 当多个线程需要访问共享数据时,首选使用实现 Runnable 接口方式
  2. 实现接口方式解决了 Java 中单继承的局限性

13. 4 多线程的常用方法

currentThread() : 获取当前线程
getName() : 获取线程名称
setName() : 设置线程名称
start() : 启动线程

sleep(long millis) : 是一个静态方法,使当前线程进入睡眠状态
join() / join(long millis) : 是一个实例方法,使当前线程进入阻塞状态
interrupt() : 中断阻塞状态的线程,使阻塞状态产生一个 InterruptedException
isAlive() : 判断线程是否处于存活状态
yield() : 线程让步,主动放弃 cpu 的资源

13.5 线程的优先级

优先级共 1-10 个级别,默认优先级为 5。优先级高并不意味着线程一定会有限执行,只不过更高概率的获取 cpu 的资源。

getPriority() : 获取线程优先级
setPriority() : 设置线程优先级

MAX_PRIORITY : 10
NORM_PRIORITY : 5
MIN_PRIORITY : 1

13.6 线程的生命周期

在这里插入图片描述

13.7 线程同步

案例:模拟售票程序,实现三个窗口同时售票 100张
遇到问题:当多个窗口同时访问“共享数据”时,产生了无序、重复、负数等多线程安全问题
解决办法:将多个线程同时放的“共享数据”,包装起来视为一个整体,确保一次只有一个线程执行流访问共享数据,加锁。

Java 针对上述问题提供了相应的解决办法:

1.同步代码块

synchronized(同步监视器){
//需要访问共享数据
}

同步监视器:俗称“锁”,可以使用任意对象充当,但是必须保证多个线程持有同一把锁(同一个对象)

package com.atguigu.java.synchronized1;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Ticket implements Runnable{
	
	int tick = 100;
	
	Object obj = new Object();
	
	Lock l = new ReentrantLock();

	@Override
	public void run() {
		while(true){
			
			synchronized(obj){
				if(tick > 0){
					
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
					}
					
					System.out.println(Thread.currentThread().getName() + " 完成售票,余票为:" + --tick);
				}
			}

		}
	}
	
}

2.同步方法:只需在方法的声明处,加 synchronized 关键字

package com.atguigu.java.synchronized1;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Ticket implements Runnable{
	
	int tick = 100;
	
	Object obj = new Object();
	
	Lock l = new ReentrantLock();

	@Override
	public void run() {
		while(true){
			show();
		}
	}
	
	public synchronized void show(){
		if(tick > 0){
			
			try {
				Thread.sleep(200);
			} catch (InterruptedException e) {
			}
			
			System.out.println(Thread.currentThread().getName() + " 完成售票,余票为:" + --tick);
		}
	}

}

非静态同步方法的隐式锁为:this
静态同步方法的隐式锁为:Class 实例

3.同步锁 Lock
a)lock() 上锁
b)unlock() 释放锁,必须保证手动的释放锁,因此 unlock() 需要使用在 finally 中

package com.atguigu.java.synchronized1;

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class Ticket implements Runnable{
	
	int tick = 100;
	
	Object obj = new Object();
	
	Lock l = new ReentrantLock();

	@Override
	public void run() {
		while(true){			
			l.lock();
			
			try{
				if(tick > 0){
					
					try {
						Thread.sleep(200);
					} catch (InterruptedException e) {
					}
					
					System.out.println(Thread.currentThread().getName() + " 完成售票,余票为:" + --tick);
				}
			}finally{
				l.unlock(); //释放锁
			}
			

		}
	}
}

13.8 线程通信(线程交互)

当多个线程完成某些任务时,有时多个线程之间也需要一定的通信,即线程通信

线程通信的核心是 Object 类中提供的三个方法:
wait() : 使当前同步监视器上的线程进入等待状态,等待的同时释放锁
notify()/notifyAll() : 唤醒当前同步监视器上一个/所有等待状态的线程
注意:上述方法必须使用在 synchronized 中(Lock 同步锁的线程通信方式:Condition)

package com.atguigu.java.waitandnotify;

public class HelloThread implements Runnable{
	
	int i = 0;

	Object obj = new Object();
	
	@Override
	public void run() {
		while(true){
			
			synchronized (obj) {
				obj.notify();
				
				if(i <= 100){
					System.out.println(Thread.currentThread().getName() + ":" + i++);
				}
				
				try {
					obj.wait();
				} catch (InterruptedException e) {
				}
				
			}
			
		}
	}

}

【线程通信的经典案例】生产者消费者案例(必须会)

第15章 网络编程

15.1 InetAddress类的使用

代码:
/*
	 * 记住:开发的时候全部抓异常
	 */
	@Test
	public void test() throws Exception{
		//获取本地的地址
		InetAddress localHost = InetAddress.getLocalHost();
		
		System.out.println(localHost);
		//获取域名
		System.out.println(localHost.getHostName());
		//获取IP地址
		System.out.println(localHost.getHostAddress());
	}
	
	/*
	 * 获取网络地址
	 */
	@Test
	public void test2() throws Exception{
		
		InetAddress byName = InetAddress.getByName("www.baidu.com");
		
		System.out.println(byName);
		//获取域名
		System.out.println(byName.getHostName());
		//获取IP地址
		System.out.println(byName.getHostAddress());
	}

15.2 UDP

代码:

@Test
	public void client() throws Exception {
		// 创建DatagramSocket
		DatagramSocket socket = new DatagramSocket();

		byte[] bytes = "hello how are you".getBytes();
		
		/*
		 * bytes : 要发送的数据
		 * bytes.length : 发送数据的长度
		 * InetAddress.getLocalHost() : 服务器的地址
		 * 3399 : 服务器的端口号
		 */
		// 创建数据包、数据报
		DatagramPacket p = new DatagramPacket(bytes, bytes.length, 
				InetAddress.getLocalHost(), 3399);
		// 发送数据
		socket.send(p);

		// 关闭
		socket.close();
	}

	@Test
	public void server() throws Exception {
		// 创建DatagramSocket
		DatagramSocket socket = new DatagramSocket(3399);
		
		//将接收到的数据保存到数组中
		byte[] b = new byte[1024];
		
		DatagramPacket p = new DatagramPacket(b, b.length);
		//接收数据
		socket.receive(p ); //将接收到的数据都放入到数据包中
		/*
		 * p.getLength() : 接收到的数据的长度
		 */
		System.out.println(new String(b,0,p.getLength()));
		//关闭
		socket.close();
	}

15.3 TCP

代码:
/*
	 * Client
	 */
	@Test
	public void client() throws Exception, Exception{
		//创建一个Socket - 端口号必须和服务器的端口号一致
		Socket socket = new Socket(InetAddress.getLocalHost(), 4567);
		
		//发送数据
		OutputStream os = socket.getOutputStream();
		os.write("您好服务器我是客户端".getBytes());
		//通知服务器数据发送完毕
		socket.shutdownOutput();
		
		//接收服务器端的数据
		InputStream is = socket.getInputStream();
		byte[] b = new byte[100];
		int len = 0;
		while((len = is.read(b)) != -1){
			System.out.println("客户端 :" + new String(b,0,len));
		}
		//通知服务器数据接收完毕
		socket.shutdownInput();
		
		//关流
		os.close();
		is.close();
		socket.close();
	}
	
	/*
	 * Server
	 * 注意 : 服务器端只能开启一次,否则会报异常
	 */
	@Test
	public void Server() throws Exception{
		//创建一个ServerSocket
		ServerSocket serverSocket = new ServerSocket(4567);
		//接收客户端的请求
		Socket socket = serverSocket.accept();
		//接收客户端的数据
		InputStream is = socket.getInputStream();
		//读取数据
		byte[] b = new byte[100];
		int len = 0;
		while((len = is.read(b)) != -1){
			System.out.println("服务器:" + new String(b,0,len));
		}
		socket.shutdownInput();
		
		
		//给客户端发送数据
		OutputStream os = socket.getOutputStream();
		os.write("小样是你啊".getBytes());
		socket.shutdownOutput();
		
		//关流
		socket.close();
		os.close();
		serverSocket.close();
	}

15.4 URL

一 URL构成
在这里插入图片描述

二 构造器:
在这里插入图片描述

三 API
在这里插入图片描述
四 针对HTTP协议的URLConnection类

	URL url = new URL("http://192.168.10.150:8080/txt/123.txt");
		//获取一个连接
	URLConnection urlConnection = url.openConnection();
	HttpURLConnection conn = (HttpURLConnection) urlConnection;
    conn.connect(); //连接网络
	//获取响应码 - 如果成功返回200
	int responseCode = conn.getResponseCode(); 

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值