java学习过程

day1

xiao.java(高级语言) ->(编译) xiao.class(字节码语言)

Java程序执行原理:

机器语言、汇编语言、高级语言
不管是什么高级语言 最终都会被编译成机器语言
bug. Debug(解决问题)

开发工具
javac 编译
java 执行

JDK的组成

JVM: java虚拟机:运行java程序的地方
核心类库:Java自己写好的程序给程序员自己调用
JRE: java的运行环境
JDK: java开发工具包

JDK有哪些组成

JVM虚拟机
核心类库
开发工具:Java javac

java跨平台

一次编译,处处可用

开发环境

集成开发环境:IDE
把代码的编译、编写、执行等多种功能综合到一起的开发工具,可以进行代码的智能提示错误提示、项目管理等
常见的java的IDE工具:eclipse等

IDEA

企业开发首选工具

IDEA项目结构

project(项目、工程)
module(模块)
package(包)
class(类)

java基础语法

注释

注释是写在程序中对代码进行解释说明的文字
特点:不影响程序执行

/**文档注释
*/  
/*多行注释
*/
//单行注释
字面量

计算机用来处理数据的数据的 字面量就是告诉程序员:数据在程序中的书写格式

变量

变量用来存储一个数据的内存区域,且里面存储的数据可以变化 存储数据的,可以改变的

变量使用注意事项

1、先声明,在使用
2、变量声明后。不能在存储其他类型的数据
3、变量作用域从开始到}截止,且不能出现两个同名变量
4、定义变量时可以没有初值,但是使用时必须给初始值

变量在计算机中的底层原理

数字二进制存储数据
字符ASCLL码存储二进制形式
图片无数个像素点:0- 255255255表示颜色。也是二进制形式

数据类型

引用数据类型:String
基本数据类型:4大类8种

整数:
byte -128~127 内从占用(字节数)1
解释 一共有256个数据 -128 ~-1 0 ~127
short 2字节 int 4。long 8
浮点数: float 4。double 8
字符 char 2
布尔 boolean 1

关键字,标志符

关键字 不能用来做为类名

标识符。不能数字开头

命名规则
变量 首字母小写
类名 首字母大写

类型转换

自动类型转换
类型范围小的变量,可以直接赋值给类型范围大的变量

表达式的自动类型转换
小范围的变量会自动转换成较大范围的类型在运算
byte、short、char->int->long->float->double
表达式最终类型由最高类型决定
表达式中byte、short、char直击转换成int类型参与运算

强制类型转换
需要将大范围的变量赋值给小范围的变量

int a = 20byte b =byte)a;

注意事项:
可能出现数据丢失
小数强制转换成整数会直接截断小数保留整数

运算符

对字面量或者变量进行操作的符号

算术运算符 + - * / %

整数除法得到的结果是整数

“+”符号可以充当连接符

“+”可以与字符串运算的时候用做连接符,结果仍是字符串
方法:能算就算,不能算就连在一起

++ – 自增自减
赋值运算符 = += -= *= /= %=
关系运算符 = = != > < <= >=
逻辑运算符 &与 !非 |或 ^异或
三元运算法。条件表达式?值1:值2;

day2

程序流程控制

顺序结构
分支结构 if switch

switch
表达式类型只能是 byte short int char. JDK7开始支持String
case不允许重复,且只能是字面量,不能是变量
必须写break,否则会出现穿透性现象

循环结构 for while do……while

数组

用来存储一批同种类型数据的内存区域

学习:如何定义 具体格式
如何操作元素:获取修改数据。
怎么解决实际问题:如随机点名等
内存原理 工作原理
注意点

数组的定义

静态初始化数组
数据类型[] 数组名 = new 数据类型[]{元素1,元素2}
数据类型[] 数组名 = {元素1,元素2}

访问数组:数组名[索引]
数组长度:数组名.length

数组一旦定义出来 数组长度类型就固定了

动态初始化数组
数据类型[] 数组名 = new 数据类型[长度]、
定义数组时只确定数组的长度

数组的遍历

遍历:一个一个的数据访问

数组的内存图

栈 堆 方法区 本地方法栈 寄存器

方法区:字节码文件加载时进入的内存
栈内存:方法运行时进去的内存。变量也在这里
堆内存:new出的东西会在堆内存中开辟空间并产生地址

代码进去方法区域。main方法 进入栈内存开始运行 ,开辟变量的存储空间
遇到引用数据类型时会在堆内存中开辟被引用变量的地址
并且在栈中存储所引用变量的首地址

int[] arr1 = {1,2,3};
int[] arr2 = arr1;
/*arr2 被赋值的是arr1所指向的地址 因此改变arr1中的值。
arr2也会改变
*/
数组中存在的问题

问题一:访问元素位置超出最大索引,执行时会出现ArrayindexOutOfBoundsException(数组索引越界异常)

问题二:数组中变量没有存储数组的地址,而是null,在访问数组信息就回出现NullPointerException(空指针异常)
//数组地址被截断

DeBug工具

自带的断点调试工具,可以控制代码从断点开始一行一行的执行,然后详细的观看程序执行情况
1、形成断点。2、使用DeBug执行,会在断点停止执行
3、控制代码一行一行的执行观察

方法

方法是一种语法结构,将一段代码封装成一个功能,重复使用

好处:
1提高代码复用性 2让程序逻辑更清晰

掌握。定义方法 调用方法(使用) 方法内存图 方法的参数传递机制 方法常见形式,技术

方法定义

方法格式:
修饰符 返回值类型 方法名 (形参列表)
{
return 返回值;
}

分析:方法是否需要返回值,形参列表

方法调用内存图

没被调用时会在方法区的字节码文件中存放
方法被调用时,需要进入栈内存中运行
(进入栈运行结束后 就会自行释放)

方法的运行区域 :栈内存

方法的参数传递机制

基本数据类型:值传递
实参传递给形参值传递
形参修改不影响实参

引用数据类型:地址传递
通过形参改变传递地址所指向地址的值内容,则访问实参所指向的地址时会发现值内容改变

方法重载

同一个类中,方法名相同,形参列表不同
不用在意修饰符
e

面向对象

设计对象并使用

设计类 设计对象并使用

类:是对象共同特征的描述
对象:真实存在的具体实例

定义类
public class 类名{
成员变量 成员方法 构造器 代码块 内部类
}

得到类的对象
类名 对象名 = new 类名();

适用对象
访问属性 对象名.成员变量
访问行为 对象名.方法名()

注意事项:成员变量定义时一般无需指定初始值,存在默认值
类名首字母建议大写且有意义
一个java文件可以定义多个class类 且只能有一个类被public修饰,且被public修饰的类名必须成为代码文件名

实际开发中建议一个文件中定义一个类

对象内存图

多个对象内存图
对象放在对内存中
Car c = new Car() c存储的是对象在对内存中的地址
成员变量的数据放在对象中 对象在堆内存中

两个变量指向同一个对象
引用变量存储的是地址
因此修改任意一个会同时修改

垃圾回收 当堆内存中的数组对象或类对象没有被任何变量引用(指向)时,会被判定为垃圾
java存在自动的垃圾回收机制

构造器

学习目的 对象具体是同过调用什么代码完成的
掌握为对象属性赋值的其他写法

作用 初始化一个类的对象 并返回对象的地址

构造器定义格式
修饰符 类名(形参列表) {
}

初始化对象的格式:
类型 变量名 = new 构造器;
例子:Car c = new Car();

分类:
无参构造器(默认存在的):初始化的对象,成员变量的数据均采用默认值
有参构造器:初始化对象的同时为对象赋值

注意:任意类定义出来就默认定义了无参构造器,写不写都有
一旦定义了有参构造器,无参构造器就消失了

this关键字

作用:出现在成员方法,构造器中代表当前对象的地址,用于访问当前对象的成员变量、成员方法

封装(三大特征之一)

合理隐藏,合理暴露

封装的实现步骤:
1、一般对成员变量使用private(私有)关键字修饰
,之后只能在此类中访问。
2、提供public修饰的公开的gettet、setter方法暴露其取值和赋值

封装好处:
增强了安全性
适当的封装提高开发效率,更易理解与维护

标准JavaBean

可以理解为实体类,其对象可以用于在程序中封装数据

要求:成员变量 private
提供每一个成员变量对应的 set/get
必须提供一个无参构造器

成员变量和局部变量

成员变量:类中 方法外。 有默认初始值。内存位置:堆内存中 随对象创建而存在,随对象消失而消失

局部变量:方法内 无默认初始值 使用之前需要先完成赋值 内存位置:栈内存 随方法存在

常用API String Arraylist()

String
String类定义的变量可以用于存储字符串,同时String类提供了很作字符串的功能

ArrayList代表的是集合类,集合是一种容器,与数组类似,不同的是集合大小不固定
通过创建ArrayList的对象得到一个集合容器,同时ArrayList提供了比数组更好用的功能给程序员使用

String概述

java.lang.String类代表字符串,String类定义的变量可用于指向字符串对象,然后操作字符串
java中所有的“”都可代表此类对象

String是不可变字符串原因
String变量的每次修改其实是指向新的字符串对象
原来的字符串对象都是没有改变的

创建对象的两种方式

一、“”创建
String c = “1”
二、通过String提供的构造器创建

String s = new String(String)

面试考试:
1、以“”方式给出的字符串对象,在字符串常量池中存储,而且相同的内容只会在其中存储一份
2、通过构造器new对象,每new一次都会产生一个新对象,存放在对内存中

注:“”在常量池中。其他的都在堆内存中。

String常用API-字符串内容比较

== 比较的是地址
字符串内容比较不适合用 ==

对字符串内容比较:
public boolean equals(Object anObject) 字符串对象比较 只关心内容
public boolean equalsIgnoreCase(String anotherString) 忽略大小写

==适用于基本数据类型

遍历字符串中的每个字符
String name = “1234234”
for(int i = 0;i < name.length();i++){ //length获取长度
char ch = name.charAt(i); //charAt(int)获取某个位置的字符
System.out.println(ch);
}

将字符串转化成字符数组
char[] chars = name.toCharArray();

截取内容
subsString(int beginIndex int endIndex). 包前不包后
String rs = name.subsString(0 3)
输出得到 123
也可以 String rs2 = name.subsString(3)
输出3234

替换
replace
String r3 = name.replace(“1” ,replacement “***”)
输出 *234234

包含判断contants
name.contants(“12”)
输出 true

starstWith()判断以什么开始。结果boolean

按照某个内容把字符串分割成字符串数组返回
public String[] split(String)
String name4 = “1,2,3,4”
String[] names = name4.split(regex",")
然后就被以逗号分隔放入数组

ArrayList

集合大小可变
数组定义后长度固定

数组适合做长度类型确定的场景

ArrayList集合

ArrayList是集合的一种,他支持索引

ArrayList集合的对象获取
构造器
public ArrayList()
添加元素
public boolean add(E e)指定元素添加到集合末端
public void add(int index,E element)指定元素添加到指定位置

ArrayList泛型

ArrayList,一个范型类,可以在变异阶段约束只能操作某种数据类型

ArrayList< integer >只能整型

ArrayList常用API,遍历

public E get(int Index)获取某个位置的元素值
public int size()返回集合大小
遍历
Arraylist list = new Arraylist();
//Arraylist<> list = new Arraylist<>();
for(i = 0;i < list.size;i++)
{
System.out.println(list.get(i));
}

根据索引删除元素并返回给你给元素
public E remove(int index)

直接删除该元素
public boolean remove(Obiect o)

修改某个索引位置处的元素值 set(int index,E element)

存储自定义类型

集合存储的不是元素本身而是元素的地址

static

静态的意思(static 属于类,内存只加载一次),表需要共享的信息。
静态成员变量可以通过类名访问
加载类的同时加载静态成员变量(堆内存)

方法有无 static

成员方法分类 :静态(有static)
实例(无static)
方法作用是通用功能与对象作用无关 用static

静态方法和main方法都在 方法区 内

static制作工具类:

建议将工具类构造器私有,不让其产生对象

static注意事项:
1、静态方法只能访问静态成员,不可以直接访问实例成员
2、实例方法可以访问静态成员,也可以访问实例成员
3、静待方法不能用this关键字

代码块

代码块定义在类中方法外
分为:
静态代码块:
static{
}
与类一起加载,自动触发一次 优先执行
作用:可以在程序加载时对静态数据初始化操作

构造代码块(实例代码块)
{}
每次创建对象时,都会在构造器执行前执行一次

设计模式-单例模式

可以保证系统永远只有一个实例:类永远只能创造一个对象

场景作用
只需一个可以解决问题

饿汉单例

在类获取对象的时候 对象已经为你提前创建好了

步骤
定义一个类 构造器私有(别的类不能new该类对象)
定义一个静态变量存储一个对象

懒汉单例

在真正需要该对象的时候才去创建一个对象(延迟加载对象)
步骤
定义一个类 构造器死后
定义一个静态变量存储一个对象
提供一个返回单例对象的方法
class xiao
{
private static xiao x1;//null

private xiao{}

public static xiao getx1{
if(x1 == null)
x1 = new xiao();
return x1;
}

}

继承 entends

继承是子类和父类的一种关系

子类继承父类,可以得到父类的行为和属性

继承的设计规范和继承原理

子类们的共同特征(公共属性和公共方法)放在父类中定义,子类独有的属性和行为应该定义在子类自己里面

继承的特点

1、子类可以继承父类的属性和行为,但子类不能继承父类的构造器
2、java是单继承模式,一个类只能有一个父类
3、java支持多层继承
4、Java中所有类都是Objiect类的子类,objiect是祖宗类
5、子类可以继承父类的私有成员,但是不能直接访问
6、静态成员是共享给子类的,并非继承

继承后 成员变量和成员方法的访问特点

满足就近原则
先子类局部范围着,在子类成员范围找,在父类成员范围找,找不到报错

继承后方法重写

继承后子类和父类出现了一样的方法声明,成为方法重写
静态成员 方法由于没有被继承 所以不能重写

@Override重写注解
写在方法上,作为重写是否正确的校检注解
加上注解后如果重写错误,编译阶段就会出现错误提示
建议重写的方法都加上注解

方法修饰符 子类需大于父类
注解可以校检重写是否正确
方法重写重写 方法名形参列表一致
私有方法不能被重写

继承后 子类构造器

子类中的所有构造器都会默认先访问父类中的午餐构造器,再执行自己
原因:子类对象初始化之前一定要先完成父类对象的初始化

默认:子类会先执行 super();调用父类无参构造器

继承后 子类访问父类有参构造器

super 调用父类有参构造器的作用:
初始化父类中的数据

如果父类中没有无参构造器,只有有参构造器会报错
因为子类默认调用父类无参构造器

子类构造器可以通过super(…)默认调用父类的有参构造器

super:父类空间的标识
super.成员方法。访问父类成员方法 super(…)访问父类构造器

this 子类对象的引用

用this()调用子类构造器时会默认调用父类构造器
this()和suprt()都只能放在第一行 不能出现在同一个构造器中「兄弟构造器」。

用来分别不同类的,类似于文件夹,建包利于程序的管理与维护
建包语法格式 公司域名.技术名称

不同包下的类必须导包才可以使用

权限修饰符

private -> 缺省 ->protected->public

成员变量一般私有
方法一般公开
只希望本类访问 用private
只希望本类 同一个包内其他类。不同包下子类。用protected

final

最终的意思
修饰方法:不能被重写
修饰变量:只能赋值一次 变量:局部。 成员(静态 实例)
修饰类:不能被继承

注意:final 修饰的变量时基本数据类型:内容不能改变
final修饰引用数据类型:地址不能改变 但是地址的内容可以改变
final int[] arr = {1,2,3}
arr = null;//报错
arr[1] = 3 ;//正确

常量

使用 public static final修饰的成员变量 必须有初始化 且执行过程中其值不能被改变
命名规则:英文单词全部大写,多个单词用下划线连接起来

信息标志和分类

可读性好 软编码

枚举

枚举是一种特殊的类型
作用“信息的标志和分类”

定义枚举的格式:
修饰符 enum 枚举名称{
第一行都是罗列枚举的实例名称
}

抽象类

抽象类由 abstract 修饰
约束子类 模版
抽象方法:
抽象类定义出的子类必须完成的功能
没有方法体只有方法签名必须有absteact修饰

注意事项:抽象类是用来继承的
一个类继承了抽象类,必须重写所有的抽象方法都则这个类也称为抽象类

抽象类的特征

得到了抽象方法 不能创建对象
因为:抽象方法调用时运行不了。因此抽象类不可以实例化

类的成员(成员变量方法构造器)抽象类都具备

抽象类可以没有抽象方法,有抽象方法的类是抽象类

不能用abstract修饰 变量 代码块 构造器

模版方法模式

当系统出现同一个功能多处开发,而该功能大部分代码一样,只有部分可能不同的时候
(相同的抽出来)
模版方法实现步骤
把功能定义称为一个所谓的模版方法 放在抽象类中 模版方法中只定义通用且明确的代码
模版方法中不能决定的功能定义成抽象方法的具体子类去实现

模版方法建议使用final修饰方法。

接口

体现规范的,其中抽象方法定规的一组行为规范,接口是彻底的抽象

定义:
public interface 接口名{
常量名 抽象方法
}

接口用法:
被类实现(implements)的,实现接口的类成为实现类

类 单继承 多实现
一个接口可以继承多个接口

接口多继承作用:
规范合并,多个接口为一个接口便于子类实现

jdk8新增功能

都默认被public修饰

默认方法(等同于实例方法)
default 修饰的方法体

静态方法(必须使用接口名自己调用)
static修饰

私有方法(jdk9)
private修饰(接口内部调用)

注意事项

1、接口不可以创建对象
2、一个类实现多个接口,多个接口有同名的静态方法冲突
(接口的静态方法只能通过接口名调用)
3一个类继承了父类 又实现了接口 父类和借口中的同名方法默认用父类的
4、一个类实现了多个接口,多个接口有同样的方法名不冲突
5、一个接口继承多个接口是没有问题的,但多个接口存在规范问题不能多继承

多态

同类型对象执行同一个行为会表现出不同的行为特征
多态常见形式
父类类型 对象名称 = new 子类构造器
接口 对象名称 = new 实现类构造器

方法调用:编译看左边 运行看右边
变量调用:编译看左边 运行也看左边 (多态侧重行为多态)

多态使用器前提
有继承实现关系,父类引用指向子类对象,有方法的重写

优势 右边对像可以实现解耦合 便于维护和扩展
定义方法时 使用父类作为参数,该方法就可以接受父类的一切子类对象。体现堕胎的扩展性和便利

产生一个问题:
不能使用子类独有的功能

多态下引用数据类型的类型转换

自动类型转换(子->父)

强制类型转换:(父->子)
此时必须进行强制类型转换 :子类 对象变量 = (子类)父亲类型的变量
作用:可以解决多态下的劣势 实现调用子类的独有功能
注意:如果转型后的类型和对象真实的类型不是同一类型,那么转换时就出现 classcastexception

用insta、nceof判断当前对象的真实类型
变量名 instanceof 真实类型
判断关键字左边的类型是否时右边的字类型。正确返回 true

内部类

内部类:寄生。外部类:宿主

当一个事物的内部还有部分需要一个完整的结构进行描述,而这个内部完整结构只为外部事物提供服务
内部类通常可以方便访问外部类的成员,包括私有成员
内部类提供了更好的封装性,同 private’ protected修饰

静态内部类

外部类名.内部类名 对象 = new 外部类名.内部构造器();
使用场景:包含了一个完整部分 如发动机类中的汽车类
特点:与普通类一样 克访问静态 不能直接访问实例

成员内部类 (jdk16之前不能定义静态成)

无static修饰
外部类名.内部类名 对象 = new 外部类构造器().内部类构造器()。 可以直接访问静态和实例成员变量

访问外部类对象。外部类名.this

匿名内部类

本质上是一个没有名字的局部内部类 定义在方法 代码块中
匿名内部类写出来就会出现一个匿名内部类对象
相当于new类型的子类类型

方便创建子类对象
格式;
new 类/抽象类名/接口名(){
重写方法
}
就是说 不用定义子类快速的构建一个对象

employee a = new employee(){
public void work(){
}
}
a.work();

常见使用语法:不是我们主动使用别人需要我们才去写

常用API

Object
toString()

默认返回当前对象的地址
地址毫无意义 、因此存在的意义:
父类中的toString()方法存在的意义是被子类重写,以便返回对象的内容信息

equals

默认比较两个对象的地址是否相同
让子类重写 比较两个对象的内容

Objects

与Object类是继承关系
在进行字符串比较时,没有对象自己的equals方法,而是选择了Objects的equalss方法来比较两个对象
Objects.equals(Object o,Object o);

StringBuilder

是一个可变的字符串类,可以看作是一个对象容器
作用:提高字符串使用效率

StringBuilder构造器
public StringBuilder() 创建一个空白的可变字符串对象,不包括任何内容
public StringBuilder(String str)创建一个指定字符串内容的可变字符串对象

常用方法
public StringBuilder append(任意类型) 添加数据并返回 StringBuilder对象本身
public StringBuilder reverse(). 将任意对象反转
public int length() 返回字符串长度
public String tpString() 通过 toString可以实现吧StringBuilder转化为String

可完整字符串的拼接

Math类

工具类
public static int abs(lint a) 获取参数绝对值。 Math.abs(-10). 10
public static double ceil(double a) 向上取整
public static double floor(double a) 向下取整
public static int round(float a) 四舍五入
public static int max(int a,int b) 获取较大值
public static double pow(double a,double b)返回a的b次幂的值
public static double random()返回为double的随机值,范围为(0.1 ,1.0)

System

功能通用 类名调用即可 不能被实例化
常用方法:
public static void exit(int status)终止运行当前的java虚拟机 非零表示异常终止
public static long currentTimeMills()返回当前系统的时间毫秒值形式
用于计算程序运行时间
public static void arraycopy(被拷贝的数组,从那个位置开始,复制的目标数组,粘贴位置,拷贝元素个数) 数组拷贝

日期与时间

Date

当前时间
构造器
public Date()创建一个Date对象,代表此刻日期时期

常用:
public long getTime()获取时间对象的毫秒值(70年到现在)

对象分为 日期对象和毫秒值对象

public Date(long time) 把时间毫秒值转化为日期对象
public void setTime(long time)日期对象转化为时间毫秒值

空。稍后学习

包装类

实现了一切皆为对象
后期泛型不支持基本数据类型
8中基本数据类型的引用类型
byte Byte
short Short
int Integer
long Long
char Character
float Float
double Double
boolean Boolean
基本数据类型的变量可以赋值给包装数值变量。 包箱
包装数值变量的类型可以直接复制给基本数值变量。拆箱

包装类 特有功能
1、包装类变量 默认为null
2、可以吧基本数据类型的数据转换成字符串类型(
1)调用toString得到字符串结果
2)调用integer.toString(基本数据类型的数据)
可以加个字符串类型“”变成字符串类型

3、可以吧字符串类型的数值转换成真实的数据类型
Integer.parselnt(“字符串类型的整数”)
Double.parseDouble(“字符串类型的小数”)

Integer.valueof(“字符串类型的整数”)
Double.valueof(“字符串类型的小数”)

正则表达式

用一些规定的字符来制定规则,并用来校验数据的合法性

字符串提供了匹配正则表达式规则的API
public boolean matches(String regex)

. 任何字符 \d数字 \s空白 \w英文数字下划线

x?最多一次
x*不是一次
x+不是0次
x{n}真好 n
x{n,} 至少n
x{n,m}至少n至多m

Arrays类

数组操作工具类
常用API
String toString(类型[] a)返回数组内容
void sort(类型[] a)默认升序排序
void sort(类型[] a,Comparator<?super T>C) 使用比较器自定义排序

int binarySearch(int[] a,int key) ,二分搜索数组中数据并返回索引 不存在返回-1(返回 - 应该插入的位置+1)
二分法要先进行排序

Arrays 比较器制作

比较器只能支持引用类型
左大于右 返回正整数(升序)
左小于右 返回负整数
左等于右 返回0

Array.sort (a,new Comparatoe(){
public int compare(Integer o1,Integer o2)

return o1-o2;
});

Lambda

简化匿名内部类:
(匿名内部类形参列表){
重写方法
}
只能简化函数式接口

必须是接口,且只能有一个抽象方法

Collection 接口

容器。只能存储引用数据类型

体系

:Collection 单列
Map 双列

分为
List :ArrayList LinkList
有序可重复。有索引
Set:HashSet TreeSet(大小默认升序排序)
无序,不重复,无索引

集合都是支持泛型的
集合和泛型都是引用数据类型,都认为是对象

常用API

添加元素 add();

清空集合 clear()

判断是否为空 isEmpty()

获取集合大小 size()

是否包含 contians()

删除某个元素 默认删除第一个 remove()

把集合转化成数组 有一个集合c
object[] arr = c.toArray()

拷贝集合2到1。c1.addAll(c2)

遍历方式

1、迭代器
Iterator 是集合的专用遍历方式

Collection集合获取迭代器
Iterator iterator() 返回集合中的迭代器对象,该迭代器对象默认指向当前集合的0索引

常用方法:
boolean hasNext() 询问当前位置是否有元素存在
E next() 获取当前位置元素,并将迭代器指向下一个元素

if(it.hasNext()){
System.out.printfln(next(it))
}

2、foreach/增强for循环
内部原理是一个迭代器

既可以遍历集合也可以遍历数组
实现iteravle接口的类才可以使用迭代器和增强for。collection接口已经实现了

for(元素数据类型 变量名;数组或者Collection集合)
{
此处使用变量或元素
}

有一个集合 list

for(String a;list){
System.out.printfln(a)
}

3 lambda表达式

forEach
list.forEach ()->{System.out.printfln(a)
}

Collection存储自定义类型的对象

常见数据结构

数据结构是计算机底层存储组织数据的方式

二叉树

节点的度 节点拥有子树的个数 不大于2 节点数为0称为终端节点

二叉查找树:二叉排序树 二叉搜索树。
左边小 右边大

平衡二叉树:左右两个子树高度差不超过1,任意节点的左右两个子树都是一颗平衡二叉树(每当有一个子树不平衡就把它变平衡)

红黑树。红黑b树。平衡通过红黑规则
二分查找 提高效率

:每一节点或是红或是黑。根必须是黑色的
如果一个节点没有子节点或者父节点,则此节点的相应指针为nil 这些Nil称为叶节点,叶节点是黑色的
节点为红 子节点必须为黑
对每一个节点 从该节点到所有后代节点的简单路径上 均包含相同数目的黑色节点

添加节点时 可红可黑
默认用红节点效率高

List集合特有方法

List list = new ArrayList<>()

索引处添加元素 list.add(1,”1“)
删除某索引处的值并返回该支 list.remove(1)
获取 get(1)
修改set(1,“1”)

ArrayLIst底层基于数组实现的
LinkList底层基于链表实现的

遍历

迭代器 增强for循环 lambda for循环

ArrayList底层原理

基于数组实现的
第一次创建集合并添加第一个元素是在底层默认创建一个长度为10的数组(size)
存满之后扩容 (扩容1.5倍 迁移)

LinkList

类似栈队列
addfirst
addlast
removefirst
removelast
getfirst
gerlast

删除(先遍历)

最好用 迭代器 或者for循环 倒着循环或者删除的时候i–
while (it.hasNext){
String ele = it,next()
if(“1”.equals(ele)){
it.remove();//迭代器自己删除当前的元素 保证不后移
}
}

深入泛型

约束数据类型 :引用数据类型
集合体系都是支持泛型的

好处
统一数据类型

会把出现泛型的地方填入真实的数据

自定义泛型类

public class 类名< E>{

}

自定义泛型方法

public< T> void show(T t){
}

自定义泛型接口

public interface xiao< E >{
}
让实现类选择当前功能需要操作的数据类型

通配符 ?代表一切类型

Set集合

无序 不重复 无索引
实现类特点
HashSet 无序不重复 无索引
LinkedHashSet 有序 不重复 无索引
TreeSet 排序 不重复 无索引

HashSet底层原理

:底层采用hash表存储的数组
jdk8后 底层采用数组链表红黑树

哈希值 根据jdk对象的地址 按照某种规则算出来的 int类型的数据
Object 类API
public int hashCode() 返回对象的哈希值
哈希值的特点
同一对象多次调用hashCode返回的哈希值是相通的
默认情况下,不同对象的哈希值是不同的

哈希表
一个数组 默认长度16默认加载因为0.75的数组,数组名为table
根据元素的哈希值和数组的长度求余计算存入的位置(哈希算法)
判断当前位置是否为nill 是则存入
不是表示有元素。调用equals比较
如一样 则不存 不一样 1.7新元素占老元素位置 指向老元素
1.8 新元素挂在老元素下面
当数组存满到0.75*16=12时,自动扩容 扩容为原来的两倍

HashSet1.8版本解析
底层架构 哈希表(数组+链表+红黑树)
当挂在元素下的数据过多时 降低效率 因此当链表长度大于8时 自动转换成红黑树

由于两对象内容一样 但是哈希值不一样
可重写 hashCode方法和equals方法 使最终得到的哈希值一样

LinkedHashSet

有序不重复无索引
有序是保证存储和取出元素的顺序一致
原理:底层结构 哈希表 不过每个元素多了一个双链表来记录存储的顺序

TreeSet

不重复无索引可排序
可排序(有大到小)
底层基于红黑树的数据结构实现排序的
注意:一定要排序的

排序规则:
数值。大小 升序
字符串。首字母的编号 升序

自定义对象 无法直接排序 因此需要制定规则
方式一 让自定义类实现Comparable接口重写里面的ComparaTo方法来制定规则(泛型接口规则)
方式二 TreeSet集合有参数构造器,可以设置Comparator接口对应的比较器对象,来制定规则
如果类和集合都带有比较器则采用集合自带的比较器

可变参数

用在形参中可以接受多个数据
格式:数据类型…参数名称
可变参数在本质上是一个数组

注意
形参列表可变参数只能有一个
可变参数必须放在形参列表的最后面

Collections工具类

批量增加元素 Collections.addAl l(super , bian liang)
打乱集合顺序 Collections.shuffle()
排序 Collections.sort(对象 new comparator<对型类型>(){} ) 只能排值特性的
例子 Collection.sort(a,(o1,o2) -> Double.compare(o1.get(),o2.get()))
如果排自定义的 需要加入比较器

Map集合<K,V>(接口)

Map是一种双列集合,每个元素包含两个数据
Map集合的每个元素的格式:key = value(键值对元素)
也称为 键值对集合
非常适合做购物车的应用场景

Map的key和value不允许基本数据类型

Map 集合的特点都是键决定的
Map 集合的键是无序的,不重复的,值不做要求(可重复)
Map 集合后面重复的键对应的值会覆盖前面重复键的值

Map集合实现类特点
HashMap:元素按照键是无序,不重复,无索引,值不做要求。
LinkedHashMap:有序,不重复 无索引
TreeMap

Map API

添加 put(key ,value)
putAll()复制另一个map进去
删除键值对元素 remove(Object)
删除所有元素 clear
判断是否包含指定的键 containsKey(key)
判断是否包含值 containsValue(Value)
isEmpty() 是否为空
size() 长度 也就是键值对个数

遍历 -键找值

先获取Map集合的全部键的Set集合
遍历键的Set集合,然后通过键提取对应值

Set keySet() 获取所有键的集合
V get(Object key)根据键获取值

遍历 -键值对

先把Map集合转化成Set集合,Set集合中的所有元素都是键值对的试题类型
遍历Set集合 提取键 提取值
调用map方法
entrySet把Map集合转化为Set集合
Set<Map.Entry< String,Integer>> entries = maps.entrySet();
for(Map.Entry< String,Intege,entries)
{
String key = entry.Key()
int value = entry.Value()
输出
}

lambda遍历

maps.forEach(K,V) -> {
输出 K,V
}

HashMap

底层原理 哈希表
保证键唯一。依赖hashCode()和equals()方法
如果键要存储自定义对象,要重写 hashCode equals方法
基于哈希表 增删改查性能较好

LinkedHashMap

底层原理哈希表 双向链表

TreeMap

只能对键排序
制定排序规则(大小规则一样就重复了)

集合的嵌套

异常

是什么:在程序在编译或者执行的过程中出现的问题
为什么要学习异常;异常一旦出现了,如果没有提前处理 程序就会退出jvm虚拟机而终止。
学习是为了 研究避免并且处理异常
异常体系:
error:错误
Exception:异常 异常又分为
1 继承自RuntimeException及其子类 运行时异常 编译阶段不会报错
(空指针异常 数组越界异常
2 没有继承RuntimeException之外所有的异常 编译时异常 编译必须处理的 否则程序不能通过编译(日期格式异常)

这个体系中的所有类和对象都具备一个独有的特点;就是可抛性。
可抛性的体现:就是这个体系中的类和对象都可以被throws和throw两个关键字所操作。

class ExceptionDemo{undefined
public static void main(String[] args) {undefined
// byte[] buf = new byte[10241024700];//java.lang.OutOfMemoryError内存溢出错误
}
}

在开发时,如果定义功能时,发现该功能会出现一些问题,应该将问题在定义功能时标示出来,这样调用者就可以在使用这个功能的时候,预先给出处理方式。

如何标示呢?通过throws关键字完成,格式:throws 异常类名,异常类名…
这样标示后,调用者,在使用该功能时,就必须要处理,否则编译失败。
处理方式有两种:1、捕捉;2、抛出。
对于捕捉:java有针对性的语句块进行处理。
try {undefined
需要被检测的代码;
}
catch(异常类 变量名){undefined
异常处理代码;
}
fianlly{undefined
一定会执行的代码;
}
catch (Exception e) { //e用于接收try检测到的异常对象。
System.out.println(“message:”+e.getMessage());//获取的是异常的信息。
System.out.println(“toString:”+e.toString());//获取的是异常的名字+异常的信息。
e.printStackTrace();//打印异常在堆栈中信息;异常名称+异常信息+异常的位置。
}

异常处理原则:
功能抛出几个异常,功能调用如果进行try处理,需要与之对应的catch处理代码块,这样的处理有针对性,抛几个就处理几个。
特殊情况:try对应多个catch时,如果有父类的catch语句块,一定要放在下面。
throw 和throws关键字的区别:
throw用于抛出异常对象,后面跟的是异常对象;throw用在函数内。
throws用于抛出异常类,后面跟的异常类名,可以跟多个,用逗号隔开。throws用在函数上。

通常情况:函数内容如有throw,抛出异常对象,并没有进行处理,那么函数上一定要声明,否则编译失败。但是有特殊情况。

异常分两种:
1:编译时被检查的异常,只要是Exception及其子类都是编译时被检测的异常。
2:运行时异常,其中Exception有一个特殊的子类RuntimeException,以及RuntimeException的子类是运行异常,也就说这个异常是编译时不被检查的异常。

编译时被检查的异常和运行时异常的区别:
编译被检查的异常在函数内被抛出,函数必须要声明,否编译失败。
声明的原因:是需要调用者对该异常进行处理。
运行时异常如果在函数内被抛出,在函数上不需要声明。
不声明的原因:不需要调用者处理,运行时异常发生,已经无法再让程序继续运行,所以,不让调用处理的,直接让程序停止,由调用者对代码进行修正。

定义异常处理时,什么时候定义try,什么时候定义throws呢?
功能内部如果出现异常,如果内部可以处理,就用try;
如果功能内部处理不了,就必须声明出来,让调用者处理。

自定义异常:
当开发时,项目中出现了java中没有定义过的问题时,这时就需要我们按照java异常建立思想,将项目的中的特有问题也进行对象的封装。这个异常,称为自定义异常。

对于除法运算,0作为除数是不可以的。java中对这种问题用ArithmeticException类进行描述。对于这个功能,在我们项目中,除数除了不可以为0外,还不可以为负数。可是负数的部分java并没有针对描述。所以我们就需要自定义这个异常。

自定义异常的步骤:
1:定义一个子类继承Exception或RuntimeException,让该类具备可抛性。
2:通过throw 或者throws进行操作。

异常的转换思想:当出现的异常是调用者处理不了的,就需要将此异常转换为一个调用者可以处理的异常抛出。

try catch finally的几种结合方式:
1,
try
catch
finally

这种情况,如果出现异常,并不处理,但是资源一定关闭,所以try finally集合只为关闭资源。
记住:finally很有用,主要用户关闭资源。无论是否发生异常,资源都必须进行关闭。
System.exit(0); //退出jvm,只有这种情况finally不执行。

当异常出现后,在子父类进行覆盖时,有了一些新的特点:
1:当子类覆盖父类的方法时,如果父类的方法抛出了异常,那么子类的方法要么不抛出异常要么抛出父类异常或者该异常的子类,不能抛出其他异常。
2:如果父类抛出了多个异常,那么子类在覆盖时只能抛出父类的异常的子集。

注意:
如果父类或者接口中的方法没有抛出过异常,那么子类是不可以抛出异常的,如果子类的覆盖的方法中出现了异常,只能try不能throws。
如果这个异常子类无法处理,已经影响了子类方法的具体运算,这时可以在子类方法中,通过throw抛出RuntimeException异常或者其子类,这样,子类的方法上是不需要throws声明的。

常见异常:
1、脚标越界异常(IndexOutOfBoundsException)包括数组、字符串;
空指针异常(NullPointerException)
2、类型转换异常:ClassCastException
3、没有这个元素异常:NullPointerException
4、不支持操作异常;

多线程:

进程和线程

进程:

正在进行中的程序。其实进程就是一个应用程序运行时的内存分配空间。

线程(thread):

其实就是进程中一个程序执行控制单元,一条执行路径。进程负责的是应用程序的空间的标示。线程负责的是应用程序的执行顺序。

一个进程至少有一个线程在运行,当一个进程中出现多个线程时,就称这个应用程序是多线程应用程序,每个线程在栈区中都有自己的执行空间,自己的方法区、自己的变量。
jvm在启动的时,首先有一个主线程,负责程序的执行,调用的是main函数。主线程执行的代码都在main方法中。

当产生垃圾时,收垃圾的动作,是不需要主线程来完成,因为这样,会出现主线程中的代码执行会停止,会去运行垃圾回收器代码,效率较低,所以由单独一个线程来负责垃圾回收。

随机性的原理:

因为cpu的快速切换造成,哪个线程获取到了cpu的执行权,哪个线程就执行。

返回当前线程的名称:Thread.currentThread().getName()
线程的名称是由:Thread-编号定义的。编号从0开始。
线程要运行的代码都统一存放在了run方法中。

线程要运行必须要通过类中指定的方法开启。
start方法。(启动后,就多了一条执行路径)
start方法:1)、启动了线程;2)、让jvm调用了run方法。

创建线程的方式

方式一:继承Thread类

Thread类是来代表线程的。
创建线程的第一种方式:继承Thread ,由子类复写run方法。
步骤:
1,定义类继承Thread类;
2,目的是复写run方法,将要让线程运行的代码都存储到run方法中;
3,通过创建Thread类的子类对象,创建线程对象;
4,调用线程的start方法,开启线程,并执行run方法。

线程状态:
被创建:start()
运行:具备执行资格,同时具备执行权;
冻结:sleep(time),wait()—notify()唤醒;线程释放了执行权,同时释放执行资格;
临时阻塞状态:线程具备cpu的执行资格,没有cpu的执行权;
消亡:stop()

优点 编码简单
缺点 存在单继承的局限性 继承Thread后不能继承其他类

方式二:实现一个接口Runnable。

创建线程的第二种方式:实现一个接口Runnable。
步骤:
1,定义类实现Runnable接口。
2,覆盖接口中的run方法(用于封装线程要运行的代码)。
3,通过Thread类创建线程对象;
4,将实现了Runnable接口的子类任务对象作为实际参数传递给Thread类中的构造函数。
为什么要传递呢?因为要让线程对象明确要运行的run方法所属的对象。
5,调用Thread对象的start方法。开启线程,并运行Runnable接口子类中的run方法。

优点 :线程任务类是实现接口 可以继续继承类或者是吸纳接口
缺点:编程多一层对象包装,如果线程有执行结果是不可以返回的(即只能跑功能)

为什么要有Runnable接口的出现?
1:通过继承Thread类的方式,可以完成多线程的建立。但是这种方式有一个局限性,如果一个类已经有了自己的父类,就不可以继承Thread类,因为java单继承的局限性。
可是该类中的还有部分代码需要被多个线程同时执行。这时怎么办呢?
只有对该类进行额外的功能扩展,java就提供了一个接口Runnable。这个接口中定义了run方法,其实run方法的定义就是为了存储多线程要运行的代码。
所以,通常创建线程都用第二种方式。
因为实现Runnable接口可以避免单继承的局限性。
2:其实是将不同类中需要被多线程执行的代码进行抽取。将多线程要运行的代码的位置单独定义到接口中。为其他类进行功能扩展提供了前提。
所以Thread类在描述线程时,内部定义的run方法,也来自于Runnable接口。

实现Runnable接口可以避免单继承的局限性。而且,继承Thread,是可以对Thread类中的方法,进行子类复写的。但是不需要做这个复写动作的话,只为定义线程代码存放位置,实现Runnable接口更方便一些。所以Runnable接口将线程要执行的任务封装成了对象。

3、线程的实现方法三:利用Callable、FutureTask接口

1)得到任务对象
(1)实现Callable接口 重写call方法 封装要做的事情
然后创建Callable对象
(2)利用FutureTask把Callable对象封装成线程任务对象
2)交给Thread对象处理
3)start()启动线程
4)线程执行完毕后 通过FutureTask的get方法获取执行此任务的结果

优点:线程任务类只是实现接口 仍然可以继承 或者实现接口 并且可以得到返回值
缺点:编程麻烦一点

Thread 的API

getname 取名字
setname 设置名字
currenThread() 返回当前正在执行的线程对象

sleep(mills);让线程休眠制定的时时间 单位毫秒 设置休眠时间
run();任务方法
start();启动方法

多线程安全问题的原因:

多个线程同事操作同一个共享资源的时候可能会出现业务安全问题 称为业务安全问题。

涉及到两个因素:
1,多个线程在操作共享数据。
2,有多条语句对共享数据进行运算。
原因:这多条语句,在某一个时刻被一个线程执行时,还没有执行完,就被其他线程执行了。

例子 账户余额1000元
小红和 1、判断是否够1000
2、吐出1000元
3、更新账户余额
小红1 小明1 小红2 小明2 小红3剩下0元 小明3 剩下0元

同步:

好处:解决了线程安全问题。
弊端:相对降低性能,因为判断锁需要消耗资源,产生了死锁。

思想

加锁:把共享资源上锁 每次只能一个线程进入访问完毕后进行解锁 然后其他线程才能进来

方法
方法一:同步代码块

作用:把出现线程安全的核心代码上锁
原理:每次只能有一个线程进入 使用完成后自动解锁

格式:
synchronized(同步锁对象) { // 任意对象都可以。这个对象就是锁。最好不要唯一
需要被同步的代码;(操作共享资源的代码)
}
规范上:建议使用共享资源作为锁对象 对于实例对象建议使用this加锁 对于静态方法建议是与类名.class加锁

方法二:同步方法

同步方法也是有隐式锁对象的 只不过锁对象是整个方法代码
实例方法默认使用 this作为同步锁对象
静态方法默认使用 类名.class作为锁对象

同步方法好还是同步代码块好?

1、同步代码块锁更小 性能更好
2、同步方法范围更大

方法三:Lock接口:多线程在JDK1.5版本升级时,推出一个接口Lock接口。

解决线程安全问题使用同步的形式,(同步代码块,要么同步函数)其实最终使用的都是锁机制。

到了后期版本,直接将锁封装成了对象。线程进入同步就是具备了锁,执行完,离开同步,就是释放了锁。
在后期对锁的分析过程中,发现,获取锁,或者释放锁的动作应该是锁这个事物更清楚。所以将这些动作定义在了锁当中,并把锁定义成对象。

所以同步是隐示的锁操作,而Lock对象是显示的锁操作,它的出现就替代了同步。

在之前的版本中使用Object类中wait、notify、notifyAll的方式来完成的。那是因为同步中的锁是任意对象,所以操作锁的等待唤醒的方法都定义在Object类中。

而现在锁是指定对象Lock。所以查找等待唤醒机制方式需要通过Lock接口来完成。而Lock接口中并没有直接操作等待唤醒的方法,而是将这些方式又单独封装到了一个对象中。这个对象就是Condition,将Object中的三个方法进行单独的封装。并提供了功能一致的方法 await()、signal()、signalAll()体现新版本对象的好处。

final private Lock lock = new ReentrantLock();//创建一个锁对象 唯一不可替换的
public void m(){
lock.lock(); //上锁
try{
method
}
finally{
lock.unlock //解锁
}
}
}

定义同步是有前提的:

1,必须要有两个或者两个以上的线程,才需要同步。
2,多个线程必须保证使用的是同一个锁。

同步方法是用的哪个锁呢?

通过验证,方法都有自己所属的对象this,所以同步函数所使用的锁就是this锁。

同步代码块和同步方法的区别?

同步代码块使用的锁可以是任意对象。
同步函数使用的锁是this,静态同步函数的锁是该类的字节码文件对象。

在一个类中只有一个同步,可以使用同步方法。如果有多同步,必须使用同步代码块,来确定不同的锁。所以同步代码块相对灵活一些。

考点问题:请写一个延迟加载的单例模式?写懒汉式;当出现多线程访问时怎么解决?加同步,解决安全问题;效率高吗?不高;怎样解决?通过双重判断的形式解决。

//懒汉式:延迟加载方式。
当多线程访问懒汉式时,因为懒汉式的方法内对共性数据进行多条语句的操作。所以容易出现线程安全问题。为了解决,加入同步机制,解决安全问题。但是却带来了效率降低。
为了效率问题,通过双重判断的形式解决。
class Single{undefined
private static Single s = null;
private Single(){}
public static Single getInstance(){ //锁是谁?字节码文件对象;
if(s == null){
synchronized(Single.class){
if(s == null)
s = new Single();
}
}
return s;
}
}

线程间通信:

思路:多个线程在操作同一个资源,但是操作的动作却不一样。
1:将资源封装成对象。
2:将线程执行的任务(任务其实就是run方法。)也封装成对象。

等待唤醒机制:涉及的方法:
wait:将同步中的线程处于冻结状态。释放了执行权,释放了资格。同时将线程对象存储到线程池中。
notify:唤醒线程池中某一个等待线程。
notifyAll:唤醒的是线程池中的所有线程。

注意:
1:这些方法都需要定义在同步中
2:因为这些方法必须要标示所属的锁。
你要知道 A锁上的线程被wait了,那这个线程就相当于处于A锁的线程池中,只能A锁的notify唤醒。
3:这三个方法都定义在Object类中。为什么操作线程的方法定义在Object类中?
因为这三个方法都需要定义同步内,并标示所属的同步锁,既然被锁调用,而锁又可以是任意对象,那么能被任意对象调用的方法一定定义在Object类中。

wait和sleep区别:
分析这两个方法:从执行权和锁上来分析:
wait:可以指定时间也可以不指定时间。不指定时间,只能由对应的notify或者notifyAll来唤醒。
sleep:必须指定时间,时间到自动从冻结状态转成运行状态(临时阻塞状态)。
wait:线程会释放执行权,而且线程会释放锁。
Sleep:线程会释放执行权,但不是不释放锁。

线程的停止:通过stop方法就可以停止线程。
停止线程:原理就是:让线程运行的代码结束,也就是结束run方法。
怎么结束run方法?一般run方法里肯定定义循环。所以只要结束循环即可。
第一种方式:定义循环的结束标记。
第二种方式:如果线程处于了冻结状态,是不可能读到标记的,这时就需要通过Thread类中的interrupt方法,将其冻结状态强制清除。让线程恢复具备执行资格的状态,让线程可以读到标记,并结束。

---------< java.lang.Thread >----------
interrupt():中断线程。
setPriority(int newPriority):更改线程的优先级。
getPriority():返回线程的优先级。
toString():返回该线程的字符串表示形式,包括线程名称、优先级和线程组。
Thread.yield():暂停当前正在执行的线程对象,并执行其他线程。
setDaemon(true):将该线程标记为守护线程或用户线程。将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。该方法必须在启动线程前调用。
join:临时加入一个线程的时候可以使用join方法。
当A线程执行到了B线程的join方式。A线程处于冻结状态,释放了执行权,B开始执行。A什么时候执行呢?只有当B线程运行结束后,A才从冻结状态恢复运行状态执行。

线程池

什么是线程池

线程池是一个复用的线程技术

不使用线程池的问题

当用户发起一个请求 后台就会创建一个新线程来处理 下次任务来了又要创建新的 创建线程的开销很大的 这样会严重影响系统性能

谁代表了线程池

jdk5中提供了代表线程池的接口ExecutorService

如何得到一个线程池对象

方式一:使用ExecutorService的实现类ThreadPoolExecutor自创建一个线程池对象

public ThreadPoolExecutor(
int corePoolSize, 指定线程池的核心线程数 >=0
int maximumPoolSize, 可支持最大线程数 >=核心线程数
long keepAliveTime,指定临时线程最大存活时间 >=0
TimeUnit unit,指定存活时间单位(秒,分,时,天) 时间单位
BlockingQueue workQueue, 指定任务队列 不能null
ThreadFactory threadFactory, 指定用哪个线程工厂创建线程
不能null
RejectedExecutionHandler handler) 指定线程忙任务满的时候新任务来了怎么办 不能null

方式二:使用Excutors(线程池的工具类)调用方法返回不同特点的线程池对象

workQueue任务队列

上面我们已经介绍过了,它一般分为直接提交队列、有界任务队列、无界任务队列、优先任务队列;

线程池常见面试题

临时线程什么时候创建啊?

新任务提交时发现核心线程都在忙 任务队列也满了 并且还可以创建临时线程 此时才可以创建临时线程

什么时候开始会拒绝任务?

核心线程和临时线程都在忙 任务队列也满了 新的任务过来的时候才会开始拒绝任务

并发与并行

正在运行的程序(软件)就是一个独立的进程 线程是属于进程的,多个线程其实是并发与并行同时进行

并发:

CPU同时处理线程的数量有限
CPU会轮询的为系统的没一个线程服务 由于CPU切换的速度很快 给我们的感觉是这些线程在同时执行,这就是并发。

并行

同一个时刻同时执行

生命周期

线程的状态

就是线程从生到死的过程,以及中间经历的各种状态及状态转换

JAVA线程的状态

Thead.State 是一个枚举类 共 6种
新建(new)还没运行 -> start() Runnable

可运行(Runnable)执行完毕terminated

阻塞(block)未获得锁Runnable进入阻塞 获得锁Runnable

无限期等待(waiting)Runnable时获得锁时调用了wait() waiting 其他线程notify()并获得锁对象 Runnable

限期等待(TIMED_WAITING)Runnable sleep(毫秒) wati(毫秒)TIMED_WAITING sleep时间到Runnable wait时间到冰淇获得锁对象Runnable wait时间没到但是被别人notifi() Runnable

结束(terminated)

网络

网络编程三要素
IP地址,设备在网络中的地址,唯一标识
端口,应用程序在设备中的唯一标识
协议,数据在网络传输中的规则常见的协议有 UDP协议和TCP协议

ip地址

分为ipv4和ipv6
ipv4 32位 4字节 0.0.0.0~255.255.255.255
ipv6 16字节 128位 8个整数。16进制 用 :隔开

域名:http://www.aaa.cn 用户将域名发送给服务器 服务器返回ip地址给用户

ip地址形式;公用和私有地址(局域网使用)192.168开头的就是常见的局域网地址
(通信效率 节约ip)

常用命令 ipconfig:查看本机ip地址
ping ip地址 检查网络是否连通
特殊ip地址:
本机ip:127.0.0.1 或者localhost:称回送地址或本机回环地址
只会寻找当前所在本机

InetAddress. 表示Internet协议(IP)地址

InetAddress.getLocalHost 获取本机地址对象
getByName(域名)获取域名ip地址
getByName()
isReachable(int timeout)

端口号:表示在计算机设备上运行的进程(程序),16位的二进制,范围0-65535

端口类型 周知端口 :0-1023 被预定的知名应用占用(HTTP 80. FTP 21)
注册端口:1024-49151 分配给用户进程或某些应用程序(如tomcat 8080 mysql3306)
动态端口:49512到65535 之所以成为动态段欧是因为他一般不固定分配某种进程,而是动态分配

      自己开发选注册端口。且同一设备两个进程不能有相同的端口号
通信协议

//
应用层:

类型。string拼接。
继承 接口 debug过一下
数据结构 arraylist。 hashmap debug 过一遍
spring教程 写一个简单Spring 工程 将list。hashmap展示

增删改查 路径:url

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值