java笔记

 

-------------------------------历史、环境搭建------------------------
一、Java的发展史
...
Java发展方向: JavaSE(java语言核心基础) JavaME(通信) JavaEE(企业版)[记住]


二、 Java的特点【面试题目】
1. 简单性(相对c c++ 等)
2. 面向对象性
3. 跨平台(可以在不同的操作系统OS上进行执行)

三、Java运行机制(一次编译多次运行)【理解】
Java先编译后解释运行:Java源文件通过---》编译器---》字节码文件(.class)
二进制文件

---》通过解释器----》逐行的翻译并解释运行

四、环境搭建【理解】
1.名词解释
① JVM : JVM虚拟机,作用屏蔽不同操作系统之间的差异性。
② JRE :Java运行环境,JRE= JVM+ 解释器
③ JDK: Java工具包,JDK= JRE+ 编译器+类库+工具.


2. 环境变量
① JAVA_HOME:JDK的根目录
② Path:JDK的bin目录
③ ClassPath:代表类路径,指示JVM去哪找所使用的类
通常取值: . --->代表在当前目录下查找所需要的类。


使用 java 和 javac 指令在DOs窗口中验证环境变量配置成功。


五、第一个Java程序【开发应用重点】
1. Java中的程序源文件 以 .java结尾。
2. class 代码容器
3. main函数:主函数,代表程序的入口。一个类中最多只能定义一个main函数。
4. 编译:javac 源文件名.java
运行:java 类名

5. 一个源文件中可以定义多个类,但是类与类之间名字不能重名。
编译之后每一个类都会生成对应的.class 文件。

6. 一个类被 public 修饰称为公开、公共类。
注意:公开类的类名必须和源文件名一致;在一个源文件中最多可以定义一个公开类。

六、包(package)【应用重点】
1. 作用:包类似于文件夹,方便管理文件,对文件分门别类。
2. 语法:package 包名; // ----> package 包名1.包名2;
注意:一个源文件中最多只能定义一个package语句。
3. 位置:必须定义在源文件中第一行有效语句。

4. 带包编译和运行:
编译: javac -d . 源文件名.java
运行: java 包名.类名

七、良好的编程习惯【注意细节】
1. 格式习惯:
① 层级之间要有缩进,通常一个Tab键
② 一行只写一句代码

2. 良好的标识符习惯

① 硬性要求(语法要求) 【重点】
a. 标识符只能以数字、字母、下划线(_)、$组成,但是不能数字开头
b. Java中的标识符严格区分大小写
c. Java中的标识符没有长度限制
d. Java中的标识符不能以关键字、保留字(goto const)、特殊字符命名(true/false/null)


② 软性要求
a. 望文生义
b. 包名全小写
c. 变量名、方法名、函数名第一个单词的首字母小写,其余单词首字母都大写(驼峰命名法)
studentName / prodctorPrice /studentNameAndAge
d. 类名每一个单词的首字母均大写

3. 良好的注释习惯
① 单行注释: //注释的内容
② 多行注释: /*
1行
2行
n行
*/

注意:单行不能嵌套多行注释;但是多行注释可以嵌套单行注释。

③ 文档注释: /** [了解]
文档的注释内容....
*/

javadoc -d dos 源文件名.java



注意:注释内容不参与编译。


=========================变量、数据类型、表达式=====================
一、变量
1.概念:计算中的一块内存空间,是数据存储的基本单元。[理解]
2.变量:由数据类型、变量名、数值三部分组成。[应用]
3.定义:【应用重点】
① 声明变量:数据类型 变量名;
赋值: 变量名 = 值;

② 声明的同时赋值:
数据类型 变量名=值;

③ 同时定义多个同类型的变量:
数据类型 变量名1,变量名2=值,变量名3;

二、数据类型【基础重点】
1. 基本数据类型(原始数据类型、简单数据类型)(8种)
① 整数类型(1B = 1Byte = 8bit)
byte 1B -128 ~ 127
short 2B -32768~32767
int 4B -2147483648~2147483647
long 8B -922京~922京-1

注意:
a. 字面值:字面上可以给一个变量赋的值。
b. long类型的变量字面值后面需要加 L 或是 l(建议使用L区分 l 和数值1)

② 小数类型:
float 4B 单精度 精确为7位
double 8B 双精度 精确为16位

注意:
a. float 字面值后面必须加 f 或是 F
b. double字面值后面可以d 或是 D ,也可以不加。
c. float/double 采用科学计数法存储,近似值。


③ 字符类型
char 2B

注意:
a. 用''引起来的一个字符(字母+中国汉字+符号)
b. 采用正整数存储(0~65535):char c = 65;
c. 采用 unicode存储:char c3 ='\u0041';【了解】


④ 布尔类型
boolean 字面值只有 true/false

2. 引用数据类型(对象数据类型)
数组、类、集合、接口等都是引用数据类型、对象数据类型。

常用的引用类型:String---》字符串类型
a. 字符串的字面值:用 ""引起来的一个或是多个字符。
b. String s = "hello";

常用的转义字符:
\n : 换行
\t : 水平跳格
\\ : 代表反斜杠
\' : 代表单引号
\" : 代表双引号

注意:以上的字符必须是英文字符。

三、 数据类型之间的转换【应用重点】
1. 数据类型自动提升:(小数据类型的变量可以直接赋值给大数据类型的变量)
① byte -->short--->int ---> long --->float --->double
② char--->int --->long --->float-->double


2. 强制类型转换(大的数据类型的变量赋值给小的数据类型的变量)
① 语法:目标数据类型 变量名 = (目标数据类型)源数据类型的变量;
小数据类型 大数据类型
② 结果:【理解】
a. 小数类型强转为整数类型,则数据截断,保留整数部分。
b. 大的整数类型强转为小的整数类型,数据合适,则直接存储
c. 大的整数类型强转为小的整数类型,数据不合适,则截断
int i = 257;
byte b = (byte)i;//1

四、表达式
1. 概念:通常由 字面值、变量、运算符组成的一个式子,表达式通常有一个结果。【理解】
2. 如果两个数值或是变量参与运算时,结果类型如下:【重点】
① 如果有一个为double ,结果自动提升double;
② 如果没有double类型,有一个为float,则结果自动提升float;
③ 如果没有double/float类型,有一个为long,则结果自动提升为long;
④ 其余情况都是int类型。

面试题目:
byte b = 1;
b = b + 1;
以上程序编译是否通过?通过打印结果,否则解释原因。

五、运算符【应用重点】
1. 算数运算符: + - *(乘) /(除) %(取模、取余数)

注意: 如果 +两端有一个是String类型,则结果自动提升为String类型;
此时的 + 为 字符串拼接。


2. 赋值运算符:= += -= *= /=

注意:
① a +=1 ; ---> a = a+1;
② += 没有自动类型提升

面试题目:
① byte b1 = 1; ② byte b2 = 1;
b1 = b1 +1; b2+=1;

以上 ① 和 ② 是否编译通过,通过的写出变量的结果,否则解释原因。

3. ++(自增) --(自减) ---》一元运算符

① a++ : 先使用 a 的原始数据,再对a进行加1运算。(先使用后运算)
② ++a : 先将a进行加1运算,再使用a进行赋值运算。(先运算后使用)

4. 关系运算符(关系成立-true; 关系不成立-false)
== 等于
> 大于
>= 大于等于
< 小于
<= 小于等于
!= 不等于

结果类型为布尔类型的表达式为布尔表达式。

5. 逻辑运算符
&& : 逻辑与,两边布尔表达式的结果都为true,结果才为true.(短路)
|| : 逻辑或,两边只要有一个为true,结果就为 true.(短路)
& : 逻辑与 两边布尔表达式的结果都为true,结果才为true(非短路)
| : 逻辑或 两边只要有一个为true,结果就为 true(非短路)


面试题目:写出 && 和 & 的区别?

6. 条件运算符 (三目运算符)
① 语法: 布尔表达式 ? 表达式1 : 表达式2
② 原理:如果布尔表达式的结果为真,则执行表达式1,否则执行表达式2.


姓名:String
电话号: String
年龄: int
成绩:double
性别: boolean char String
地址: String
产品信息:String
数量:int
价格:double

六、扫描仪(Scanner)

1. 获取扫描仪:
java.util.Scanner sc = new java.util.Scanner(System.in);
2. 使用扫描仪:
① 输入一个整数: int a = sc.nextInt();
② 输入一个字符串: String s = sc.next();//---> String s = sc.nextLine();
③ 输入一个小数: double d = sc.nextDouble();
④ 输入一个字符:char c= sc.next().charAt(0);

3. 导包(import)
① 语法: import 包名1.包名2.类名;
import 包名1.包名2.*;
② 位置:package语句的后面
③ 注意:一个源文件中可以定义多个导包语句;
java.lang 中的内容可以直接使用,自动导入。


==============================分支结构========================
一、if分支【开发应用重点】
1. 基本结构
① 语法 :
if(布尔表达式){
//条件成立,执行的语句
}

② 执行原理:如果布尔表达式结果为 true,则执行if后面{}中的语句。

2. 基本结构2:
① 语法:
if(布尔表达式){
//语句1
}else{
//语句2...
}

② 执行原理:如果布尔表达式的结果为 true,则执行语句1,
否则(布尔表达式的结果为false)执行语句2。


3. 多重的if 结构
① 语法:
if(布尔表达式1){
//语句1
}else if(布尔表达式2){
//语句2
}else if(布尔表达式3){
//语句3
}else{
//语句4
}
② 原理:哪一个布尔表达式的结果为 true,则执行对应的{}中的语句;
如果都不满足,则执行else后面的语句。


4. 嵌套的if结构
① 语法:
if(布尔表达式){
if(布尔表达式){
//语句
}else if(布尔表达式){
//语句
}else{}
}else{
//外层条件不成立,则执行此语句....
}

② 原理:
先判断外层if 条件,如果条件满足,再判断内层if条件。

二、 switch...case结构
1. 语法:
switch(表达式){
case 值1: 语句1;break;
case 值2: 语句2;break;
case 值3: 语句3;break;
default:语句;break;
}

2. 注意:
① 表达式的结果类型: byte 、short、int 、char
JDK7.0版本之后,支持String类型【面试题目】


② break 可以中断、终止当前的switch...case结构

③ default没有位置的限制,建议后面的break;不省略.

④ case后面的值不允许重复

三、局部变量[应用+面试重点]

1. 概念:定义在函数/方法内部的变量。
2. 特点:
① 必须先赋值后使用
② 作用范围:从定义位置开始,到定义它的代码块结束。
③ 在重合的作用范围内,不允许出现重名的局部变量(避免命名冲突)


==========================循环结构=========================
一、 循环【理解】
1. 概念:通过某个条件,重复并且有规律的执行程序代码。
2. 组成:循环的初始数据 、 循环条件、循环体、循环变量的改变(递增、递减)


二、分类
1. while循环【重点】
① 语法:
while(循环条件/布尔表达式){
//循环体...
}

② 执行原理:先判断布尔表达式的结果是否为 true,如果为true,则执行循环体,
通过循环变量的改变,再 去判断条件是否成立(布尔表达式的结果
是否为true),成立,继续执行循环体,直到循环条件不满足(布尔表达式
的结果为false),跳出循环,继续执行循环结构后面的程序内容。

③ 特点:先判断,再执行,执行次数0~n次。

2. do...while循环

① 语法:
do{
//循环体
}while(循环条件/布尔表达式); //分号不能省略

② 原理:先执行循环体,再判断循环条件是否满足,如果结果为true,则继续执行循环体,
再次判断循环条件,直到循环条件不满足的情况下,跳出循环结构,继续执行
循环结构后面的内容。

③ 特点:先执行,再判断,执行次数 1~n次。


3. for循环【开发应用重点】
① 语法:
for(循环变量的初始值;循环条件;循环变量的改变){
// 循环体...
}

② 原理:先对循环变量进行初始化,接着会判断循环条件,如果条件满足(即结果为 true),
则执行循环体,然后对循环变量进行改变;继续判断循环条件...重复此过程,
直到循环条件不满足为止(布尔表达式的结果为false),循环结构终止。


③ 特点:先判断,再执行,执行的次数:0~n次。


总结:
① 循环次数明确,建议使用 for循环
② 循环次数不明确,建议使用 while循环。


三、 循环控制语句【开发应用重点】

1. break: 终止、跳出循环结构。
2. continue: 终止本次循环,从而进入下一次循环。

面试题目:写出 break 和 continue的区别?
break: ① 终止、跳出循环结构
② 用于终止结束 switch..case结构。
continue:只能应用于循环结构,终止本次的循环。


四、循环的嵌套
1. 概念:在一个循环结构中,再定义一个完整的循环结构。
2. 应用:可以用于图形的打印,通常用外层循环控制行数,内层循环控制列数。
3. 循环嵌套中 break 和 continue的应用:
break: 终止,结束本层循环。(如果break应用在内层循环中,结束内层循环)
continue: 终止、结束本次的循环,从而进入下一次。
4. 循环Lable标签:为循环做标记,可以指定操作的是内层循环还是外层循环。【了解】



总结:程序中分为:顺序结构、分支结构、循环结构。

=======================函数===========================
一、函数【理解】
1. 概念: 实现特定功能的一块代码组成的一个整体,可以通过名字被反复的使用。
2. 函数的使用流程:
① 函数的定义:
函数的声明:给特定的功能代码块起名字。
函数的实现:特定功能的代码组成的内容。

② 函数的调用:
想使用此功能时,通过名字使用特定的功能代码称为函数的调用。

3. 位置:函数定义在类以内,其他函数以外的位置(与main并列的位置)。

二、函数的定义【应用重点】
1. 语法:
public static 返回值类型 函数名(形参列表){
//函数的实现(函数的功能)
}

注意:
函数的声明:public static 返回值类型 函数名(形参列表)

注意: 返回值类型 、函数名、形参列表称为函数的三要素。

函数的实现:{}

2. 函数名:遵循标识符命名规范,望文生义,首单词的第一个字母小写,
其余单词的首字母大写(驼峰命名)

3. 参数:函数的调用者给函数传递的数据
① 语法:(数据类型1 变量名1,数据类型2 变量名2,数据类型3 变量名3)
---》形式参数列表:0~n个
② 范围:参数相当于函数内部的局部变量,可以直接利用参数名直接在函数内部使用。
③ 形式参数:约定了调用者传递的数据类型

4. 返回值类型:
① 无返回值: void --->代表函数没有返回值,但是也可以利用 return ;结束当前函数。

② 有返回值: 返回类型为 8种基本数据类型或是对象类型
函数有返回类型:必须要有return XXXX;语句。

return 作用:
① 将数据返回给调用者
② 结束当前函数

注意: return 可以应用在分支语句中,但是必须保证每一个分支都有return语句。

三、函数的调用【开发应用重点】
1. 无参函数的调用:函数名();
2. 有参调用:函数名(数据1,数据2,数据3);
注意:实际参数(实参):给形式参数赋值,
实际参数的个数、顺序、数据类型必须和形参完全一致。
3. 有返回值的函数调用:
数据类型 变量 = 函数名(实际参数);
注意:变量的数据类型取决于函数的返回值类型;
用于存储函数的返回值。

四、函数的作用:【理解】
1. 减少冗余代码
2. 提高代码可复用(重用)性
3. 提高代码的可维护性
4. 提高代码的结构化,利用分工合作。

五、函数的嵌套调用【理解】
1. 概念:被调函数的内部又调用其他函数。
2. 执行原理:程序执行过程中,如果遇到函数的调用,则优先执行被调函数内部的代码,
被调函数内部代码全部执行后,如果有返回值,需要带着返回值返回到调用
位置,程序才能继续往下执行未完成的代码。

 

六、递归调用【理解】
1. 概念:一个函数内部,自己调用了自己。
2. 应用:需要给递归设置一个出口,避免无穷递归。

注意:无穷递归最终的结果就是 栈溢出。


==============================数组==========================

一、数组
1. 概念:能够同时存储多个相同类型的数据,可以对多个变量进行统一操作。
2. 数组的使用流程:
① 声明:数据类型[] 数组名; --->指定数组中存储的数据类型及数组名

② 分配空间:数组名 = new 数据类型[长度]; ---》指定数组的长度

③ 往数组中存取元素

3. 数组的基本操作:【开发应用+基础重点】
① 数组中的下标范围:0~数组长度-1
② 数组中存储的数据称为数组的元素。
③ 对数组中元素的操作(存储元素、取元素)称为数组的访问。
④ 数组的访问: 数组名[下标];

⑤ 注意:如果访问数组时超出数组的范围,则编译OK,运行报错,错误信息:
java.lang.ArrayIndexOutOfBoundsException(下标越界异常)

⑥ 对数组中的元素进行一一访问称为数组的遍历。
for(int i=0;i<数组名.length;i++){
//通过 数组名[i]操作数组元素
}

注意:获取数组长度: 数组名.length

⑦ 数组具有默认值,默认值情况:
整数: 0
小数: 0.0
字符: 空字符(\u0000)
布尔: false
对象/引用:null

4. 数组的其他定义方式:【掌握】
① 声明的同时分配空间:
数据类型[] 数组名= new 数据类型[长度];

② 声明的同时初始化(显示初始化)
数据类型[] 数组名= new 数据类型[]{值1,值2,值3};
注意:[]中不允许指定数组的长度,长度由{}中数值的个数决定。

③ 声明的同时初始化(显示初始化)
数据类型[] 数组名= {值1,值2,值3};

注意:这种显示初始化方式的 声明和初始化必须一起进行。

错误写法:
int[] a;
a={1,6,3};

二、内存【理解】
1. 数组在内存的空间是连续的。
2. 数组名中存储的是数组在内存的首地址。
3. 数组每一个元素对应空间的地址:(寻址)
首地址+下标*数据类型字节数

4. 数组的下标从0开始:为了计算机寻址方便,从而提高效率。

5. 数组类型的变量相互赋值,传递是数组的首地址。
基本数据类型的变量相互赋值,传递是数值。


三、数组的扩容【理解】
1. 思想:
① 声明一个长度更大的数组,通常为原有数组长度的2倍
② 将原有数组中的内容一一复制到新数组中

2. 方式:
① 声明一个长度更大的数组
int[] a = {1,5,3,5};//原有数组
int[] b = new int[a.length*2];
将原有数组的内容一一复制到新数组中
for(int i=0;i b[i]=a[i];
}
将新数组的地址覆盖原有地址
a= b;

② 声明一个更大长度的数组
int[] a= {1,5,3};//原有数组
int[] b= new int[a.length*2];
将原有数组的内容一一复制到新数组中-->借助工具即可
System.arraycopy(a,0,b,0,a.length);

参数说明:
第一个参数:原有数组
第二个参数:复制起始下标
第三个参数:新数组名
第四个参数:存储起始下标
第五个参数:复制的长度
将新数组的地址覆盖原有地址
a= b;

③ 利用工具java.util.Arrays.copyOf(a,a.length*2);
参数说明:
第一个参数:原有数组名
第二个参数:新数组的长度

案例:
int[] a= {1,4,2};
a=java.util.Arrays.copyOf(a,a.length*2);

3. 应用场景:数组存储内容满了,不足以存储更多的数据时,需要将数组扩容。

四、可变长的参数【理解】
1. 概念:函数定义时,参数不固定,而是根据实际需求确定参数的个数。
2. 语法:
public static 返回值类型 函数名(数据类型... 变量名){
//函数的实现....
}

3. 应用:JVM遇到可变长参数时,自动转换为一个对应类型的数组。
在函数内部,将可变长参数当成数组应用即可。

4. 注意:一个函数中只能定义一个可变长的参数,而且必须定义在最后一个参数的位置。

5. 好处:使函数更加的通用、灵活。

五、数组排序【面试重点】
1. 冒泡排序:相邻的两个元素进行一一比较,每一轮的比较获取最大值(大值往后放)。(从小到大)
2. 选择排序:固定一个下标,和后面的下标对应的元素一一比较,每一轮获取最小数据.
3. JDK提供的排序工具:java.util.Arrays.sort(数组名); ---->快速排序


六、二维数组
1. 定义:
① 声明:数据类型[][] 数组名;
② 分配空间: 数组名 = new 数据类型[行数/高维][列数/低维];
2. 注意:
① 二位数组的行标和列表都是从0开始
② 访问二位数组的元素:数组名[行][列]
③ 二位数组同一维数组,具有默认值。
④ 获取二位数组的行数:数组名.length
获取二位数组的列数:数组名[行].length
⑤ 二位数组的遍历:
//外层循环控制行标
for(int i=0;i<数组名.length;i++){
//内层循环控制列标
for(int j=0;j<数组名[0].length;j++){
//通过 数组名[i][j]操作数组的元素
}
}
3. 其他定义方式
① 声明的同时分配空间:
数据类型[][] 数组名 = new 数据类型[行数][列数];
② 显示初始化:
数据类型[][] 数组名 = new 数据类型[][]{{值1,值2},{值3,值4},{值5,值6}};

③ 显示初始化:
数据类型[][] 数组名={{值1,值2},{值3,值4},{值5,值6}};

注意:赋值和声明必须一起定义。


4. 不规则的二位数组
① 概念:每一行的列数不相同。

② 定义方式:
第一种方式:
数据类型[][] 数组名= new 数据类型[行数][];
数组名[0]= new 数据类型[列数];//指定第0行对应列数
数组名[1]= new 数据类型[列数];//指定第1行对应列数
...
注意:二位数组可以只指定行数,但是不能仅仅指定列数。

例如:int[][] a= new int[][3];//错误的定义
int[][] a= new int[3][];//正确的定义方式
第二种方式:
数据类型[][] 数组名={{值1},{值2,值3,值4},{值5,值6}};

===============================面向对象==================================
一、对象【理解】
1. 概念:复杂的客观事物在 Java程序中的一种表现形式
(一切客观存在的事物都是对象)

2. 对象的组成:
① 对象的属性:代表对象有什么特征
② 对象的方法:代表对象有什么功能(能干什么)


3. 计算中,用类描述对象的属性和方法,需要描述对象有哪些属性和哪些方法。

二、类和对象的关系【理解】
1. 类是对象的模板
2. 对象是类的实例

三、类的组成【开发应用重点+基础语法】
1. 属性:描述对象有什么特征 ---》成员变量
① 语法:数据类型 属性名;
数据类型 属性名 = 值;

注意:声明和赋值必须一起进行。
String name;
name="lisi"; //错误的写法

② 属性:也称为成员变量
③ 位置:定义在类以内,方法以外
④ 注意:一个对象属性有很多个,程序设计过程中需要保留程序所关注的那部分属性即可。
⑤ 成员变量具有默认值:同数组
整数: 0
小数: 0.0
布尔: false
字符: 空字符('\u0000')
对象/引用类型: null
⑥ 作用范围:至少在本类中有效。
⑦ 命名冲突:在一个类中不允许有同名的属性(成员变量),
但是成员变量可以和局部变量命名相同,命名相同时,在局部变量所在方法
内部访问此变量时,局部变量优先被使用。


面试题目:成员变量和局部变量的区别????
成员变量 局部变量
位置: 类以内,方法以外 定义在方法以内
默认值: 具有默认值 没有默认值,必须先赋值再使用
作用范围:至少在本类中有效 从定义位置开始,到定义它的代码块结束
命名冲突:一个类中不能定义相同成员变量, 在重合的作用范围内,不允许命名冲突。
但是成员变量可以和局部变量命名
相同,如果命名一旦相同,则局部
变量优先被使用。


2. 方法:描述对象有什么功能
① 方法又称为成员方法。
② 位置:定义在类以内,其他方法以外的位置。
③ 语法:
I.函数:public static 返回值类型 函数名(形参列表){
//函数的实现....(函数体)
}

II.方法:public 返回值类型 方法名(形参列表){
//方法的实现
}

注意:方法不需要加 static ,具体内容后期讲解.....

④ 方法的定义:包括方法的声明和方法的实现
I. 方法的声明:代表对象具有功能
a. 组成:修饰符 返回值类型 方法名(形参列表)异常
b. 注意:一个方法的修饰符可以定义多个,而且没有先后顺序


II.方法的实现:代表对象如何实现对应的功能
a. 组成: {}


⑤ 方法的重载(overload)
a. 概念:在一个类中,定义多个相同名字的方法,但是形参不同。
b. 要求:
I. 方法名相同
II. 形参列表不同(个数、顺序、类型)
III. 方法的返回值类型、修饰符、异常没有要求

注意:两个方法只是参数名不同,不能构成方法的重载。

c. 使用:编译器在编译过程中,根据传递的实际参数,确定具体调用哪一个方法。

d. 注意:
i. 编译器匹配时,先精确匹配,如果没有匹配成功,则就近向上匹配;
ii. 匹配时避免混淆现象。

3. 构造方法(构造器)
① 概念:构造方法是特殊的方法。
② 位置:定义在类以内,方法以外。
③ 特点:
a. 构造方法的方法名必须和类名一致(包括大小写)
b. 构造方法没有返回值类型(连void都没有)
public 类名(){}
c. 构造方法允许重载
d. 构造方法不能手工的调用

④ 作用:
a. 用于创建对象
b. 通常给属性赋值

⑤ 注意:
a. 构造方法在创建对象时,JVM自动调用构造方法1次
b. 如果一个类中没有定义任何的构造方法,则JVM会自动提供一个默认 公开的、无参数的构造方法;
如果类中提供了有参数的构造方法,则JVM不再提供默认的构造方法。

四、对象的创建【开发应用重点】
1. 语法:
类名 对象名/变量名/引用名 = new 构造方法(实际参数);//根据实际参数决定调用哪一个构造方法

2. 使用:
① 属性:
赋值: 对象名.属性名 = 值;
调用: 对象名.属性名

② 方法:
对象名.方法名(实参);

五、对象的创建的过程【理解】
1. 分配空间:为所有的属性赋默认值
2. 初始化属性:为属性赋初始值(属性第二次赋值的机会)
3. 调用构造方法:为属性再次赋值(属性第三次赋值的机会)

六、this 的应用【开发应用重点】

1. this 的第一种应用:this.
① this 代表当前对象,类似于 "我",用于类中代表调用当前对象的属性或是方法
② this.属性/this.成员方法(实参):用在本类的成员方法或是构造方法中,代表调用
该对象的属性或是成员方法。

③ this. 通常可以省略,但是当成员变量和局部变量命名冲突时,必须使用 this. 区分
成员变量。

2. this 的第二种应用: this()
① this()用于该类中的构造方法中,代表调用本类的其他构造方法。
② this():代表调用无参数的构造方法
this(实参):代表调用本类的有参数的构造方法
③ 注意:this()/this(实参)必须定义在构造方法中的第一行有效语句
避免出现递归调用(回环调用)

七、引用[理解]
1. 概念:对象类型的变量称为引用。
2. 引用中存储的是对象在堆空间中的首地址。
3. 对象在内存中的空间相互独立。
4. 声明引用: 类名 引用名;
5. 引用之间可以相互赋值,传递的是对象在堆空间中的首地址。
基本数据类型的变量之间传递的是数值。

6. 注意:如果引用中存储的是 null(空地址),用此引用操作该对象中的属性或是成员方法,
则编译通过,运行报错,错误信息为:java.lang.NullPointerException(空指针异常)


=========================面向对象的三大特性====================
一、封装【重点】
1. 属性私有化:private修饰属性
① public : 修饰符,公开的、公共的
② private: 修饰符,私有的,被private 修饰的属性只能在本类中使用。

2. 为私有化的属性提供公开的get/set方法
① set方法:为私有的属性赋值
public void set属性名(属性的数据类型 变量名){
this.属性名 = 变量名;
}
注意:方法名 :set+属性名---》属性名首字母大写

② get方法:获取私有的属性值
public 属性的数据类型 get属性名(){
return this.属性名;
}
注意:方法名:get+属性名---》属性名首字母大写

3. 使用:
① 获取属性值:对象名.get属性名();
② 设置属性值:对象名.set属性名(实参);

小结:封装的要求
a. 所有的属性私有化:使用private修饰
b. 为私有化的属性提供公开的get/set方法

二、继承

1. 概念:【理解】
水杯 是一种 容器
钢笔 是一种 笔
狗 是一种 动物
A is-a B
① 继承体现的是类之间的一种 "is-a"关系;
A is-a B
A 继承 B
子类 继承 父类
② 继承是一种机制,通过继承,子类可以直接使用父类中属性和方法;
语法:class 子类 extends 父类类名{}

③ 程序设计过程中,不能强制使用继承机制,继承是类之间本身存在一种
"is-a"关系,不能人为、刻意创造。

2. 继承的好处:体现代码的可复用性和可扩展性。【理解】

3. 方法的覆盖(override)[方法的重写]【面试+应用重点】
① 概念:子类中定义了和父类完全一样的方法。

② 要求:
a. 子类的方法名、形参列表、返回值类型和父类完全一致
b. 子类的方法的访问修饰符 和 父类相同或是比父类更宽

③ 使用:如果子类覆盖了父类中的方法,则优先调用子类中自身的方法。
子类对象名.方法名(实参);//子类方法优先

④ 注意:
a. 子类中方法名、形参列表和父类相同,但是返回值不同,编译报错。
b. 子类中方法名、返回值类型和相同,但是形参类表不同,则编译通过,运行OK.---》方法的重载

⑤ 应用场景:父类中的方法实现部分不满足子类的需求时,子类可以覆盖父类中的方法。

4. 父类中的属性和方法由每一个子类的共性提取而确定。【理解】
父类是一般的、抽象的;
子类是特殊的、具体的。

5. Java的类之间的继承特点:Java中的类之间是单继承关系,即一个类只能有一个直接的父类,
但是可以多级继承(可以有多个间接的父类)。【理解+面试】

6. 子类通过继承可以使用父类的哪些内容,从构造方法、属性和成员方法考虑?
① 构造方法:子类不能继承父类中的构造方法【理解】
a. 构造方法的方法名必须和类名一致,父类和子类各有自己的类名
b. 子类中的内容比父类中的更多、更具体,所有具有更复杂的构造工作,
所有父类的构造方法不能满足子类的构造需求,则需要定义自己的
构造方法。

② 属性和成员方法:取决于访问修饰符【理解+面试+应用】
本类 同包 不同包的子类 其他(不同包的非子类)
private(私有的) : OK
default(默认的) : OK OK
protected(受保护的): OK OK OK
public (公开的): OK OK OK OK


4个访问修饰符修饰的属性和成员方法继承性如下:
private : 不可以继承
default: 同包子类可以继承
protected: 可以继承
public : 可以继承

注意:
a. 4个访问修饰符都可以修饰 属性、成员方法、构造方法;
b. 只有public 和 default修饰类

7.创建对象的过程(具有继承关系)【理解】
① 分配空间(本类+所有父类):为所有属性赋默认值

② 递归的创建父类对象(JVM自动完成):
a. 初始化父类的属性:为父类属性赋初值(机会)
b. 调用父类的构造方法:为父类的属性第三次赋值(机会)

③ 初始化子类的属性:为子类的属性赋初值

④ 调用子类的构造方法:为子类的属性第三次赋值

8. super的应用【开发应用重点】
① 第一种应用:super()
a. super()/super(实参):用于子类的构造方法中,代表创建父类对象时,指示JVM利用哪一个构造方法
完成父类对象的创建;而且必须放在子类构造方法中第一行有效语句。
b. 注意:
I. 如果子类构造方法中的第一行没有定义super()/super(实参),则JVM会默认在第一行添加super()
II.一个构造方法中不能同时定义 this()/this(实参) 和 super()/super(实参)
III. 如果一个子类的构造方法第一行语句定义了this()/this(实参),则JVM会放弃在当前构造
方法中查找 super()/super(实参),转向this()/this(实参)所指向的构造方法的第一行去
查找 super()/super(实参)

② 第二种应用:super.
a. super. 用在子类的构造方法或是成员方法中,代表调用父类的属性或是父类的成员方法
b. super.属性名:代表访问父类的属性
super.方法名(实参); -->代表调用父类的成员方法

三、多态

1. 概念:【理解+开发应用重点】
① 多态:父类型的引用指向不同子类型的对象。

语法:父类类名 引用名 = new 子类类名(实参);
引用 对象
父类型 子类型
主观类型 客观实际类型

② 用父类型的引用调用属性和方法,只能调用父类中定义的属性和方法。[编译过程检查]
③ 运行时,JVM会自动检测子类是否覆盖父类中方法,如果覆盖,则优先调用覆盖
后的方法,否则直接调用父类中的方法。[运行时]

 

2. 引用之间的转换【理解+开发应用】
① 父类型的引用 赋值 给子类型的引用 ---》需要强制类型转换
大类型 小类型

a. 语法:子类类名 对象名 = (子类类名)父类型的引用;
Animal a = new Dog();
Dog d = (Dog)a;

b. 结果:编译一定通过,但是如果引用中存储的实际对象类型和要转换的类型相匹配,
则运行通过,如果引用中存储的实际对象类型和要转换的类型不匹配,则运行
报错,错误信息:java.lang.ClassCastException(类型转换异常)

c. 如何避免类型转换异常?
I. 利用 instanceof避免类型转换异常
-->语法:引用名 instanceof 类名
-->作用:判断引用中存储的对象类型是否兼容于后面的类型,
兼容-true;不兼容-false.
-->应用:先利用instanceof进行判断,再进行引用之间的转换。

② 子类型的引用 赋值 父类型的引用 ----》直接赋值(多态的应用)
小类型 大类型
例如:Dog d = new Dog();
Animal a= d;


③ 如果转换双方不存在继承关系,则不能相互转换,编译报错。
例如:Animal a= new Dog();
Person p = (Person)a;

3. 多态的应用【理解】
① 多态用在数组上:本类型+所有子类型的对象 都可以作为数组元素存储。
② 多态用在形参上:本类型+所有子类型的对象 都可以作为实际参数传递。【开发应用】
③ 多态用在返回值上:本类型+所有的子类型的对象 都可以作为返回值返回。【开发应用】


4. 多态的好处:屏蔽了不同子类之间的差异性,对所有子类进行统一操作,让程序
更加的通用和灵活。 【理解】



================================三个修饰符===============================
一、abstract(抽象的)

1. abstract 可以修饰符类
① 抽象类:被abstract修饰的类。
② 不能单独创建对象,但是可以声明引用
③ 抽象类有构造方法,但是构造方法不是用于自身单独创建对象的;
而是创建子类对象过程中先完成父类对象的创建时使用。

2. abstract可以修饰方法
① 抽象方法:被asbtract修饰的方法
② 抽象方法特点:只有方法的声明,没有方法的实现(连{}都没有)
访问修饰符 abstract 返回值类型 方法名(形参列表);
注意:访问修饰符 和 abstract没有位置先后。

③ 抽象方法只能定义在抽象类中

注意:如果一个类继承抽象类,子类不想成为抽象类,则必须实现(覆盖)抽象类(父类)中
所有的抽象方法。

3. 抽象的应用:强制使用多态

二、static (静态的)【重点】

1. static可以修饰属性
① 被static 修饰的属性称为静态属性、类变量、静态变量
② 语法:访问修饰符 static 属性名;
访问修饰符 static 属性名 = 值;

注意:访问修饰符 和 static 没有先后顺序。

③ 特点:静态变量和创建多少对象无关,静态变量为类变量,全类共有的属性/变量。
④ 使用:类名.静态属性名 ----》建议使用
对象名.静态属性名


2. static可以修饰方法:
① 被static修饰的方法称为静态方法。
② 位置:定义在类以内,其他方法以外,同时被static修饰。
③ 语法:访问修饰符 static 返回值类型 方法名(形参列表){}
注意:访问修饰符 和 static没有先后之分。

④ 使用:类名.静态方法名(实参); ----》建议使用
对象名.静态方法名("实参");


⑤ 注意:
a. 静态方法中只能直接访问本类的静态成员(静态属性和静态方法)
静态方法中不能直接访问本类的非静态的成员(实例变量和成员方法)

b. 静态方法中不能使用 this / super 关键字

c. 静态方法可以被继承,静态方法可以被静态方法覆盖,但是没有多态的应用


思考:System.out.println(); 实现原理??????(包、类、属性、方法等)

System: 类
out: 静态属性 --》对象类型的属性(引用) --->从源码获取:out同被final修饰
println():方法 --》out属性对应的类型中的方法


3. static可以修饰初始化代码块

初始化代码块:动态代码块【了解】
① 位置:定义在类以内,方法以外的 {}
② 作用:在创建对象时,按照和实例变量定义的先后顺序完成实例变量的初始化工作。

静态初始化代码块【重要】
① 位置:定义在类以内,方法以外,同时被static修饰的{}
② 作用:在类加载时,按照和静态属性定义的先后顺序完成静态属性的初始化工作。
③ 类加载:
I. 概念:当JVM第一次使用一个类时,通过classPath找到该类对应的.class文件,
读取该类信息(包名、类名、属性、方法、父类等),将读取的信息保存
到JVM内存中,类加载只进行一次。

II. 类加载时机:
a. 第一次创建该类对象:先进行类加载,在完成对象的创建
b. 第一次访问该类的静态成员(静态属性和静态方法)
c. 子类类加载会先加载其父类:
--->第一次创建子类对象:先进行加载(父类+子类),再进行对象创建(父类+子类)

--->第一次访问子类的静态成员(静态属性和静态方法)


注意:只是声明引用不会进行类加载。

对象创建的过程总结:
先类加载:
先加载父类:
静态属性初始化+静态代码块
再加载子类:
子类的静态属性初始化+子类的静态代码块
再创建对象:
分配空间(子类+父类)
先创建父类对象:
父类属性的初始化:定义部分+动态代码块
调用父类的构造方法
再创建子类对象:
子类属性的初始化:定义部分+子类的动态代码块
调用子类的构造方法



三、final (最终的、最后的)
1. final 可以修饰变量(局部变量、实例变量、静态变量)

特点:final修饰的变量是作用范围内的常量,只允许一次赋值,不允许修改。

① final修饰的实例变量没有默认值,赋值的机会:
a. 声明的同时对其初始化
b. 利用构造方法对其初始化:必须保证每一个构造方法都对其初始化

② final 修饰的静态变量没有默认值,赋值的机会:
a. 声明的同时对其初始化
b. 在静态代码块中对其初始化

注意:如果 引用被 final 修饰,代表引用中存储的对象不能改变。

2. final 可以修饰方法:可以被继承,但是不能被覆盖

3. final 可以修饰类:不能被继承(即没有子类)
例如: String Math System

=========================接口============================
一、概念
1. 接口是一种标准,是接口的实现者和接口的使用者都必须遵循的约定。【理解】
2. 语法:【重点】
① 关键字: interface
interface 接口名{}

② 接口不能创建对象,但是可以声明引用

③ 接口中没有构造方法

④ 接口中所有的属性都是 公开、静态、常量(默认被 public static final 修饰)

⑤ 接口中所有的方法都是 公开、抽象方法(默认被 public abstract修饰)

注意:接口不是类。

二、实现类【重点】
1. 语法:
class 类名 implements 接口名{}

2. 注意:实现类如果不想成为抽象类,必须实现(覆盖)接口中所有的方法;
而且实现类实现接口中的方法时,访问修饰符必须为 public .


3. 应用:接口名 引用= new 实现类类名(实参); //---》多态的应用


三、接口的继承性【重点】

1. 接口可以继承多个父接口,即Java中接口是多继承。
语法: interface 接口名 extends 父接口1,父接口2{}

2. 一个类同时可以实现多个接口:
语法: class 类名 impelements 接口名1,接口名2{}

注意: 实现类不想成为抽象类,则需要实现所有接口中的所有方法。


3. 一个类实现多个接口的同时可以继承一个父类,但是必须先先继承再写实现

语法: class 类名 extends 父类 implements 接口1,接口2{}


四、接口多继承的影响【了解】
如果强转双方有一方为接口类型,则编译一定通过,但是运行时JVM需要判断
引用中存储的实际对象类型是否兼容于要转换的类型,兼容-运行通过;
不兼容-运行报错,错误信息: java.lang.ClassCastException(类型转换异常)


五、接口的好处【理解】

1. 扩充子类的能力
① Java中类是单继承,当父类中的方法不足以满足子类的功能展现需求时,
可以通过接口扩充子类的能力。

② 主要的功能通常定义在父类中;次要的功能通常定义在接口中。


2. 解耦和:降低各模块之间的耦合度
接口定义之后,将接口的实现者和接口的使用者进行分离,
利用多态技术,降低各模块之间的耦合度,从而达到各模块
之间的弱耦合性。


六、接口的回调【理解】

接口定义之后,先有接口的使用者,再有接口的实现者。
注意:一旦提及接口的回调,开发时需要关注的是接口的实现部分。

重点面试题目:写出抽象类 和 接口的区别?

抽象类 接口

关键字 abstract class interface
属性 实例变量、静态变量 公开、静态、常量(publilc static final修饰)
方法 非抽象方法+抽象方法 公开抽象方法(public abstract修饰)
构造方法 有构造方法 没有构造方法
继承关系 单继承 多继承


相同点:
① 只能声明引用,不能创建对象
② 编译之后,都可以生成对应 .class文件

==================================内部类============================
一、概念
1. 内部类:在一个类的内部定义了一个完整的类。
//外部类
class Outer{
//内部类
class Inner{}
}

2. 内部类编译之后会生成独立的 .class文件,文件名 Outer$Inner.class

3. 内部类可以直接访问外部类的私有成员(属性和方法)

二、分类

1. 内部类的分类:成员内部类、静态内部类、局部内部类、匿名内部类

2. 成员内部类(类比实例变量)【了解】
① 位置:定义在类以内,方法以外
② 创建成员内部类的对象必须依赖于外部类的对象:
Outer o = new Outer();
Outer.Inner inner = o.new Inner();
③ 外部类类名.this:指向外部类的当前对象
外部类的类名.this.属性名 : 访问外部类的属性

④ 成员内部类中不允许定义静态的成员(属性和方法)


3. 静态内部类(类比静态变量)【了解】
① 位置:定义在类以内,方法以外,同时被 static 修饰

② 静态内部类中可以定义实例变量和静态变量

③ 创建静态内部类的对象需要依赖于外部类的类名:
Outer.Inner i = new Outer.Inner();

④ 访问静态内部类中静态成员时:
外部类的类名.静态内部类的类名.静态属性名
外部类的类名.静态内部类的类名.静态方法名(实参);


4. 局部内部类(类比局部变量)【练习语法】
① 位置:定义方法以内
② 创建局部内部类的对象,必须在定义它的方法内部进行对象创建。
③ 注意:局部内部类中可以访问它所在方法内部中的局部变量,但是要求
局部变量必须加 final(Java语法规定)

JDK8.0默认将局部内部类访问的局部变量前面加 final ---》语法糖



5. 匿名内部类【语法重点】
① 匿名内部类是特殊的局部内部类
② 匿名内部类定义时必须实现一个接口或是继承一个父类
③ 基于一个匿名内部类只能创建该类的一个对象,并且匿名内部类的
定义和对象的创建一起完成


Interface IA{
void method();
}

IA ia=new IA(){
public void method(){
System.out.println("方法的实现....");
}
};

④ 好处:让代码更加简洁,从而减少代码量,而且使程序员的编程思路更连续。
缺点:可读性差,维护低。


============================第三阶段 API======================================

----------------------------常用类------------------------
一、Object类

1. 概念:【理解】
① Object是所有类的父类、根类、超类,位于 java.lang包中。
所有类是Object子类(直接的或是间接的)

② Object类型的引用可以存储任意类型的对象。

③ Object中定义的方法是所有类都具备的。

2. 常用的方法:

① getClass():返回引用中存储的实际对象类型。【理解】

开发实际应用:用于判断两个引用中存储的实际对象类型是否一致,
一致-true; 不一致-false.

Animal a1 = new Dog();
Animal a2 = new Cat();
System.out.println(a1.getClass() == a2.getClass());

② int hashCode(): 将对象的十六进制的地址转换为 十进制的整数而获取的结果。【理解】
不同的对象有不同的地址,从而不同的对象获取不同的哈希码值。

③ String toString():返回该对象的字符串表现形式。【重点】
toString方法作用:展示对象的信息。
覆盖的原则:将对象的所有的属性拼凑成一个 String类型的结果作为返回值返回。
public String toString(){
return "name="+name+",age="+age;
}

④ boolean equals(Object obj):比较两个对象的内容是否相同。【重点】

① ==的应用:
a. 如果 == 两端是基本数据类型的变量,则比较变量中存储的值是否相同
b. 如果 == 两端是引用数据类型的变量,则比较引用中存储的地址是否相同。

==开发中的应用:【重点】
通常用 == 判断两个引用是否指向同一个对象。
引用名1 == 引用名2 -->true,指向同一个对象
-->false,指向不同的对象


② equals方法的覆盖的原则:
public boolean equals(Object o){
//1.自反性:判断 this 和 o 是否指向同一个对象
if(this == o){
return true;
}
//2.判断 o是否为 null
if(o==null){
return false;
}
//3.判断两个引用中存储的实际对象类型是否一致
if(this.getClass() != o.getClass()){
return false;
}
//4. 强制类型转换---》为下一步准备
Student s= (Student)o;
//5. 将属性一一比较:基本数据类型(==) 引用 (equals)
if(this.age==s.age && this.name.equals(s.name)){
return true;
}else{
return false;
}
}

面试重点: == 和 equals的区别?


⑤ void finalize():垃圾回收器在回收垃圾对象时调用的方法。【面试重点+性能调优】

a. 垃圾对象:没有任何引用指向的对象。
b. 垃圾回收的目的:清除垃圾对象,释放JVM内存空间。
c. 垃圾回收器(gc/GC): JVM用于回收垃圾对象。

d. 垃圾回收的时机:
I. 自动回收机制:当JVM内存被占用满时,不能再为新创建的对象开辟空间,
JVM会自动启动垃圾回收器,将所有的垃圾对象一次性
回收,在垃圾回收器回收垃圾对象时,JVM会自动的调用
finalize方法。


II.手动回收机制:通过 System.gc(),通知垃圾回收器回收垃圾对象,
如果 GC处于繁忙,则暂不回收;如果 GC空闲,则
回收垃圾对象。


面试题目:写出 final 和 finalize?

分析: final修饰符,可以用于修饰类、方法、变量
final修饰的类:不能被继承,没有子类
final修饰的方法:可以被继承,不能被覆盖
final修饰的变量:作用范围内的常量。

finalize:方法签名,用于JVM垃圾回收器回收垃圾对象的时候调用的方法。

二、包装类(位于 java.lang 中)
1. 概念:基本数据类型对应的对象类型。
2. 基本数据-包装类型【重点】

基本数据类型 包装类
byte Byte
short Short
int Integer
long Long
float Float
double Double
char Character
boolean Boolean

3. 数据类型之间的转换(以Ineger为例):
① int ---> Integer
int a= 12;
a. Integer i1 = new Integer(a);
b. Integer i2 = Integer.valueOf(a);//静态方法

② Integer --> int
int a2=i1.intValue();

③ String --->Integer
a. Integer i3 = new Integer("123");
b. Integer i4 = Integer.valueOf("123");//静态方法

④ Integer--->String
a. String s1 = i4.toString();
b. String s2 = i4+"";

⑤ String --> int 【开发应用重点】
int a = Integer.parseInt("123");//静态方法
注意:String转换为 int/Integer类型时,要转换的字符串必须是纯数字的,
否则运行报错,错误信息为:java.lang.NumberFormatException
(数字格式转换异常)

⑥ int ---> String

4. 自动的装箱和拆箱(JDK5.0 版本之后)【理解】

① 概念:基本数据类型和对象类型之间的自动转换称为自动的装箱、拆箱。

② 装箱:基本数据类型转换为对象类型。
Integer i1 = 12;//int--->Integer

拆箱:对象类型转换为基本数据类型。
int a = i1;//Integer-->int



注意:① 自动的装箱默认调用 valueOf方法。(int --->Integer)
② Java为了提高包装效率,对常用的数据进行预先包装,常用数据范围为
-128~127,将包装的结果存储在JVM内存中,称为缓冲区。(常量池)

面试题目:写出以下程序的打印输出结果。
Integer i1 = 126;
Integer i2 = 126;
System.out.println(i1 == i2);//true

Integer i3 = 129;
Integer i4 = 129;
System.out.println(i3 == i4);//false

Integer i5 = new Integer(125);
Integer i6 = new Integer(125);
System.out.println(i5==i6);//false
System.out.println(i5.equals(i6));//true,Integer类中覆盖了 equals方法


5. 包装类开发中的应用【重点】
① 作用:开发中可以用包装类型区分有效数据和无效数据,例如: 0 和 null
0.0 和 null

② 场景:属性定义时,由以前的基本数据类型 换成对应的包装类型。
class Student{
String name;
Integer age;
Double score;
}


三、String 类

1. 创建字符对象:【面试题目】
① String s1 ="hello";//只会在串池中产生一个对象,供其他字符串共享
② String s2 = new String("world");//创建两个对象,一个在串池中,一个在堆空间中
注意:如果串池中已经存在该字符串,则无需在串池中创建。


2. 常用方法:
① char charAt(int index):根据指定下标获取对应的字符。
注意:字符串底层本质为 字符类型的数组,所有下标的范围是:0 ~ 字符串的长度-1

② boolean contains(String s):判断 s是否包含在当前字符串中,包含——true;不包含-false。

③ boolean equals(String s):判断两个字符串内容是否相同。


④ int length():获取字符串的长度

注意:获取数组的长度:数组名.length

开发中的应用:遍历字符串
for(int i=0;i //根据下标获取对应的字符
char c = str.charAt(i);
//操作每一个字符
....
}

⑤ String trim(): 去除字符串的前后空格。
开发中的应用:int age = Integer.parseInt(ageString.trim());

3. String不可变长的字符串

① 字符串为字面值的常量,一旦创建长度不可改变,如果对其操作,需要拷贝
一个副文本,在副文本的基础上进行操作,例如字符串的拼接。

② 思考: String s = "a"+"b"+"c"; 产生几个对象?【面试题目】
分析:只会产生一个对象(abc-->串池中),此拼接过程 "+"两端都是字符串常量,
所有编译器在编译时,将拼接结果直接翻译为 "abc"--->编译期可知。


4. 可变长的字符串(位于java.lang 包中)
① StringBuffer: JDK1.0版本,线程安全,运行效率慢。
StringBuilder: JDK5.0版本,线程不安全,运行效率快。

② 常用的构造方法:
a. StringBuilder()
b. StringBuilder(String str)

③ 常用的方法:
append(String str):字符的拼接。

注意:StringBuilder/StringBuffer 在字符串拼接效率上 比 String 的字符串的拼接效率高。
可以利用 toString方法将StringBuilder转换为 String类型。


面试题目:① 写出 StringBuilder 和 StringBuffer的区别?
② 写出 String 和 StringBuider的区别?

四、BigDecimal类【精确度要求高的项目时应用】
1. 位置:位于 java.math包中
2. 作用:精确地表示小数,解决小数的计算问题。
3. 常用的构造方法:
public BigDecimal(String str)

4. 常用的方法:
① BigDecimal r1 = bd1.add(bd2);//加法
② BigDecimal r2 = bd1.subtract(bd2);//减法
③ BigDecimal r3 = bd1.multiply(bd2);//乘法
④ BigDecimal r4 = bd1.divide(bd2,3,BigDecimal.ROUND_HALF_UP);//除法
参数:
第一个参数:分母
第二个参数:代表精确到小数点后第几位
第三个参数:取舍模式,BigDecimal.ROUND_HALF_UP(四舍五入)




===========================集合===========================
一、概念【理解】
1. 集合是一种工具类,也是一种容器,用于存储多个对象。
2. 所有的集合的接口和实现类都位于 Java.util包中。
3. 学习集合从以下4点学习:
① 集合接口的特点
② 集合接口的功能方法
③ 集合接口的实现类
④ 集合对应元素遍历方式

二、Collection 集合 体系

1. 父接口:Collection
① 特点:用于存储多个 Object类型的对象
② 方法:
a. add(Object o):往集合中添加一个元素,成功-true,否则-false.【开发重点】
b. boolean remove(Object o):将指定的对象从当前集合中删除、移除,删除成功-true;否则-false.
c. int size():获取集合中元素的个数。【重点】

③ 实现类:没有直接的实现类。
④ 遍历:详见子接口实现类对应的遍历方式。


2. 子接口:List
① 特点:用于存储多个 Object类型的对象;有序、有下标,元素可以重复。
List集合下标的范围:0 ~ size-1 (集合中有效元素的个数-1)

② 方法:部分方法继承于 父接口Collection,部分方法是自身独有的。
a. add(int index,Object o):将对象o存储到指定的下标位置。
b. Object get(int index):根据下标,获取指定下标的元素。【重点】
c. Object remove(int index):根据下标删除元素,被删除的元素作为返回值返回。
d. Object set(int index,Object o):根据指定下标修改对应元素的内容,被修改的元素
作为返回值返回。

③ 实现类:ArrayList【重点】
a. ArrayList:底层用 数组实现, 查询效率高,增删慢。
JDK2.0 版本,线程不安全,运行效率快。

b. Vector:底层用 数组实现,查询效率高,增删慢。
JDK1.0版本,线程安全,运行效率低。

c. LinkedList: 底层用链表实现,查询效率慢,增删效率快。
线程不安全,运行效率快。


面试题目:写出 ArrayList 、Vector和 LinkedList的区别?【重点】

④ 遍历:
a. 下标遍历:
for(int i=0;i<集合名.size();i++){
//根据下标获取对应的元素
Object o = 集合名.get(i);
//操作元素
....
}



b. forEach遍历
for(数据类型 变量名:要遍历的集合名){
//利用变量名操作集合中的每一个元素
...
}
注意:数据类型取决于集合中存储的对象类型。

--------------forEach底层实现原理---》迭代器遍历---------------【理解即可+面试】
迭代器的遍历:
① 通过iterator()方法获取迭代器对象
Iterator it = list.iterator();//获取迭代器对象

② 迭代器中常用的方法:
a. hasNext():判断迭代器中是否含有元素,含有-true;否则-false.
b. next(): 每次调用此方法,会将迭代器的指针后移一个元素的位置,
跨过去的元素,作为返回值返回。

③ 迭代器遍历:
Iterator it = list.iterator();//获取迭代器对象
while(it.hasNext()){
String s= it.next();
//利用 s操作集合中的元素
}

3. 泛型

1). 泛型集合:安全性的集合,泛型可以强制约束集合中的数据元素类型必须统一。【重点】
集合类名<数据类型> 集合名 = new 集合类名<数据类型>();

注意:集合一旦加了泛型,则集合中的元素必须和泛型的数据类型一致。

2). 泛型类:【理解】
① 语法:
class 类名<泛型标识1,泛型标识2>{
//在类中,直接使用泛型标识作为数据类型使用即可
}

注意:通常使用 T/E/K/V等作为泛型的标识符。

② 使用:
在创建对象时,需要指定泛型的数据类型:
类名<具体数据类型> 引用名 = new 类名<具体的数据类型>();

③ 注意:
a. 如果创建对象时,没有指定具体的泛型类型,则默认为 Object类型。
b. 基本数据类型不能指定泛型数据类型,必要时,需要使用基本数据类型
对应包装类型

3). 泛型接口【理解】
① 语法:
interface 接口名<泛型标识1,泛型标识2>{
//通过泛型标识在接口中作为数据类型使用即可
}

② 实现类:
第一种方式:
class 类名 implements 接口名<具体的数据类型>{
//实现接口中的方法时,直接使用具体的数据类型即可
}

第二种方式:
class 类名<泛型标识> implements 接口名<泛型标识>{
//在实现类中,实现接口中的方式,需要继续使用泛型标识
}

4). 好处:使代码更加灵活,通用。

5). 通配符:? --->泛型类型的引用之间传递时,通常用通配符进行传递。【了解】
a. 设置上限:
语法:

使用:传递的泛型类型必须是指定的类型的本类型或是其子类型。

b. 设置下限:
语法:
使用:传递的泛型类型必须是指定类型的本类型或是其父类型;
也可以是 Object类型。

4. Collections工具类(位于 java.util包中)

1). Collections 是Java中提供的操作集合元素的工具类,类中提供大量的功能方法,
为了方便使用,功能方法 被 static 修饰,使用时 用
Collections.静态方法名(实参);

2). 常用方法:【了解】
① public static void reverse(List list):将集合中元素进行倒置。
② public static void shuffle(List list):将集合中元素进行随机显示。
③ public static void sort(List list):将集合中元素进行排序,但是集合中如果存储的
是自定义类型的对象,对应的类必须实现 java.lang.Comparable接口,
同时实现接口中的compareTo方法,指定排序的规则。


面试题目:写出 Collection 和 Collections的区别?

Collection是Java中Collection集合体系中的根接口,它有直接的
子接口 List 和 Set.

Collections是Java中操作集合元素的工具类,其中提供大量的静态功能方法。

5. 子接口:Set
① 特点:存储任意类型的Object类型的对象,无序、无下标、元素内容不允许重复。【重点】

② 方法:Set中的方法都是继承于父接口 Collection .
a. 往集合中添加元素: add(Object o);【重点】


③ 实现类:HashSet【重点】
自定义类型的对象存储在 HashSet中,为了保证元素内容不重复,需要做到以下两点:
a. 覆盖 hashCode方法
原则:覆盖 hashCode方法时,必须保证内容相同的对象返回相同 哈希码值;
为了提高效率,尽可能保证内容不同的对象返回不同哈希码值。

规则:将所有的属性拼凑成一个 int 整数作为返回值进行返回。
public int hashCode(){
return this.name.hashCode()+this.age.hashCode()+(int)score;
}

注意:如果属性中基本数据类型采用的是对应包装类型,则需要使用 属性名.hashCode();


b. 覆盖 equals方法
原则:内容相同的对象返回 true,拒绝添加到 HashSet集合中。



注意:一个元素往 HashSet集合中存储时,首先调用 hsahCode方法,
根据 hashCode % 存储数组长度 获取存储下标;如果两个对象
往同一个下标存储时,此时JVM才会调用该对象的equals方法,判断
两个对象的内容是否一致,eauqls方法的返回结果为false,代表
内容不同,则采用链表形式继续存储;eauqls方法的返回值结果为
true,则代表对象的内容相同,则拒绝添加。【面试重点】


面试+开发应用重点: HashSet集合如何保证元素内容不重复?????

④ 遍历:
a. forEach遍历(底层迭代器遍历)

 

⑤ SortedSet--->是 Set的子接口
a. 特点:无序、无下标、元素内容不允许重复。可以根据集合元素内容进行排序。
b. 实现类: TreeSet 【面试题目】

自定类型的对象存储在TreeSet中,保证元素不重复,取决于compareTo方法
返回值,如果返回为 0,则代表为内容相同元素,则拒绝添加到TreeSet中。

c. 遍历方式:forEach(底层迭代器遍历)


⑥ 扩充的Set实现类:LinkedHashSet
a. 特点:有序存储,无下标,元素内容不允许重复的。
是HashSet直接的子类。

b. LinkedHashSet维护自身元素内容不重复要求和 HashSet相同,
需要自定义类型的对象对应的类,覆盖 hashCode方法 和 equals方法。

c. 遍历方式: forEach(底层迭代器遍历)


三、Map集合集合体系

1. 根接口:Map

① 特点:【了解+面试】
a. Map存储任意的键值对(key-value)
b. 键:无序、无下标、元素不允许重复(唯一性)
c. 值:无序、无下标、元素允许重复

② 方法:
a. V put(K key,V value):往Map集合中存储一个键值对,如果键在Map中不存在,则直接存储,
返回值为 null ; 如果 键在Map中已经存在,则新的value替换原有
的value数据,则被替换的value作为返回值返回。【重点】

b. V remove(K key):根据键删除Map中对应的键值对,被删除的值作为返回值返回。

c. V get(K key):根据键获取对应的值。【重点】

d. boolean containsKey(K key):判断某一个键在Map中是否存在,存在-true;不存在—false.

e. boolean containsValue(V value):判断某一个值在Map中是否存在,存在-true;不存在-false.

f. int size():获取Map集合中键值对的个数。

③ 实现类:HashMap
a. HashMap : JDK1.2版本,线程不安全,运行效率快。
可以允许null作为 key/value.
如果 null 作为键,只允许一个键为 null;
如果 null 作为值,没有个数限制。

b. Hashtable : JDK1.0 版本,线程安全,运行效率慢。
不允许 null作为 key/value.

c. Properties : 是 Hashtable 子类,要求键和值都是 String类型。
作用:通常用于读取配置文件。【后期技术应用】

d. TreeMap : 实现SortedMap接口,可以对集合中的键自动完成排序。【了解】

e. LinkedHashMap : 维护键的存储有序性。

【重要】面试题目:写出HashMap 和 Hashtable 区别?

④ 遍历方式:
a. 键遍历:通过keySet()获取Map中所有的键【重点】

Set keys=集合名.keySet();//获取Map中所有的键

//通过遍历Set集合 keys获取每一个键
for(K key:keys){
//通过键获取对应的值
V value=map.get(key);
//利用 key 和 value 操作集合中内容
...
}

b. 值遍历:通过 values()获取Map中所有的值

Collection vs = map.values();

//通过遍历Collection集合 vs获取每一个值
for(V value:vs){
//通过 value操作值....
}

注意:值遍历,只能获取集合中值的内容,没有方法通过值获取对应键

c. 键值对遍历:通过 entrySet()获取Map中所有的键值对【或是重点】

Set> kvs = map.entrySet();//获取Map中所有键值对

//通过遍历Set集合 kvs 获取每一个键值对
for(Map.Entry kv:kvs){
//通过键值对Entry获取其中键:getKey()
K key = kv.getKey();
//通过键值对Entry获取其中值:getValue()
V value = kv.getValue();
//操作Map的键和值....
}

思考:如果自定义类型的对象作为键,如何保证键的唯一性???【拓展...】

必须覆盖 hashCode方法 和 equals方法。要求等同于 HashSet

注意:实际开发应用过程中,不建议将定义类型的对象(可变性的对象)作为键;
通常用 String作为键的内容。


=====================================异常====================================
一、异常
1. 概念:程序在运行过程中出现的一些非正常的情况。
2. 异常处理:一旦程序中出现非正常的情况,让程序执行预先准备好的一段代码。
3. 异常处理的必要性:可以减小用户的损失,避免给用户带来不必要的麻烦。


二、异常的分类【面试题目】
1. 异常的父类:Throwable,位于 java.lang 中

(1) 常用构造方法:
① 无参数的构造法方法:public Throwable(){}
② 有参数的构造法方法:public Throwable(String message){//...}

(2) 常用功能方法:

① public String getMessage():获取异常字符串类型的信息。
通常给用户展示提示信息的。
② public void printStackTrace():打印方法调用栈而获取的异常详细信息。
通常用于程序调试错误/bug.

2. Throwable有两个直接的子类:Error(错误) 和 Exception(异常)

(1) 子类:Error --》表示紧靠程序本身无法恢复的严重错误,
例如 内存空间不足或是方法调用过程中栈溢出。
java.lang.StackOverflowError(栈溢出)

特点:在大多数的情况下,遇到此错误,无法处理。

(2) 子类:Exception 分为两类
① RuntimeException:运行时异常、未检查异常,和RuntimeException有直接或是间接的继承的关系的异常类
特点:Java编译编译时不会检测这类异常,运行的过程中报错。
此类异常如果代码写的足够规范,则可以避免,所以遇到此类异常可以处理也可不处理。


常见的运行时异常:
a. java.lang.ArrayIndexOutOfBoundsException(下标越界)
b. java.lang.NullPointerException(空指针异常)
c. java.lang.ClassCastException:(类型转换异常)
d. java.lang.NumberFormatException(数字的格式转换异常)


② 非RuntimeException:非运行时异常、已检查异常,和RuntimeException没有任何的继承关系(直接或是间接)

特点:Java编译器在编译过程检测它,遇到此类异常,编译不通过,开发时遇到此类必须处理。

三、异常的产生
1. 自动产生异常:程序在运行过程中,遇到出错的代码,则JVM自动终止程序运行。

2. 手动产生异常:【开发应用重点】
(1) 语法: throw new 异常类名("异常信息");
(2) 位置:手动产生异常必须定义在方法内部。
(3) 结果:结果和 return语句相当,会将当前函数/方法终止、结束。

四、异常的传递【理解】
异常沿着方法的调用调用链反方向进行传递,直到JVM,程序被终止。

五、异常的处理【开发应用重点】

1. 消极异常处理:声明异常
(1) 语法:修饰符 返回值类型 方法名(形参列表)throws 异常类名1,异常类名2{ //方法的实现}
(2) 位置:方法的声明位置
(3) 作用:消极处理异常可以使 非运行时异常 在编译时编译通过。
(4) 结果:消极处理异常只是推卸责任,最终程序还是因异常而被终止。


2. 积极处理异常:(捕获异常)
(1) 语法:
try{
//可能出现的异常的语句
}catch(异常类名 e){
//一旦出现异常时,执行语句....
}

(2) 位置:积极处理异常定义在方法的内部

(3) 注意:
① try后面可以定义多个 catch结构,当try中出现异常时,从第一个catch从上往下
依次匹配,直到匹配成功为止。
② catch中可以利用父类型(多态)处理异常,如果利用父类型处理异常,可以处理的
异常类型是:本类型+所有的子类型的异常

③ 定义父类型的catch块 必须写在 定义其子类型的catch块的 后面
(父类的catch在后,子类的catch在前)

④ catch中只能处理try中可能出现的非运行时异常;
catch中可以任意的处理运行时异常(不管try有没有可能出现)【了解】

(4) finally : 不管有没有异常都必须执行的语句
① 语法:
try{
//可能出现异常的语句...
}catch(异常类名 e){
//异常出现时,执行的语句...
}finally{
//不管有没有异常都必须执行
}

② 作用:开发时,通常finally中不定义 return 语句;通常用于关系资源,例如IO、连接等。


六、自定异常类【理解】

1. 自定义异常类需要继承 Exception 或是 其子类;
如果想让自定异常类抛出异常为运行时异常,则需要继承 RuntimeException或是其子类。

2. 为自定异常类提供两个构造方法:
① 无参数的构造方法
② 有参数的构造方法:参数类型为 String
借助super(message)给父类属性赋值



七、方法的覆盖[终结版]【面试+开发重点】
1. 子类的方法名、形参列表、返回值类型和父类相同
2. 子类的访问修饰符和父类相同或是比父类更宽
3. 子类不能抛出比父类更多、更宽的异常



面试题目:写出 final 、finalize和 finally的区别?

=============================多线程==========================
一、进程
1. 进程:操作系统中,执行的应用程序称为进程。
2. 进程的并发执行:操作系统(OS)中,同时执行的多个逻辑任务。
3. 进程并发执行的原理:微观串行(一个进程一个进程的执行,哪一个进程获取CPU时间片,哪一个执行)
宏观并行(所有的进程一起执行)


二、线程
1. 线程:一个进程中,并发执行的多个逻辑任务。
线程是进程的执行单位。(线程是轻量级的进程)

2. Java语言中只有多线程,没有多进程的概念。

3. 目前Java中的程序为单线程,这个线程以main函数的开始为开始,以main函数的结束为结束,
这线程被称为主线程。

4. 线程的组成部分:
① CPU时间片:操作系统(OS)分配时间片的线程才能执行。(宏观并行,微观串行)

② 数据:堆空间共享,栈空间独立。
堆空间:存储对象。 ----》共享
栈空间:存储局部变量。---》独立

③ 代码实现多线程:【应用重点+面试重点】
第一种方式:
a. 继承继承 java.lang.Thread类,覆盖 run方法
b. 创建线程对象:
MyThread t = new MyThread();
c. 开启线程:利用线程对象.start()方法
t.start(); //--->JVM会默认执行 run方法

注意:用 t.run(); -->不是正确开启线程,是一种普通方法的调用。


第二种方式:
a. 实现java.lang.Runnable接口,同时实现run方法 ---》目标类
b. 创建目标对象: ---》代表线程将来需要完成的任务
MyTarget mt = new MyTarget();

c. 创建线程对象,将目标对象作为参数进行传递
Thread t2 = new Thread(mt);
d. 开启线程:利用 start()即可
t2.start();

注意:两种创建线程的方式区别?
a. 第一种创建线程相对第二种创建线程的方式简单,而且直接;
b. 第二种创建线程的方式可以更有利于资源共享。

三、线程的状态(详见pdf)【理解】
1. static sleep(long ms): 此方法会让当前线程处于休眠(限期等待状态-Timed Waiting),
处于休眠状态的线程会释放CPU时间片;但是不释放拥有的锁标记。

2. void join(): 加入,让一个线程加入到当前任务中,让前线程处于无限期等待状态(Waiting).
在 main函数中调用 t.join(); --->主线程让步于 t线程,即让 t线程优先执行。

四、线程同步【理解】

1. 临界资源:多线程并发访问时,被多个线程共享的对象。

2. 原子操作:不可分割的多步操作,被视为一个整体,其顺序和步骤不能被破坏。

3. 线程同步:多线程并发访问时,为了保证临界资源的正确性,从而不破坏程序中的原子操作。

4. 线程同步的方法:【重点】
① 同步代码块
a. 同步代码块是对临界资源对象进行加锁
b. 语法:
synchronized(临界资源对象){
//原子操作....
}

c. 原理:如果线程执行同步代码块{}中的内容,必须先获取临界资源对象的锁标记,
如果获取了临界资源对象的锁标记,将同步代码块{}中所有的内容全部执行
完,才释放锁标记;如果获取临界资源对象的锁标记时,锁标记被其他线程
占用,则该线程进入阻塞状态(Blocked状态),直到获取锁标记才能从阻塞
状态结束,同时获取CPU时间片才能执行同步代码块{}中的内容。

② 同步方法
a. 同步方法:被 synchronized修饰的方法。
b. 语法:
修饰符 synchronized 返回值类型 方法名(形参列表){
//方法实现(包含原子操作)
}

c.同步方法的本质等同于同步代码块
synchronized(this){
//原子操作...
}



面试题目:ArrayList 和 Vector 区别?
ArrayList: 线程不安全,底层方法都是非同步方法,运行效率高。
Vector:线程安全,底层方法是同步方法,运行效率慢。(多个线程访问时需要等锁标记)

五、线程间的通信
1. wait方法:wait()
(1) wait方法的调用必须使用在该对象的同步代码块中(用哪一个对象调用wait方法,对象就是该对象)
(2) 在当前线程中调用了 wait方法,则当前线程进入 无限期等待状态(Waiting状态)
(3) wait方法会让当前线程释放拥有的锁标记,同时释放CPU.

2. notify()/notifyAll()
(1) notify()通知一个线程从等待的状态结束。
notifyAll():通知所有的线程草丛等待状态结束。

(2) notify()/notifyAll()必须使用在该对象的同步代码块中
(3) notify()/notifyAll() 只是起到通知的作用,不会让当前线程释放锁标记和CPU.


面试题目:写出 sleep(long ms)和 wait()方法的区别?


3. 经典的应用:生产者-消费者【思想理解】
① 栈存储结构:先进后出(FILO),后进先出(LIFO)
a.入栈:往栈结构存储元素---》生产者
b.出栈:从栈结构取出元素---》消费者

② 程序中用 while 判断消费者和生产者是否需要等待,而不用if判断的原因
是防止有 一对多/多对一/多对多的情景出现。

注意:如果 是 一对一的场景,用 if或是while都可以,但是建议统一使用while.

线程池.....

六、Callable接口(位于 java.util.concurrent 包中)【应用+练习】
1. 作用:解决了Runnable接口中run的两个不足的地方,一个run方法不能抛出异常;
另一个就是不能有返回值。

2. JDK5.0之后添加了一个新的接口 Callable

3. Callable接口 相当于 Runnable 接口,代表一个线程任务

4. Callable接口中的方法:--->接口是一个泛型接口
V call(): 带有返回值,并且可以抛出异常的方法。

5. 同步、异步
① 同步方法:方法一旦调用,调用者必须停下等着被调方法执行完毕,返回到调用的位置,
调用者才能继续往下执行。[现实商场购物]

② 异步方法:方法一旦调用,调用者立即返回,继续执行以下内容。[网购]

6. Future
① 应用:获取存储异步计算的结果,ExecutorService.submit()所返回的状态结果,
当中包含了call()的返回值。
② V get():获取 Future中 call方法的返回值结果。
返回值类型取决于 Callable接口的泛型类型。



七、补充Collection集合

1. 队列:先进先出(FIFO),后进后出

2. 子接口:Queue--》
① 特点:模拟队列存储结构,先进先出
② 方法:
a. add(Object o):往队列结构中添加一个元素,不自动扩容
b. offer(Object o):往队列结构中添加一个元素,通常用此方法较多。
c. Object poll():从队列中移除一个元素。(队头元素)


③ 实现类:LinkedList


④ 子接口:BlockingQueue【面试题目】
a. 特点:阻塞队列,内部实现了生产者与消费者,会根据队列的容量,判断是否让当前线程阻塞。
b. 实现类:
ArrayBlockingQueue ---》数组实现
LinkedBlockingQueue ---》链表实现

八、补充 Collections的应用【了解】

1. Collections工具类中提供了大量的静态方法,可以将线程不安全的集合对象转换为
线程安全的集合对象,线程安全的集合对象作为返回值返回。

2. 方法:
① static List synchronizedList(List list)
② static Map synchronizedMap(Map map)
③ static Set synchronizedSet(Set set)



九、锁(Lock)

1. Lock: 位于 java.util.concurrent.locks 包中,替代了早期的 synchronized,锁分离。

(1) 常用的方法:
① void lock():获取锁,如果锁标记被占用,则需要等待
② void unlock():释放锁标记

注意:需要手动释放锁标记。

(2) 实现类:ReentrantLock

2. 读写锁:ReadWriteLock,所在包java.util.concurrent.locks
① 读写锁:支持一写多读的同步锁,可以分配读锁和写锁。
② 实现类:ReentrantReadWriteLock
ReadWriteLock rwl=new ReentrantReadWriteLock();
Lock rl=rwl.readLock();//读锁
Lock wl=rwl.writeLock();//写锁

③ 读写锁之间的访问约束
读操作 写操作
读锁 不阻塞 阻塞
写锁 阻塞 阻塞


总结:读与读操作之间不互斥
读与写操作之间互斥
写与写操作之间互斥

④ 使用场景:当读操作远远高于写操作时,可以使用读写锁提高性能。


十、提高并发效率的集合实现类
1. CopyOnWriteArrayList:所在包java.util.concurrent,对读操作不加锁,对写操作加锁,
而且在写操作中复制原有数据文本,在新数据文本上进行操作。
(牺牲写操作的效率提高读操作的效率) 【面试题目】

应用场景:读操作远远大于写操作。
CopyOnWriteArrayList和Vector比较:效率高
CopyOnWriteArrayList和ArrayList比较:安全


2. ConcurrentLinkedQueue :所在包java.util.concurrent,是 Queue接口常用实现类,
实现了队列存储结构,内部采用比较交换算法(CAS)实现
线程安全。---》(内部无锁,线程安全)

3. ConcurrentHashMap:所在包java.util.concurrent包中 【面试重点】
① ConcurrentHashMap:减小锁的锁定范围,从而减小锁之间冲突可能性,
从而提高线程并发时效率。

② ConcurrentHashMap:内部细分若干个小的HashMap,称为段(16段)。

③ 应用场景:全局操作不经常使用时,会提高并发效率。
全局操作:size()/containsKey()/containsValue()等。

④ ConcurrentHashMap 和 HashMap 比较:安全
ConcurrentHashMap 和 Hashtable 比较:相对效率高(全局操作不经常)

================================IO 流 (位于 java.io 包中)==============================
一、概念:
1. 流就是 内存 和 其他存储设备传输数据的通道、管道。【理解】
2. 流的分类:【面试题目】
① 按方向分(以JVM内存为参照物)
a. 输入流:将 <存储设备>中的数据 读入到 中。---》读操作
b. 输出流:将 中的数据 写入到 <存储设备>中。---》写操作

② 按单位分(传输内容)
a. 字节流:以字节为单位进行传输,可以操作所有类型的文件。
b. 字符流:以字符为单位进行传输,只能操作文本文件。
(以 记事本打开,不丢失原有内容的文件--->文本文件:.java/.c/.html/.txt等)

③ 按功能分
a. 节点流:只具备基本的读写功能。
b. 过滤流:在节点流的基础上,增强新的读写功能。

二、字节流
1. 字节流的父类(抽象类)【了解】
a. InputStream: 字节输入流 ---》读操作 read
b. OutputStream:字节输出流 ---》写操作 write


2. 字节节点流
① FileOutputStream:文件字节输出流【开发应用重点】

常用构造方法:
a.FileOutputStream fos=new FileOutputStream("F:\\CoreJava\\a.txt");
I. 参数:代表操作的文件的路径及文件名,F:\\CoreJava\\a.txt 或是
F:/CoreJava/a.txt
II. 注意:如果指定文件不存在,则系统默认的自动创建新的文件;
如果指定的文件夹不存在,则报错,错误信息:
java.io.FileNotFoundException: (系统找不到指定的路径)

III. 绝对路径:盘符:/文件夹/文件名

b. FileOutputStream fos=new FileOutputStream("file/a.txt");
I. 相对路径:在当前项目的根目录下查找指定的文件,
如果文件不存在则,系统默认创建;如果文件夹不存在,则报错,
错误信息:java.io.FileNotFoundException: (系统找不到指定的路径)


c. FileOutputStream fos=new FileOutputStream("file/a.txt",true);
I. 第一个参数:代表指定操作的文件的路径及文件名
第二个参数:是否在原内容上追加新内容;true-追加 ; false - 覆盖(默认行为)


常用功能方法:
a. public void write(int n):将单个字节写入到文件中。
b. public void write(byte[] bs):将多个字节内容一次性写入到文件中。
c. public void write(byte[] bs,int off,int len):将多个字节内容一次性写入到
文件中(从下标off开始,写入到文件中字节数为 len)


注意:使用完的流需要关闭,调用 close方法(关闭此文件输出流并释放与此流有关的所有系统资源)
关闭之后的流不能继续使用。


② FileInputStream:文件字节输入流 【开发应用重点】
常用构造方法:
a. FileInputStream fis = new FileInputStream("file/b.txt");
I. 参数:代表读取的文件的路径及 文件名
II. 注意:指定的文件及文件夹必须都存在,否则运行报错,错误信息:
java.io.FileNotFoundException(系统找不到指定的文件)

常用的功能方法:
a. public int read():从文件中读取一个字节的内容,将读取到的内容,作为返回值返回,
如果达到文件的尾部,则返回-1.

应用:一次性的将文件中的内容全部读取?
while(true){
int n = fis.read();
if(n == -1) break;
//操作读取到的字节内容 n
....
}
b. public int read(byte[] bs):从文件中一次性读取多个字节内容,将读取到的字节内容
自动存储在 bs数组中,实际读取到的字节数作为返回值返回,
如果达到文件的尾部,则返回-1.

c. public int read(byte[] bs,int off,int len):从文件中一次性读取多个字节内容,将读取到的
字节内容自动的存储在 bs数组中(存储的起始下标为off, 读取的个数
为len),返回值代表实际读取到的字节个数,如果达到文件尾部,返回-1.


思考:如何用程序实现文件的拷贝?????【开发应用重点--》文件的上传与下载的应用】

3. 过滤流:
① BufferedOutputStream/BufferedInputStream
a. 缓冲流,用于提高IO的读写效率,减少硬盘访问的次数。
b. 操作过程中数据存储在 缓冲区中,需要调用flush方法或是close方法刷新缓冲区。
注意:使用flush刷新缓冲区,流还可以继续使用;
但是使用close方法关闭流的同时,刷新缓冲区,流不能继续被使用。

如果缓冲区满了的情况下,JVM会自动将缓冲区的内容一次性写入到文件中。


② DataOutputStream/DataInputStream

a. 增强了操作8种基本数据类型的功能
writeByte(byte b)/writeShort(short s)/.....
readByte()/readShort()/....

b. 操作字符串:readUTF()/ writeUTF(String str)

③ ObjectOutputStream/ObjectInputStream
a. 增强了操作8种基本数据类型和字符串的功能方法
b. 增强了缓冲的功能
c. 增强了读写对象的功能:
writeObject(Object o):将一个对象写入到文件中
Object readObject():从文件中读取一个对象

d. 对象序列化:
I. 概念:对象在流上进行传输的过程。【面试+应用 重要】
II. 要求:参与对象序列化的对象 必须是 可序列化的,即对象对应的类
必须实现 java.io.Serializable 接口 【面试+应用 重要】
III. 被 transient 修饰的属性不参与对象序列化。 【应用 重要】

IV. 如果达到文件尾部,则抛出异常:java.io.EOFException(文件达到尾部的异常)
V. 如果参与对象序列化的对象属性中有自定类型的属性,则该属性也必须是
可序列化的,对应的类需要实现java.io.Serializable 接口。

集合可以参与对象序列化,但是如果集合中存储的元素为自定类型的对象,
则对象元素对应的类必须实现java.io.Serializable 接口。


面试题目:简述对象序列化及其要求?

重点:FileInputStream/FileOutputStream
对象序列化及其要求


三、编码【理解】
1. ISO8859-1 西欧 底层存储占 1字节
2. 简体中文:
GBK :常用,对2万多的汉字进行编码
GB2312 : 最早 ,对 6000多个汉字进行编码
GB18030 : 最新,对中国所有符号进行编码

3. 繁体中文:Big5
4. UTF-8 : 万国码,底层采用动态编码进行存储,占1~3字节。
汉字 占 2~3字节。

注意:编码方式和解码方式统一的情况下不会出现乱码。

四、字符流
1. 字符流父类(抽象类)
① Reader: 字符输入流 ---》读操作
② Writer: 字符输出流 ---》写操作

2. 字符节点流
① FileWriter : 文件字符输出流
常用构造方法:
FileWriter fw = new FileWriter("file/b.txt");
常用功能方法:
a. public void write(int n):将一个字符写入到文件中
b. public void write(String str):将多个字符写入到文件中
c. public void write(char[] cs):将多个字符写入到文件中

② FileReader:文件字符输入流
常用的构造方法:
FileReader fr = new FileReader("file/b.txt");

常用的构造方法:
a. public int read(): 从文件中读取一个字符的内容,读取达到字符内容作为返回值返回
b. public int read(char[] cs):从文件中读取多个字符的内容,将读取到的字符内容自动存储
cs数组中,返回值代表实际读取的字符个数,如果达到文件尾部,
则返回-1.


3. 字符过滤流【开发应用重点】
① BufferedReader:
常用方法:
public String readLine():一次性读取一个文本行,如果文件达到尾部,则返回null.



② PrintWriter:
a. 可以操作8种基本数据类型和字符串

b. print(形参列表):写入之后不换行
println(形参列表):写入之后自动完成换行

c. print(Object o)/println(Object o):将对象 toString方法的返回值字符串内容写入文件中。



4. 桥转换流【开发应用重点】
InputStreamReader/OutputStreamWriter

桥转换流的作用:字节流和字符转换的通道、桥梁;同时可以设置编码方式。

步骤总结: 【开发应用重点】
① 创建字节节点流对象:FileInputStream/FileOutputStream
② 创建桥转换流:
作用:字节流和字符流转换桥梁;同时可以设置编解码格式
③ 包装过滤流:
作用:增强读写功能
④ 读写操作
⑤ 关闭流:关闭最外层流即可

五、File类(位于 java.io 包中)
1. 概念
① IO流是对文件内容进行操作。
② File类是对文件本身进行设置,删除文件、重命名等操作。

2. 常用方法:
① String getName():获取文件名含扩展名
② String getAbsolutePath():获取绝对路径 【重点】

===============================反射================================
一、反射【理解】
1. 概念:
① 类 的对象:基于一个定义好的类,创建该类的实例对象。即new出来的对象都是类的对象。
② 类 对象:是类加载的产物,封装了一个类的包名、类名、属性、方法、父类、实现的接口等信息。


2. 获取类对象的方式:
① 通过 类的对象 获取类对象
Student s = new Student();//类的对象
Class c1 = s.getClass();//类对象

② 通过 类名.class 获取 类对象
Class c2= Student.class;

③ 通过 Class类中静态方法 forName(String className) 获取类对象
Class c3 = Class.forName("test_flect.Student");

注意:forName方法中参数代表全类名,即 包名.类名;
通常利用Class.forName("全类名")让一个类进行类加载。

3. 常用的方法:
① 利用类对象获取类的对象:c3.newInstance()
注意:默认调用类中无参数的构造方法创建对象;
开发时,自定义的类中尽可能提供无参数+有参数的构造方法

② 反射中利用有参数的构造方法获取对象:
a. Constructor constru = c3.getConstructor(String.class,int.class);//获取有参数的构造方法
注意:参数代表调用构造方法的参数类型

b. Object o= constru.newInstance("母华",88);//利用有参数的构造方法获取实例对象
注意:利用有参数的构造方法获取实例对象时,需要给属性传递实际参数。

③ 设置私有方法的访问权限:dm.setAccessible(true);

4. 反射的优缺点
① 缺点:操作繁琐,可读性差;可以打破封装。
② 优点:让代码更加的灵活和通用。通常用于框架的底层开发。

二、设计模式(23种)【理解】

1. 概念:被多人知晓、分门别类的代码的总结。
2. 单例设计模式:程序设计中,必须保证JVM内存中,只有该类的一个实例对象存在。

① 单例实现的第一种方式:饿汉式
class ClassA{
private final static ClassA ca = new ClassA();
private ClassA(){}
public static ClassA getIntance(){
return ca;
}
}

优点:并发效率高
缺点:空间利用率低

② 单例实现的第二种方式:懒汉式
class ClassB{
private static ClassB cb;
private ClassB(){}
public synchronized static ClassB getInstance(){
if(cb == null){
cb = new ClassB();
}
return cb;
}
}

优点:空间利用率高
缺点:并发效率低

③ 拓展
class ClassC{
private ClassC(){}
//静态内部类
private static class Inner{
static ClassC c = new ClassC();
}
public static ClassC getInstance(){
return ClassC.Inner.c;
}
}

3. 工厂设计模式:用于解决对象的创建问题。
① 工厂在设计过程中,通常利用反射技术让自身功能更加灵活和通用。

② Properties 通常用于读取配置文件中
load(形参列表)方法将输入流执行的文件内容进行加载,自动以 "="或是":"
进行拆分,将左侧内容作为 键(key),右侧内容作为 值(value).

demo:
Properties pro = new Properties();// Map
FileInputStream fis = new FileInputStream("config.txt");
pro.load(fis);


4. 适配器设计模式
interface IA{
void m1();
void m2();
void m3();
}

abstract MyClass implements IA{
public void m1(){}
public void m2(){}
public void m3(){}
}

//不同的实现类继承 MyClass



转载于:https://www.cnblogs.com/lhq1996/p/11356739.html

你可能感兴趣的:(java笔记)