Java入门

windows命令行:cmd 打开命令行界面       算法+数据结构=应用程序

目录名:目录切换;dir列出当前目录下的文件以及文件夹;md 创建文件夹;

cd d:\java打开D盘下的Java目录

cd..回到上层目录;del 文件名  删除文件;echo 内容>文件名;

*通配符;rd 文件夹 删除目录;

SUN公司,1995年推出的语言

java特点:面向对象———两个基本概念:类、对象

三大特性:封装、继承、多态

健壮性————去掉了c的指针,提供了一个相对安全的内存管理和访问机制

跨平台性————可以在不同的系统平台上运行,在不同的操作系统中的JVM中运行

JDK中包含JRE(程序运行环境)中包含(JVM标准库)

Java -version查看Java版本

path:windows系统执行命令时要搜寻的路径  配置path的原因,在任何路径下都可以执行java环境

java注释://单行注释;作用:对所写的程序解释说明,增强可读性

/* 内容*/    多行注释;不可以嵌套使用

/**内容*/文档注释;java特有的,注释内容可以被JDK提供的工具javadoc解析,生成一套以网页文件形式体现的该程序的说明文档。例:javadoc -d 起的名字 - author -version 文件名.java

API应用程序编程接口:

1.在一个Java源文件中可以声明多个class,但是,只能最多有一个类声明为public的。而且要求声明为public的类的类名必须与源文件名相同。

2.程序的入口是main()方法,格式是固定的;

3.输出语句:System.out.println(先输出数据,后换行):和System.out.print(只输出):

4.每一行执行语句都以“;”结束

5.编译的过程:编译以后,会生成一个或多个字节码文件,字节码文件的文件名与java源文件总的类名相同。

Java基础语法

1.关键字与保留字

关键字:被Java赋予了特殊含义,用做专门的字符串,特点:所有的关键字都是小写。如:class、public

保留字:现有Java尚未使用,但以后的版本可能会作为关键字使用,自己命名标识符时要避免这些保留字;如:goto、const

2.标识符命名规则:Java对变量、方法和类等要素命名时使用的字符序列称为标识符;凡是可以自己起名字的地方都是标识符。

如: 类名、变量名、方法名、接口名、包名......

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

3.java中的名称命名规范

包名:多个单词组成的所有字母都小写:xxxyyyzzz

类名、接口名:多单词组成时,所有单词的首字母大写:XxxYyyzz  俗称大驼峰

变量名、方法名:多单词组成时,第一个单词首字母小写,第二个单词开始每个单词首字母大写:xxxYyyZzz 俗称小驼峰

常量名:所有字母都大写。多单词时每个单词用下划线连接:XXX_YYY_ZZZ

  1. 起名字时要”见名知意“

1.java定义变量的格式:数据类型 变量名 = 变量值;

变量的格式:包含数据类型(字符型、整型、浮点型)、

变量名 =变量值; int myAge = 12     

存储的值;

2.(1)变量必须先声明,后使用;

(2)变量都定义在其作用域内,在作用域内,他是有效的,出了作用域就失效

(3)不可以在同一个作用域内定义同名变量

一、变量按数据类型来分

基本数据类型:

整型:byte\short\int\long;浮点型:float\double;字符型:char;布尔型:boolean

引用数据类型:

类:class ;接口:interface;数组:array

二、变量在类中声明的位置

成员变量   局部变量

整型:byte 1字节=8bit   范围:-128~127  

short 2字节  

int 4字节

long 8字节  定义完必须以l或L结尾

通常定义整型变量时使用int型

浮点型:单精度float 4字节  定义float时,变量要以f或F结尾

双精度double 8字节

表示小数点的数值、float表示数值范围比long还大,通常定义浮点型变量时使用double

字符型:char 1字符=2字节   定义char型变量,通常使用一对''''

声明一个字符,单引号内部只能写一个字符

转义字符:\n换行符;\t制表符

直接使用Unicode(字符集)之来表示字符型常量  \u

布尔型:boolean

只能取两个值之一:true、false,常常在条件判断、循环结构中使用

1.自动类型提升:

结论:当容量小的数据类型的变量于容量大的数据类型的变量做运算时,结果自动提升为容量大的数据类型,此时的容量大小指的是表示数的范围的大和小;

byte 、char、short -->int-->long-->float-->double

特殊:当byte 、char、short这三种变量做运算时至少用int

2.强制类型转换:自动类型提升运算的逆运算,需要使用:(变量名)强转符

注意:强制类型转换,可能导致精度损失。

整型常量,默认类型为int型;浮点型常量,默认类型为double型。

String类型变量的使用

1.String属于引用数据类型 ;翻译为:字符串

2.声明String类型变量时,使用一对“”

3.String可以和8种基本数据类型变量做运算,且运算只能是连接运算:+  (+代表连接运算)

4.运算的结果仍然是String类型

进制说明

对于整数,有四种表示方式:

二进制:0,1,满2进1,以0b或0B开头;

十进制:0-9,满10进1;

八进制:0-7,满8进1,以数字0开头;

十进制:0-9及A-F,满16进1,以0x或0X开头表示,

运算符

算数运算符;+正、-负、+加、-减、*乘、/除、%取模(取余)、++加加(前后)、--减减(前后)、%取模运算(结果的符号与被模数符号相同),后面开发中,经常使用%来判断能否被除尽的情况

(前)++:先自增1,然后在运算 ;(后)++:先运算,后自增1

注意点:自增1不会改变本身变量的数据类型

(前--):先自减1,后运算;(后--):先运算,后自减1

赋值运算符;=、+=、-=、*=、/=、%=     

结论:使用时不会改变变量本身的数据类型

比较运算符;==、!=、<、>、<=、>=、instanceof   

结果都是boolean型,要么是true,要么是false

逻辑运算符;&-逻辑与、&&-短路与;|-逻辑或、||-短路或;!-逻辑非、^-逻辑异或;

a b a&b a&&b a|b a||b !a a^b

true true true true true true false false

true false false false true true false true

false true false false true true true true

false false false false false false true false

逻辑运算符操作的都是boolean类型的变量

区分&与&&

相同点1:&与&&的运算结果相同;

相同点2:当符号左边是true时,二者都会执行符号右边的运算

不同点:当符号左边是flase时,&继续执行符号右边的运算。&&不在执行符号右边的运算。

开发中推荐使用&&

区分|与||

相同点1:|与|的运算结果相同;

相同点2:当符号左边是flase时,二者都会执行符号右边的运算

不同点:当符号左边是true时,|继续执行符号右边的运算。||不在执行符号右边的运算。

开发中推荐使用||

位运算符;

<<左移;>>右移;>>>无符号右移;&与运算;|或运算;^异或运算;~取反运算

结论:操作的都是整形的数据

在一定的范围内,每向左移一位,相当于 * 2

在一定范围内,每向右移一位,相当于 / 2

三元运算符;(条件表达式)?表达式1:表达式2

说明:条件表达式的结果为boolean类型

根据条件表达式的真或假,决定执行表达式的1,还是表达式的2,如果表达式为true ,则执行表达式1,如果表达式为false,则执行表达式2,要求:表达式1和表达式2要求是一致的,三元运算符可以嵌套使用

结论:凡是可以使用三元运算符的地方,都可以改写为if-else,反之不成立

如果程序既可以使用三元运算符,又可以使用if-else结构,那么优先选择三元运算符。原因:简洁,执行效率高

运算符的优先级:想让谁先运算,就加括号()

流程控制if-else

获取随机数:公式:【a,b】:int 名 = (int)(Math.random() *(b -a + 1) + a)

顺序结构

分支结构(if-else)                  

第一种:if(条件表达式){

}

第二种:二选一

if(条件表达式){

执行语句1

}else{

执行语句2

}

第三种:n选一

if(条件表达式){

执行语句1

}else if(条件表达式){

执行语句2

...

else{

执行语句3

}

}

如何从键盘获取不同类型的变量:需要使用Scanner类

具体操作步骤:

1.导包:import java.util.Scanner;

2.Scanner的实例化

3.调用Scanner类的相关方法(next()/nextXXX()),来获取指定类型的变量

注意:需要根据相应的方法,来输入指定类型的值。如果输入的数据类型与要求类型不匹配时,会报异常:InputmMisMatchExcetion导致程序终止。

定义String后直接用next,后面不用加

String类型引用“是否”得写成变量名+.equals("是或否")

流程控制switch-case

switch-case

1.格式:

switch(表达式){

case常量1:

执行语句1;

//break;

case常量2:

执行语句2;

//break;

……

default:

执行语句n;

//braek;

}

2.说明:

根据switch表达式中的值依次匹配各个case中的常量,一旦匹配成功,则进入相应的case结构中,调用其执行语句。当调用完执行语句以后,则任然继续向下执行其他case结构中的执行语句,直到遇到braek关键字或此switch-case结构末尾结束

3.break,可以使用在switch-case结构中,表示一旦执行到此关键字,就跳出switch-case结构。

4.switch-case结构中的表达式,只能是如下6种数据类型之一:byte、short、char、int、枚举类型(JDK5.0新增)、String类型(JDK7.0新增)

5.case之后只能声明常量,不能声明范围。

6.break关键字是可选的。

7.default相当于if-else结构中的else,default结构是可选的,而且位置是灵活的。

8.如果switch-case结构中的多个case的执行语句相同,则可以考虑合并。

1.凡是可以使用switch-case的结构,都可以转换为if-else,反之,不成立。

2.当我们写分支结构时,当发现既可以使用switch-case,(同时,switch中表达式的取值情况不太多),又可以使用if-else时,我们优先选择switch-case。原因:switch-case执行效率稍高。

提示:String world = scan.next();

char c = world.charAt(0);   char型键盘输入需要转换

循环结构

循环:for、while、do-while

for循环的使用:

循环结构的四个要素:

初始化条件;循环条件(是boolean类型);循环体;迭代条件

1.for循环的结构

for(初;条;跌){

}

break一旦在循环中执行break,就跳出循环。

while循环

while(条){

体;

跌;

}

说明:1.写whil循环千万小心不要丢了迭代条件,一旦丢了,就可能导致死循环

2.我们写程序,要避免出现死循环。

3.for循环和while循环是可以相互转换的。

区别:for循环和while循环的初始化条件部分的作用范围不同。

do-while循环

do{

体;

跌;

}while(条);

执行过程:初-->体-->跌-->条

说明:1.do-while循环至少会执行一次循环体

2.开发中使用for和while的更多一些,较少使用do-while

嵌套循环的使用

1.嵌套循环:将一个循环结构A声明在另一个循环结构B的循环体中,就构成了嵌套循环

2.外层循环;内存循环;

3.内存循环结构遍历一遍,只相当于外层循环循环体执行了一次

4.假设外层循环需要执行m次,内层循环需要执行n次,此时内层循环的循环体一共执行了m*n次

5.外层循环控制行数,内层循环控制列数

break和continue关键字的使用

使用范围: 循环中使用的作用(不同点) 相同点

break:   switch-case或者

循环结构中            结束当前循环 关键字后面不能声明执行语句

continue:只能在循环结构中 结束当次循环 关键字后面不能声明执行语句

求和就是+=

int bai = i / 100;  分别取百十个位数
int shi = i % 100 /10;
int ge = i % 10;

一维数组

数组的概述:

  1. 数组的理解:数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编码的方式对这些数据进行统一管理。
  2. 数组相关的概念:

数组名,数组的元素,角标、下标、索引,数组的长度:元素的个数

3.数组的特点:

1)数组是有序排列的

2)数组属于引用数据类型的变量;数组的元素,既可以是基本数据类型,也可以是引用数据类型。

3)创建数组对象在内存中开辟一整块连续的空间

4)数组的长度一旦确定,就不能修改。

4.数组的分类

1)按照维数:一维数组、二维数组、……

2)按照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组

5.一维数组的使用

1)一维数组的声明和初始化,总结:数组一旦初始化完成,其长度就确定了。

2)调用数组的指定位置的元素。通过角标的方式调用。数组的角标或索引从0开始,到数组的长度减1结束

3)如何获取数组的长度,属性:length

4)如何遍历数组

5)数组元素是基本数据类型的默认初始化值

数组元素是整型;默认初始化都是0

数组元素是浮点型;默认初始化都是0.0

数组元素是char型;默认初始化都是0(\u000),而非‘0’

数组元素是boolean型;默认初始化都是false

数组的元素是引用数据类型:null(空值)

多维数组

1)二维数组的声明和初始化  

2)如何调用数组的指定位置的元素。

3)如何获取数组的长度

4)如何遍历数组

规定:二维数组分为外层数组的元素,内层数组的元素

int[][] i = new int[4][3];

外层元素:i[0],i[1]等

内层元素:i[0][0],i[1][2]等

5)数组元素的默认初始化值

针对于初始化方式一:比如int[][] arr = new int[4][3];

外层元素的初始化值为:地址值

内层元素的初始化值为:与一维数组初始化情况相同

针对于初始化方式二:比如int[][] arr = new int[4][];

外层元素的初始化值为:null

内层元素的初始化值为:不能调用,否则报错

面向对象

一、三条主线:

1.java类及类的成员:属性、方法、构造器、代码块、内部类

2.面向对象的三大特征:封装性、继承性、多态性、(抽象性)

3.其他关键字:this、super、static、final、abstract、interface、package、import等

二、面向对象的两个要素

类:对一类事物的描述;

对象:是实际存在的该类事物的每个个体,因而也称为实例(instance);对象是由类派生出来的。

面向对象程序设计的重点是类的设计

1.设计类其实就是设计类的成员

属性 = 成员变量 = field= 域、字段

方法 = 成员方法 = 函数 = method

创建类的对象 = 类的实例化 = 实例化类:

三、类和对象的使用(面向对象思想的落地实现):

1.创建类,设计类的成员;

2.创建类的对象;

3.通过”对象.属性“或”对象.方法“调用对象的结构。

测试类:

创建类的对象

变量名 名 = new 变量名();

例:Scanner scan = new Scanner();

调用对象的结构:属性、方法

调用属性:”对象。属性“

调用方法:"对象.方法

四、如果创建了一个类的多个对象,则每个对象都独立的拥有一套类的属性。(非static的),意味着:如果我们修改一个对象的属性a,则不影响另外一个对象的属性a的值

类中属性的使用

属性(成员变量)   vs   局部变量

1.相同点:

1.)定义变量的格式:数据类型 变量名= 变量值

2).先声明,后使用

3.)变量都有其对应的作用域

2.不同点:

1)在类中生命的位置不同

属性:直接定义在类的一对{}内

局部变量:声明在方法内,方法形参、代码块内、构造器形参、构造器内部的变量

2)关于权限修饰符的不同

属性:可以在声明属性时,指明其权限,使用权限修饰符

常用的权限修饰符:private、public、缺省、protected

目前,大家声明属性时,都使用缺省就可以了

局部变量:不可以使用权限修饰符

3)默认初始化值

属性:类的属性,根据其类型,都有默认初始化值

整型(byte、short、int、long):0

浮点型(float、double)0.0

字符型(char) 0或\u0000

布尔型(boolean)false

引用数据类型(类、数组、接口): null

局部变量:没有默认初始化值

意味着,我们在调用局部变量之前,一定要显示赋值

特别的:形参在调用时,我们赋值即可

4)在内存中加载的位置:

属性:加载到堆空间中(非static)

局部变量:加载到站空间

类中方法的声明和使用

方法:描述类应该具有的功能

比如:Math类:sqrt()\random()\……

Scanner类:nextxxx()……

Arrays类:sort()\binarySearch()\toString()\equals()\……

1.举例:

public void eat(){
public void sleep(int hour){
public String getName(){
public String getNation(String nation){

2.方法的声明:权限修饰符 返回值类型 方法名(形参列表){

方法体

}

3.(1)关于权限修饰符

java规定的四种权限修饰符:private、public、缺省、protected

(2)返回值类型:有返回值  vs  没有返回值

3.2.1如果方法有返回值,则必须在方法声明时,指定返回值的类型。同时方法中需要使用return关键字来返回指定类型的变量或常量。”return 变量“如果方法没有返回值,则声明时,使用void来表示。通常没有返回值的方法中,就不使用return。但是,如果使用的话,只能“return;”表示结束此方法的意思。

3.2.2我们定义的方法该不该有返回值?题目要求;凭经验:具体问题具体分析;

(3)方法名:属于标识符,遵循标识符的规则和规范,要见名知意

(4)形参列表:方法可以声明0个,1个,或多个形参。

格式:数据类型1 形参1,数据类型2 形参2,……

我们定义方法时,该不该定义形参?  题目要求;凭经验:具体问题具体分析;

(5)方法体:方法功能的体现

return关键字的使用:

1.使用范围:使用在方法体中

2.作用(1)结束方法;(2)针对于有返回值类型的方法,使用“return 变量“方式返回所要的数据。

3.注意点:return关键字后不可以声明执行语句。

方法的使用中,可以调用当前类的属性、还可以调用当前类的方法

特殊的:方法A中又调用了方法A,:递归方法。

方法中不可以定义方法

编译完源程序以后,生成一个或多个字节码文件,我们使用JVM中的类的加载和解释器对生成的字节码文件

进行解释运行。意味着需要将字节码文件对应的类加载到内存中,涉及到内存解析。

面向对象

一、理解“万事万物皆对象”

1.在java语言范畴,我们都将功能结构等封装到类中,通过具体的实例化,来调用具体的功能结构。

Scanner、String等

文件:File

网络资源:URL

2.涉及到java语言与前端的Html、后端的数据库交互时,前后端的结构在java层面交互时,都体现为类,对象

二、匿名对象的使用

1.理解,我们创建的对象,没有显示赋给一个变量名。即为匿名对象

2.特征:匿名对象只能调用一次

方法的重载

1.定义:在同一个类中,允许存在一个以上的同名方法,只要他们的参数个数或者参数类型不同即可"两同一不同":同一个类,相同方法名,参数列表不同:参数个数不同,参数类型不同

2.举例:Arrays类中重载的sort() / binarySearch()

3.判断是否重载:跟方法的权限修饰符、返回值类型、形参变量名、方法体都没有关系!

4.通过对象调用方法时,如何确定某一个指定的方法:

方法名-->参数列表

可变个数的形参

可变个数形参的格式:数据类型...变量名

当调用可变个数形参的方法时,传入的参数个数可以是:0个,1个,2个,。。。。

可变个数形参的方法与本类中方法名相同,参数不同的方法之间构成重载

可变个数形参的方法与本类中方法名相同,形参类型也相同的数组之间不构成重载,他们二者之间不能共存

可变分数形参在方法的形参中,必须声明在末尾

可变分数形参在方法的形参中,最多只能声明一个可变参数

方法参数的值传递机制

关于变量赋值:

如果变量是基本数据类型,此时赋值的是变量所保存的数据值

如果变量是引用数据类型,此时赋值的是所保存的数据的地址值

方法形参的传递机制:值传递

1.形参:方法定义时,声明的小括号内的参数

实参:方法调用时,实际传递给形参的数据

2.值传递机制:

如果参数是基本数据类型,此时实参赋给形参的是,实参真实存储的数据值。

如果参数是引用数据类型,此时实参赋给形参的是,实参存储数据的地址值。

递归方法的使用

1.递归方法:一个方法体内调用它自身。

2.方法的递归包含了一种隐式的循环,它会重复执行某段代码,但这种重复执行无需循环控制

3.递归一定要向已知方向递归,否则这种递归就变成了无穷递归,类似于死循环。

封装与隐藏

“高内聚,低偶合”

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

一、问题的引入:

当我们创建一个类的对象以后,我们可以通过“对象.属性”的方式,对对象的属性进行赋值。这里,赋值操作要受

属性的数据类型和存储范围的制约。除此之外,没有其他制约条件。但是在实际问题中,我们往往需要给属性赋值加入额外的

限制条件。这个条件就不能在属性声明时体现,我们只能通过方法进行限制条件的添加。(比如steLegs()),同时我们需要避免

用户在使用“对象.属性”的方式对属性进行赋值。则需要将属性声明为私有的(private),此时,针对于属性就体现了封装性

二、封装性的体现

我们将类的属性xxx私有化(private),同时,提供公共(public)的方法来获取(getxxx)和设置(setxxx)此属性的值

拓展:封装性的体现:不对外暴露的私有的方法;

三、封装性的体现,需要权限修饰符来配合。

1.java规定了4种权限(从小到大排列):private 、缺省、protected、public

修饰符 类内部 同一个包 不同包的子类 同一个工程

Private yes

缺省 yes yes

protected yes yes yes

public yes yes yes yes

2.4种权限可以用来修饰类及类的内部结构,属性、方法、构造器、内部类

3.具体的4种权限都可以用来修饰类的内部结构:属性、方法、构造器、内部类

修饰类的话,只能使用 缺省、public

总结封装性:java提供了4种权限修饰符来修饰类及类的内部结构,体现了类及类的内部结构在被调用时的可见性的大小。

构造器

类的结构之三:构造器(或构造方法、constructor)的使用

一、构造器的作用:

1.创建对象

2.初始化对象的属性

二、说明:

1.如果没有显示的定义类的构造器的话,则系统默认提供一个空参的构造器

2.定义构造器的格式:权限修饰符 类名(形参列表){}

3.一个类中定义的多个构造器,彼此构成重载

4.一旦我们显示的定义了类的构造器之后,系统就不在提供默认的空参构造器

5.一个类中,至少有一个构造器

总结:属性赋值的先后顺序

1.默认初始化

2.显示初始化

3.构造器中初始化

4.通过”对象.方法“或”对象.属性“的方式,赋值

以上操作的先后顺序:1-2-3-4

This关键字

JavaBean是一种Java语言写成的可重用组件。

所谓JavaBean,是指符合如下标准的Java类:

类是公共的;有一个无参的公共的构造器;有属性,且有对应的get、set方法

this关键字的使用

1.this可以用来修饰:属性、方法、构造器

2.this修饰属性和方法:this理解为:当前对象或当前正在创建的对象

2.1在类的方法中,我们可以使用”this.属性“或”this.方法“的方式,调用当前对象属性或方法,但是,通常情况下,我们都选择神略”this.“。特殊情况下,如果方法的形参和类的属性同名时,我们必须显示的使用”this.变量“的方式,表面此变量是属性,而非形参

2.2在类的构造器中,我们可以使用”this.属性“或”this.方法“的方式,调用当前正在创建的对象属性或方法但是,通常情况下,我们都选择神略”this.“。特殊情况下,如果构造器的形参和类的属性同名时,我们必须显示的使用”this.变量“的方式,表面此变量是属性,而非形参

3.this修饰或调用构造器

1.我们在类的构造器中,可以显示的使用”this(形参列表)“方式,调用本类中指定的类的其他构造器

2.构造器中不能通过 ”this(形参列表)“方式调自己

3.如果一个类中有n个构造器,则最多有n-1构造器中使用了”this(形参列表)“

4.规定:”this(形参列表)“必须声明在当前构造器的首行

5.构造器内部,最多只能声明一个”this(形参列表)“,用来调用其他构造器

Package关键字

一、package关键字 的使用

1.为了更好的实现项目中类的管理,提供包的概念

2.使用package声明类或接口所属的包,声明在源文件的首行

3.包属于标识符,遵循标识符命名规则、规范,“见名知意”

4.每“.”一次,就代表一层文件目录。

补充:同一个包下,不能命名同名的接口、类

不同的包下,可以命名同名的接口、类

MVC设计模式

二、import关键字的使用

import 导入

1.在源文件中显示的使用import结构导入指定包下的类、接口

2.声明在包的声明和类的声明之间

3.如果需要导入多个结构,则并列写出即可

4.可以使用xxx.*的方式,表示可以导入xxx包下的所有结构

5.如果使用的类或接口是java.lang包下定义的,则可以则可以省略import结构

6.如果使用的类或接口是本包下定义的

7.如果在源文件中使用了不同包下的同名的类,则必须至少有一个类以全类名的方式显示

8.如果使用xxx.*方式表明可以调用xxx包下的所有结构,但是如果使用的是xxx子包下的结构,则仍需要显示调用

9.import static :导入指定类或接口中的静态结构:属性或方法

继承性

一、继承性的好处:

1.减少了代码的冗余,提高了代码的复用性

2.便于功能的扩展

3.为了之后多态性的使用,提供了前提

二、继承性的格式: class A extends B{}

A:子类,派生类subclass;B:父类、超类、基类superclass

1.体现:一旦子类A中继承了父类B以后,子类A就获取到了父类B中的结构所有的属性、方法,特别的,父类中声明为Private 的属性或方法,子类继承了父类以后,任然认为获取了父类中私有的结构,只是因为封装性的影响,使得子类不能直接调用父类的结构而已

2.子类继承父类以后,还可以声明自己特有的属性和方法,实现功能的扩展。

extends 延展、扩展

三、Java中关于继承性的归定

1.一个类可以被多个子类继承

2.Jvav 中类的单继承性:一个类只能有一个父类

3.字父类是相对的概念,多层继承

4.子类直接继承父类成为直接父类,间接继承的父类成为间接父类

5.子类继承父类以后,就获取了直接父类以及所有间接父类中声明的属性和方法。

四、1.如果我们没有显示的声明一个类的父类的话,则此类继承Java.lang.Object类

2.所有的Java类,(除Java.lang.Object类之外),都直接或间接的继承于Java.lang.Object类

3.意味着,所有的Java类都具有Java.lang.Object类中声明的功能

方法的重写与super关键字

方法的重写(override / overwrite):

1.重写:子类继承父类以后,可以对父类中同名同参的方法,进行覆盖操作

2.应用,重写以后,当出创建子类对象以后,通过子类对象调用字父类同名同参的方法时,实际执行的

是子类重写父类的方法。

3.重写的规定:

方法的声明:权限修饰符 返回值类型 方法名(形参列表)throws 异常的类型{

方法体}

约定俗称:子类的叫重写的方法,父类的叫被重写的方法

1)子类重写的方法的方法名和形参列表与父类被重写的方法的方法名和形参列表相同

2)子类重写的方法的权限修饰符不小于父类被重写的方法的权限修饰符

特殊情况:子类不能重写父类中声明为private权限的方法

3)返回值类型:

父类被重写的方法的返回值类型是void,则子类重写的方法的返回值只能是void

父类被重写的方法的返回值类型是A类型,则子类重写的方法的返回值可以是A类或A类的子类

父类被重写的方法的返回值类型是基本数据类型,则子类重写的方法的返回值类型必须是相同的基本数据类型

4)子类重写的方法抛出的异常类型不大于父类被重写的方法抛出的异常类型

子类和父类中的同名同参的方法要么都声明为非static的(考虑重写),要么都声明为static的(不是重写)

super关键字的使用:调用属性和方法

1.super 理解为:父类的

2.super可以用来调用:属性、方法、构造器

3.super的使用

①我们可以在子类的方法或者构造器中,通过使用”super.属性“或”super.方法“的方式,显示的调用父类中声明的属性或方法。

②当子类和父类中定义了同名的属性时,我们要想在子类中调用父类中声明的属性,则必须显示的使用”super.属性“的方式,表明调用的是父类中声明的属性

③特殊情况:当子类重写了父类中的方法以后,我们想在子类的方法中调用父类中被重写的方法时,则必须显示的使用”super.方法“的方式,表明调用的是父类中被重写的方法

4.super调用构造器

①我们可以在子类的构造器中显示的使用“super(形参列表)”的方式:调用父类中声明的指定的构造器

②“super(形参列表)”的使用,必须声明在子类构造器的首行!

③我们在类的构造器中,针对于“this(形参列表)”或“super(形参列表)”只能二选一,不能同时出现

④当我们在构造器的首行,没有显示的声明“this(形参列表)”或“super(形参列表)”,则默认调用的是父类中空参构造器:super()

⑤在类的多个构造器中,至少有一个类的构造器中使用了“super(形参列表)”,调用了父类中的构造器

子类对象实例化的全过程

1.从结果上来看:(继承性)

子类继承父类以后,就获取了父类中声明的属性或方法。创建子类的对象,在堆空间中,就会加载所有父类中声明的属性。

2.从过程中来看:当我们通过子类的构造器创建子类对象时,我们一定会直接或间接的调用其父类的构造器,进而调用父类的父类的构造器,直到调用了Java.lang.Object类中的空参的构造器为止。正因为加载过所有父类中的结构,所以才可以看到内存中有父类的结构,子类对象才可以考虑进行调用。

明确:虽然创建子类对象时,调用了父类的构造器,但是自始至终就创建过一个对象,即为new的子类对象。

多态

1.理解多态性:可以理解为一个事物的多种形态

2.何为多态性:

对象的多态性:父类的引用指向子类的对象(或子类的对象赋给父类的引用)

多态的使用:当调用子父类同名同参数的方法时,实际执行的是子类重写父类的方法---虚拟方法调用

3.多态的使用:虚拟方法使用

有了对象的多态性以后,我们在编译期,只能调用父类中声明的方法,但在运行期,我们实际执行的是子类重写父类的方法,总结:编译看左边,运行看右边。

4.多态性的使用前提:①要有类的继承关系 ②要有方法的重写

5.对象的多态性只适用于方法,不适用于属性,对于定义的属性(编译和运行都看左边)

instanceof关键字的使用

a instanceof A :判断对象a是否是类A的实例。如果是,返回ture;如果不是,返回false

使用情境:为了避免在向下转型时出现ClassCastException的异常,我们在向下转型之前,先进行instanceof的判断,一旦返回true,就进行向下转型。如果返回false,不进行向下转型

例:

if(p2 instanceof Woman){
Woman w1 = (Woman)p2;
w1.goShooping();
}

如果a instanceof A返回true,则a instanceof B 也返回true

其中,类B是类A的父类。

Object类的使用

1.Object类是所有Java类的跟父类

2.如果在类的声明中未使用extends关键字指明其父类,则默认父类为Java.long.Object类

3.Object类中声明的功能(属性、方法):就具有通用性

属性:无

方法:

equals() /toString()/getClass()/hashCode()/clone()/finalize()/
wait()/notify()/notifyAll()

4.Object类只声明了一个空参的构造器

面试题:  == 和equals的区别

一、== 运算符

1.可以使用在基本数据类型变量和引用数据类型变量中

2.如果比较的是基本数据类型:比较两个变量保存的数据是否相同。(不一定类型要相同)如果比较的是引用数据类型:比较两个对象的地址值是否相同。即两个引用是否指向同一个对象实体。补充:==符号使用时,必须保证符号左右两边的变量类型一致

二、equals()方法的使用

1.是一个方法,而非运算符

2.只能适用于引用数据类型

3.Object类中的equals()的定义:

public boolean equals(Object obj){
return (this == obj);
}

说明:Object 类中定义的equals()和==的作用是相同的:比较两个对象的地址值是否相同,即两个引用是否

指向同一个对象实体

4.像String、Date、File、包装类等都重写了Object类中的equals()方法。重写以后,比较的不是两个引用的地址是否相同,而是比较两个对象实体的“实体内容”是否相同

5.通常情况下,我们自定义的类如果使用equals()的话,也通常是比较两个对象的“实体内容”是否相同,那么,我们就需要对Object类中声明的equals()进行重写,重写的原则:比较两个对象的实体内容是否相同

包装类

包装类:  int --> lnteger;          char --> Character;  其它七种都是首字母大写。所有数值型的类型都继承于Number

基本数据类型、包装类、String三者之间的转换

基本数据类型转换成包装类,调用包装类的构造器

包装类转换成基本数据类型,调用包装类的xxxValue()

自动装箱:基本数据类型转换成包装类

int num = 12;
Integer in = num;

自动拆箱:包装类转换成基本数据类型

int num1 = in;

基本数据类型、包装类 --> String类型:调用String重载valueOf(Xxx xxx)

String 类型---> 基本数据类型、包装类: 调用包装类的parseXxx(String s)

Static关键字的使用

1.static:静态的

2.static:可以用来修饰:属性、方法、代码块、内部类

3.使用static修饰属性:静态变量(类变量)

3.1 属性:按是否使用static修饰,又分为:静态属性vs非静态属性(实例变量)

实例变量:我们创建了类的多个对象,每个对象都独立的一套类中的非静态属性,当修改其中一个对象中的非静态属性时,不会导致其他对象中同样的属性值修改。

静态变量:我们创建了类的多个对象,多个对象共享同一个静态变量,当通过某一个对象修改静态变量时,会导致其他对象调用此静态变量时,是修改过了的。

3.2static修饰属性的其他说明:

 ①静态变量随着类的加载而加载。可以通过“类.静态变量”的方式进行调用

 ②静态变量的加载早于对象的创建

 ③由于类只会加载一次,则静态变量在内存中也只会存在一份,存在方法区的静态域中。

④ 类变量 实例变量

类 yes no

对象 yes yes

4.使用static修饰方法:静态方法

①随着类的加载而加载,可以通过“类.静态方法”的方式进行调用

② 静态方法 非静态方法

类 yes no

对象 yes yes

③静态方法中,只能调用静态的方法或属性

非静态方法中,既可以调用非静态的方法或属性,也可以调用静态的方法或属性

5.static注意点

5.1在静态的方法内,不能使用this关键字、super关键字

5.2关于静态属性和静态方法的使用,大家都从生命周期的角度去理解

6.开发中,如何确定一个属性是否需要声明为static的?

属性式可以被多个对象所共享的,不会随着对象的不同而不同的,类中的常量也常常声明为static

开发中,如何确定一个方法是否需要声明为static的?

操作静态属性的方法,通常设置为static的,工具类中的方法,习惯上声明为static的,比如:Math、Arrays、Collections

单例设计模式

单例设计模式:(饿汉式)

1.所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例

2.如何实现?饿汉式vs懒汉式

2.1私有化构造器

2.2内部创建类的对象   要求此对象也必须声明为静态的

2.3提供公共的静态的方法,返回类的对象

懒汉式

1.私有化类的构造器

2.先声明当前类对象,没有初始化  此对象也必须声明为static的

3.声明public、static的返回当前类对象的方法

区分饿汉式和懒汉式

懒汉式:好处,延迟对象的创建;目前的写法坏处,线程不安全

饿汉式:坏处,对象加载时间过长;好处,饿汉式是线程安全的

代码块

代码块(初始化块){ }

1.代码块的作用:用来初始化类、对象

2.代码块如果有修饰的话,只能使用static

3.分类:静态代码块vs非静态代码块

4.静态代码块

内部代码块可以有输出语句

随着类的加载而执行而且只执行一次

作用:初始化类的信息

如果一个类中定义了多个静态代码块,则按照声明的先后顺序执行

静态代码块的执行,优先于非静态代码块的执行

静态代码块内只能调用静态的属性、静态的方法,不能调用非静态的结构

5.非静态代码块

内部代码块可以有输出语句

随着对象的创建而执行

每创建一个对象,就执行一次非静态代码块

作用:可以在创建对象时,对对象的属性进行初始化

如果一个类中定义了多个非静态代码块,则按照声明的先后顺序执行

非静态代码块内可以调用静态的属性、静态的方法、或非静态的属性、非静态的方法

对属性可以赋值的位置:

①默认初始化;②显示初始化/⑤在代码块中赋值;③构造器中初始化;

④有了对象以后,可以通过对象.属性或对象.方法的方式进行赋值

执行的先后顺序:① - ② / ⑤ - ③ - ④

Final关键字的使用

final:最终的

1.final可以用来修饰的结构:类、方法、变量

2.final用来修饰一个类:此类不能被其他类所继承

比如:String、System、StringBuffer类

3.final用来修饰方法:表明此方法不可以被重写

比如:Object类中getClass()

4.final用来修饰变量:此时的”变量“就称为是一个常量

4.1final修饰属性:可以考虑赋值的位置有:显示初始化、代码块中初始化、构造器初始化

4.2final修饰局部变量:

尤其是使用final修饰形参时,表明此形参是一个常量,当我们调用此方法时,给常量形参赋一个实参。一旦赋值以后,就只能在方法体内使用此形参,但不能进行重新赋值。

static final :用来修饰属性:全局常量;

抽象类和抽象方法

abstrct关键字的使用

1.abstract:抽象的

2.abstract可以用来修饰的结构:类、方法

3.abstract修饰类:抽象类

此类不能实例化,抽象类中一定有构造器,便于子类实例化时调用(涉及:子类对象实例化的全过程),开发中,都会提供抽象类的子类,让子类对象实例化,完成相关操作

4.abstract修饰方法:抽象方法

抽象方法只有方法的声明,没有方法体,包含抽象方法的类一定是抽象类,反之,抽象类中是可以没有抽象方法的。若子类重写了父类中的所有的抽象方法后,此子类方可实例化若子类没有重写了父类中的所有抽象方法,则此子类也是一个抽象类,需要使用abstract修饰

abstract使用上的注意点:

1.abstract不能用来修饰:属性、构造器等结构

2.abstract不能用来修饰私有方法、静态方法、final的方法、final的类

接口

接口的使用

1.接口使用interface来定义

2.在Java中,接口和类是并列的两个结构

3.如何定义接口,定义接口中的成员

3.1JDK7及以前:只能定义全局常量和抽象方法

全局常量:public static final的,但是书写时可以省略

抽象方法:public abstract的

3.2JDK8:除了定义全局常量和抽象方法之外,还可以定义静态方法、默认方法

1.接口中定义的静态方法,只能通过接口来调用

2.通过实现类的对象,可以调用接口中的默认方法,如果实现类重写了接口中的默认方法,调用时,任然调用的是重写以后的方法

3.如果子类(或实现类)继承的父类和实现的接口中声明了同名同参的数的方法,

那么子类在没有重写此方法的情况下,默认调用的是父类中的同名同参的方法。-->类优先原则

4.如果实现类实现了多个接口,而这多个接口中定义了同名同参数的默认方法,

那么在实现类没有重写此方法的情况下,报错--->接口冲突,这就需要我们必须在实现类中重写此方法

4.接口中不能定义构造器。意味着接口不可以实例化

5.Java开发中,接口通过让类去实现(implements)的方式来使用

如果实现类覆盖了接口中的所有抽象方法,则此实现类就可以实例化

如果实现类没有覆盖了接口中的所有抽象方法,则此实现类仍为一个抽象类

6.Java类可以实现多个接口 --> 弥补了Java单继承性的局限性

格式:class AA extends BB implements CC,DD,EE

7.接口和接口之间可以继承,而且可以多继承

8.接口的具体使用,可以体现多态性

接口的使用:1.接口使用上也满足多态性;2.接口,实际上就是定义了一种规范;3.开发中,体会面向接口编程

9.接口实际上就可以看作一种规范

内部类

1.Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类

2.内部类的分类:成员内部类(静态的、非静态的)vs局部内部类(方法内、代码块内、构造器内)

3.成员内部类:

一方面:作为内部类的成员

调用外部类的成员

可以用static修饰

可以被四种不同的权限修饰

另一方面:作为一个类:

类内部可以定义属性、方法、构造器等

可以被final修饰,表示此类不能被继承,言外之意,不使用final,就可以被继承

可以被abstract修饰

4.关注如下的三个问题:

4.1如何实例化成员内部类的对象

4.2如何在成员内部内中区分调用外部类的结构

4.3开发中局部内部类的使用

异常处理

Error

1.栈溢出:Java.lang.StackOverflowError

2.堆溢出:Java.lang.OutOfMemoryError

Exception

一、异常的体系结构       Java.lang.Throwable

java.lang.Error:一般不编写针对性的代码进行处理

java.lang.Exception:可以进行异常的处理

编译时异常(checked);IOException--FileNotFoundException;  ClassNotFoundException

运行时异常(unchecked、RuntimeException); NullPointerException; ArrayIndexOutOfBoundsException;ClassCastException;NumberFormatException;InputMismatchException;ArithmeticException

一、异常处理:抓抛模型

过程一:”抛“:程序在正常执行的过程中,一旦出现异常,就会在异常代码处生成一个对应异常类的对象,并将此对象抛出,一旦抛出对象后,其后代码就不在执行

关于异常对象的产生:①系统自动生成的异常对象②手动的生成一个异常对象,并抛出(throw)

过程二:”抓“:可以理解为异常的处理方式:①try-catch-finally;  ②throws

二、try-catch-finally的使用

try{
//可能出现异常的代码
}catch(异常类型1 变量名1){
//处理异常的方式1
}catch(异常类型2 变量名2){
//处理异常的方式2
}catch(异常类型3 变量名3){
//处理异常的方式3
}.......
finally{
//一定会执行的代码
}

二、try-catch-finally中finally的使用

1.finally是可选的

2.finally中声明的是一定会被执行的代码,即使catch中又出现异常了,try中有return语句,catch中有return语句等情况。

3.向数据库连接、输入输出流、网络编程Socket等资源,JVM是不能自动的回收的,我们需要自己手动的进行资源的释放,此时资源释放,就需要声明在finally中,说明:1.finally是可选的

2.使用try将可能出现异常代码包装起来,在执行过程中,一旦出现异常,就会生成一个对应异常类的对象,根据此对象的类型,去catch中进行匹配

3.一旦try中的异常对象匹配到某一个catch时,就进入catch中进行异常的处理,一旦处理完成就跳出当前的try-catch结构(在没有写finally的情况),继续执行其后的代码

4.catch中的异常类型,如果没有子父类关系,则谁声明在上,谁声明在下无所谓,catch中的异常类型如果满足子父类关系,则要求子类一定声明在父类的上面,否则,报错

5.常用的异常处理的方式:①String getMessage()  ②printStackTrace()

6.在try结构中声明的变量,再出了try结构以后,就不能在被调用

7.try-catch-finally结构可以相互嵌套

体会1:使用try-catch-finally处理编译时异常,是程序在编译时就不在报错,但是运行时仍可能报错,相当于我们使用try-catch-finally将一个编译时可能出现的异常,延迟到运行时出现。

体会2:开发中,由于运行时异常比较常见,所以我们通常就不针对运行时异常编写try-catch-finally了针对于编译时异常,我们说一定要考虑异常的处理

异常处理方式二:throws + 异常类型

1.throws + 异常类型写在方法的声明处,指明此方法执行时,可能会抛出的异常类型,一旦当方法体执行时,出现异常,仍会在代码异常处生成一个异常类的对象,此对象满足throws后异常类型时,就会被抛出。异常代码后续的代码就不在执行了

2.体会:try-catch-finally:真正的将异常给处理了throws的方式只是将异常抛给了方法的调用者,并没有真正将异常处理掉。

3.开发中如何选择使用try-catch-finally 还是使用throws?

3.1如果父类中被重写的方法没有throws方式处理异常,则子类重写的方法也不能使用throws,意味着如果子类重写的方法中有异常,必须使用try-catch-finally方式去处理

3.2执行的方法中,先后又调用了另外的几个方法,这几个方法是递进关系执行的,我们建议这几个方法使用throws的方式进行处理,而执行的方法可以A可以考虑使用try-catch-finally方式进行处理

如何自定义异常类:

1.继承于现有的异常结构:RuntimeException、Exception

2.提供全局常量:serialVersionUID

3.提供重载的构造器

多线程

程序:是为完成特定任务、用某种语言编写的一组指令的集合,即指一段静态代码,静态对象

进程:是程序的一次执行过程,或是正在运行的一个程序。是一个动态的过程,有它自身的产生、存在和消亡的过程------生命周期

线程:进程可以进一步细化为线程,是一个程序内部的一条执行路径

并行:多个CPU同时执行多个任务,

并发:一个CPU(采用时间片)同时执行多个任务。

多线程的创建:方式一:继承于Thread类  方式二:创建Thread类的匿名子类的的方式

1.创建一个继承于Thread类的子类

2.重写Thread类的run()-->将此线程执行的操作声明在run()中

3.创建Thread类的子类的对象

4.通过此对象调用start():①启动当前线程;②调用当前线程的run()方法

问题一:我们不能通过直接调用run()的方式启动线程

问题二:再启动一个线程,不可以还让已经start()的线程再去执行,会报异常,我们需要重新创建一个线程的对象,再去调用start

Thread中的常用方法:

1.start():启动当前线程,调用当前线程的run()方法

2.run()通常需要重写Thread类中的此方法,将创建的线程要执行的操作声明在此方法中

3.currentThread():静态方法,返回执行当前代码的线程

4.getName():获取当前线程的名字

5.setName():设置当前线程的名字

6.yield():释放当前cpu的执行权

7.join():在线程A中调用线程B的join(),此时线程A就进入阻塞状态,知道线程B完全执行完以后,线程A才结束阻塞状态。

8.sleep(long millitime):让当前线程”睡眠“,指定的millitime毫秒,在指定的millitime毫秒时间内,当前线程是阻塞状态

9.isAlive():判断当前线程是否存活

线程的优先级:

1.MAX_PRIORITY:10;     MIN_PRIORITY:1;     NORM_PRIORITY:5(默认优先级)

2.如何获取和设置线程的优先级:

getPriority():获取线程的优先级

setPriority(int p):设置线程的优先级

说明:高优先级的线程要抢占低优先级线程的cpu的执行权,但是只是从概率上讲,高优先级的线程高概率的情况下被

执行,并不意味着只有当高优先级的线程执行完以后,低优先级的线程才执行。

创建多线程的方式二:实现Runnable

1.创建了一个实现Runnable接口的类

2.实现类去实现Runnable中的抽象方法:run()

3.创建实现类的对象

4.将此对象作为参数传递到Thread类的构造器中,创建Thread类的对象

5.通过Thread类的对象调用start()

比较创建线程的两种方式

开发中:优先选择:实现Runnable接口的方式

原因:1.实现的方式没有类的单继承性的局限性

2.实现的方式更适合来处理多个线程有共享数据的情况

联系:Thread类本身实现了Runnable接口

相同点:两种方式都需要重写run(),将线程要执行的逻辑声明在run()方法中。

1.问题:卖票过程中,出现了重票、错票 --> 出现了线程安全问题

2.问题出现的原因:当某个线程操作车票的过程中,尚未操作完成时,其他线程参与进来,也操作车票。

3.如何解决:当一个线程a在操作ticket的时候,其他线程不能参与进来,直到线程a操作完ticket的时候,其他线程才可以继续操作ticket。这种情况,即使线程a出现了阻塞,也不能被改变

4.在Java中,我们通过同步机制来解决线程的安全问题

方式一:同步代码块

synchronized(同步监视器){

//需要被同步的代码

}

说明:1.操作共享数据的代码,即为需要被同步的代码。--->不能包含代码多了,也不能包含代码少了

2.共享数据:多个线程共同操作的变量。比如:ticket就是共享数据。

3.同步监视器:俗称:锁。任何一个类的对象都可以充当锁

要求:多个线程必须要共用同一把锁。

补充:在实现Runnable接口创建多线程的方式中,我们可以考虑使用this重当同步监视器。在继承THread类创建多线程的方式中,慎用this同步监视器,可以考虑使用当前类充当同步监视器

方式二:同步方法,如果操作共享数据的代码完整的声明在一个方法中,我们不妨将此方法声明同步的。

关于同步方法的总结:

1.同步方法仍然涉及到同步监视器,只是不需要我们显示的声明。

2.非静态的同步方法,同步监视器时:this

静态的同步方法,同步监视器是:当前类本身

5.同步的方式,解决了线程安全的问题。---好处:操作同步代码时,只能由一个线程参与,其他线程等待。相当于是一个单线程的过程,效率低---局限性

解决线程安全的方式三:Lock锁 --- JDK5.0新增

1.实例化ReentrantLock;2.调用锁定方法Lock();3.调用解锁方法unLock()

1.面试题:synchronized与lock的异同?

相同:二者都可以解决线程的安全问题

不同:synchronized机制在执行完相应的同步代码以后,自动的释放同步监视器

lock需要手动的启动同步(lock()),同时结束同步也需要手动的实现(unlock())

2.优先使用顺序:lock -- 同步代码块(已经进入了方法体,分配了相应资源)-- 同步方法(在方法体之外)

JDK5.0新增的创建线程的方式

方式三:实现Callable接口

1.创建一个实现Callable接口的实现类class NumThread implements Callable{

2.实现call方法  ,将此线程需要执行的操作声明在call方法中

3.创建Callable接口实现类的对象NumThread numThread = new NumThread();

4.将此Callable接口实现类的对象作为传递到FutureTask构造器中,创建FutureTask的对象FutureTask futureTask = new FutureTask(numThread);

5.将FutureTask类的对象作为参数返回值传递到Thread类构造器中,创建Thread的对象,并调用start()

6.可以获取Callable中Call方法的返回值Object sum = futureTask.get();

如何理解实现Callable接口的方式创建线程比实现Runnable接口创建多线程更强大?

1.call()方法可以有返回值

2.call()方法可以抛出异常,被外面的操作捕获,获取异常的信息

3.Callable是支持泛型的

方式四:使用线程池

1.提供指定线程数量的线程池ExecutorService service = Executors.newFixedThreadPool(10);

2.执行指定的线程的操作,需要提供实现Runnable或Callable接口实现类的对象

service.execute(new NumberThread());//适合适用于Runnable

service.submit();//适合适用于Callable

3.关闭连接池  service.shutdown();

好处:1.提高相应速度(减少创建新线程的时间)

2.降低资源消耗(重复利用线程池中线程,不需要每次都创建)

3.便于线程管理

corePoolSize:核心池的大小

maximumPoolSize:最大线程数

keepAliveTime:线程没有任务时最对保持多长时间后会终止

死锁

死锁的理解:不同的线程分别占用对方需要的同步资源不放弃,都在等待对方

放弃自己需要的同步资源,就形成了线程的死锁。

说明:1.出现死锁后,不会出现异常,不会出现提示,只是所有的线程都处于阻塞状态,无法继续2.我们使用同步时,要避免出现死锁。

线程通信

涉及到的三个方法:

wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器

notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个

notifyAll():一旦执行此方法,就会唤醒所有被wait的线程

说明:

1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中

2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。否则,会出现ILLegaLMonitorStateException异常

3.wait(),notify(),notifyAll()三个方法是定义在Java.long.Object类中

面试题:sleep()和wait()方法的异同?

1.相同点:一旦执行方法都可以使得当前的线程进入阻塞状态

2.不同点:1)两个方法声明的位置不同:Thread类中声明sleep(),Object类中声明wait()

2)调用的范围不同:sleep()可以在任何需要的场景下调用wait()必须使用在同步代码块或同步方法中

3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁