Java基础学习笔记
Java 学习
基础
1. Java特性和优势
- 简单性(和C++相比没有指针,没有头文件,不需要分配内存)
- 面向对象
- 可移植性(跨平台)(write once,run anywhere)(JVM虚拟机)
- 高性能(即时编译)
- 分布式
- 动态性(反射机制)
- 多线程(一边听音乐,一边玩游戏)
- 安全性(没有指针,不分配内存)(异常机制)
- 健壮性
2. Java三大版本
-
JavaSE:标准版(桌面程序,控制台开发…)
-
JavaME:嵌入式开发(手机,小程序…)
-
JavaEE:企业级开发(web端,服务器开发…)
3. JDK JRE JVM
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tKhl7dTa-1597813984216)(https://s1.ax1x.com/2020/05/02/JvBHOJ.png)]
- JDK包括JRE和JVM
- JDK:Java Development Kit
- JRE:Java Runtime Environment
- JVM:Java Virtual Machine
4. Java程序运行机制
-
编译型
-
解释型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BgJJ9MG1-1597813984221)(https://s1.ax1x.com/2020/05/02/JvBTlF.png)]
5.标识符和关键字
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-jxtF7m77-1597813984226)(https://s1.ax1x.com/2020/05/02/JvB7y4.png)]
- Java所有的组成部分都需要名字。类名、变量名以及方法名都被称为标识符。
6.数据类型
-
基本类型
-
引用类型
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-sYCfxUo4-1597813984229)(https://s1.ax1x.com/2020/05/02/JvBoSU.png)]
7.强类型语言
- 要求变量的使用要严格符合规定,所有变量都要先定义再使用。
- 安全性高
- 但消耗资源
8.类型转换
- 不能对布尔值进行转换
- 不能把对象类型转换为不相关的类型
- 在把高容量转换到低容量的时候,强制转换
- 转换的时候可能存在内存溢出,或者精度问题
- 强制转换 (类型)变量名 高->低
9.变量
-
变量是可以变化的量
-
每个变量都有类型,类型可以是基本类型,也可以是引用类型。
-
变量名必须是合法的标识符。
-
变量声明是一条完整的语句,因此每一个声明都必须以分号结束
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dtMyKMPy-1597813984233)(https://s1.ax1x.com/2020/05/02/JvB4YV.png)]
10.运算符
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5jSVGs7G-1597813984237)(https://s1.ax1x.com/2020/05/02/JvBhF0.png)]
-
a++ 先赋值,再自增
-
++a 先自增,再赋值
-
幂运算
Math.pow(2,3);//2的3次方
流程控制
1. Scanner
- 通过Scanner类的next()与nextLine()方法获取输入的字符串,在读取前我们一般需要使用hasNext()与hasNextLine()判断是否还有输入的数据。
- next():
- 一定要读取到有效字符后才可以结束输入
- 对输入有效字符之前遇到的空白,next()方法会自动将其去掉
- 只有输入有效字符后才将其后面输入的空白作为分隔符或者结束符
- next()不能得到带有空格的字符串
- nextLine():
- 以Enter为结束符,也就是说nextLine()方法返回的是输入回车之前的所有字符。
- 可以获得空白
Scanner s = new Scanner(System.in);
if(s.hasNextLine()){
String str = scanner.nextLine();
}
s.close();
2. Switch选择结构
switch(expession){
case value:
//语句
break;//可选
case value:
//语句
break;//可选
//你可以有任意数量的case语句
deafult://可选
//语句
}
- switch语句中的变量类型可以是:
- byte、short、int或者char,String
3. While循环
while(布尔表达式){
//循环内容
}
4. do…while循环
- While和do-While的区别:
- while先判断后执行,dowhile先执行后判断
- do-while总是保证循环体会被至少执行一次!这是它们之间的主要差别。
5. for循环
- for循环语句是支持迭代的一种通用结构,是最有效、最灵活的循环结构。
- for循环执行的次数是在执行前就确定的,语法格式如下:
for(初始化;布尔表达式;更新){
//代码语句
}
-
关于for循环说明:
- 最先执行初始化步骤,可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句
- 然后,检测布尔表达式的值,如果为true,循环体被执行。如果为false,循环中止,开始执行循环体后面的语句
- 执行一次循环后,更新循环控制变量(迭代因子控制循环变量的增减)
- 再次检测布尔值,循环执行上面的过程
6. 增强for循环
int[] numbers = {10,20,30,40,50};//定义了一个数组
for (int x:numbers){
System.out.println(x);
}
7. break和continue区别
- break在任何循环语句的主体部分,均可用break控制循环的流程
- break用于强行退出循环,不执行循环中剩余的语句。(break语句也在switch语句中使用)
- continue语句用在循环语句体中,用于中止某次循环过程,即跳出循环体中尚未执行的语句,接着进行下一次是否执行循环的判定
方法
1. 什么是方法?
- Java方法时语句的集合,它们在一起执行一个功能。
- 方法包含于类或对象中
- 方法在程序中被创建,在其他地方被引用
2. 设计方法的原则
- 方法的本意是功能块,就是实现某个功能的语句块的集合。我们设计方法的时候,最好保持方法的原子性,就是一个方法只完成一个功能,这样利于后期的扩展。
3. 方法的定义
修饰符 返回值类型 方法名(参数类型 参数名){
...
方法体
...
return 返回值;
}
4. 方法的重载
- 重载就是在一个类中,有相同的函数名称,但形参不同的函数
- 方法的重载的规则:
- 方法名必须相同
- 参数列表必须不同(个数不同、类型不同、参数排列顺序不同等)
- 方法的返回类型可以相同也可以不相同
- 仅仅返回类型不同不足以成为方法的重载
5. 递归
- A方法调用自己
数组
1. 数组的定义
- 数组是相同类型数据的有序集合
- 数组描述的是相同类型的若干个数据,按照一定的先后次序排列组合而成。
- 其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们。(数组下标从0开始)
2. 数组的声明
- 首先必须声明数组变量,才能在程序中使用数组。下面是声明数组变量的语法
dataType[] arrayRefVar;//首选的方法
dataType arrayRefVar[];//首选的方法
-
Java语言使用new操作符来创建数组,语法如下
dataType[] arrayRefVar = new dataType[arraySize];
-
数组的元素通过索引访问,数据索引从0开始
-
获取数组长度
3. Java内存
4. 数组初始化
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dsDbUy9X-1597813984239)(https://s1.ax1x.com/2020/05/02/JvBcLj.png)]
5. 数组的特点
- 长度是确定的,数组一旦被创建,它的大小就是不可以改变的
- 其元素必须是相同类型,不允许出现缓和类型
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型
- 数据变量属于引用类型,数据也可以看成是对象,数组中的每个元素相当于该对象的成员变量。数组本身就是对象,Java中对象是在堆中的,因此数组无论保存原始类型还是其他对象类型。数组对象本身是在堆中的。
6. 数组的使用
- forEach的使用
- 数组做方法参数
7. Arrays类
- Arrays.toString() //打印数组元素
- Arrays.sort(); //数组进行排序,升序
8.冒泡排序
//冒泡排序
//1、比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们交换它们的位置
//2、每一次比较,都会产生出一个最大,或者最小的数字
//3、下一轮则可以少一个排序
//4、依次循环,直到结束
public static int[] sort(int[] array){
//临时变量
int temp = 0;
//外层循环,判断我们要走多少步
for (int i = 0; i < array.length; i++) {
boolean flag = false;
//内层循环,比较数组中,两个相邻的元素,如果第一个数比第二个数大,我们交换它们的位置
for (int j = 0; j < array.length-1-i; j++) {
if (array[j+1]<array[j]){
temp = array[j];
array[j] = array[j+1];
array[j+1] = temp;
flag = true;
}
}
if (flag == false){
break;
}
}
return array;
}
面向对象
1. 静态方法和非静态方法
- static关键字
- 静态方法调用 类名.方法名()
- 非静态方法调用 先实例化 然后 类名.方法名()
2. 类与对象的关系
-
类是一种抽象的数据类型,它是对某一类事务整体描述/定义,但是不能代表某一个具体的事物。(动物,植物)
-
类里面只可以写属性和方法
-
对象是抽象概念的具体事例。
3. 面向对象编程的本质
- 以类的方式组织代码,以对象的组织(封装)数据
4. 创建与初始化对象
-
使用new关键字创建对象
- 使用new关键字创建的时候,除了分配内存空间外,还会给创建好的对象进行默认的初始化以及类中构造器的调用。
- Person POPO = new Person();
-
对象的属性 POPO.name
-
对象的方法 POPO.sleep()
5. 构造器
-
和类名相同
-
没有返回值
-
作用:
- new 本质在调用构造方法
- 初始化对象的值
-
注意点:
- 定义有参构造之后,如果想使用无参构造,显示的定义一个无参的构造
-
alt + insert
6. 引用类型
- 基本类型(8)
- 对象是通过引用来操作的 : 栈——>堆
7. 属性
-
字段Field 成员变量
-
默认初始化:
- 数字: 0
- char:u0000
- boolean:false
- 引用:null
-
修饰符 属性类型 属性名 = 属性值;
-
public int a = 3;
8. 封装
- 提高程序的安全性,保护数据
- 隐藏代码的实现细节
- 统一接口
- 系统可维护增加了
- 属性私有,get/set
9. 继承
- 继承是类和类之间的一种关系。
- 继承关系的俩个类,一个为子类(派生类),一个为父类(基类)。子类继承父类,使用关键字extends来表示。
- 子类和父类之间,从意义上讲应该具有"is a"的关系
- Java中类只有单继承,没有多继承。一个儿子只有一个爸爸,一个爸爸可以有多个儿子
10. super()
-
super调用父类的构造方法,必须在构造方法第一个
-
super必须只能出现在子类的方法或者构造方法中
-
super和this不能同时调用构造方法
-
与this的区别:
-
代表的对象不同:
- this:本身调用者这个对象
- super:代表父类对象的应用
-
前提:
- this:没有继承也可以使用
- super:只能在继承条件才可以使用
-
构造方法:
- this():本类的构造
- super():父类的构造
-
11. 重写
-
前提:需要有继承关系,子类重写父类的方法
-
方法名必须相同
-
参数列表必须相同
-
修饰符:范围可以扩大:public–>protected–>default–>private
-
抛出的异常:可以被缩小,但不能扩大;
-
子类的方法和父类必须一致,方法体不同
-
为什么需要重写:
- 父类的功能,子类不一定需要,或者不一定满足
-
哪些方法不能重写:
- static方法,属于类,它不属于实例
- final 修饰的方法,在常量池
- private 方法
12. 多态
- 多态是方法的多态,属性没有多态
- 即同一个方法根据发送对象的不同而采用多种不同的行为方式
- 父类和子类,有联系,类型转换异常 ClassCastException
- 存在条件:继承关系,方法需要重写,父类引用指向子类对象! father f1 = new son();
13. instanceof
14. 父子类型转换
- 父类引用指向子类的对象
- 把子类转换为父类,向上转型
- 把父类转换为子类,向下转型,强制转换
- 方便方法的调用,减少重复代码
15. static
-
变量:
- 静态变量,类名.变量 调用
- 非静态变量,new 类名().变量
-
方法:
- 静态方法:在一个类里,直接调用;不在一个类通过 类名.方法名()调用
- 非静态方法: new 类名().方法()
-
静态代码块
static{ //静态代码块 }
- 静态代码块先执行
16. 抽象类
- 不能new这个抽象类,只能靠子类去实现它:约束!
- 抽象类中可以写普通的方法
- 抽象方法必须在抽象类中
17. 接口
-
是一个约束
-
定义一些方法,让不同的人实现
-
接口中的方法都是public abstract
-
变量都是public static final
-
接口不能被实例化,接口中没有构造方法
-
implements可以实现多个接口
-
必须要重写接口中的方法
异常
1. Error
- Error类对象由Java虚拟机生成并抛出,大多数错误与代码编写这所执行的操作无关。
- Java虚拟机运行错误,当JVM不再有继续执行操作所需的内存资源时,将出现OutOfMemoryError。这些异常发生时,JVM一般会选择线程终止。
2. Exception
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2ZyO5JL1-1597813984240)(https://s1.ax1x.com/2020/05/02/JvBRwn.png)]
3. Error和Exception区别
Error通常是灾难性的致命的错误,是程序无法控制和处理的,当出现这些异常时,Java虚拟机一般会选择终止线程;Exception通常情况下是可以被程序处理的,并且在程序中应该尽可能的去处理这些异常
4. 异常处理机制
try{
}catch(){
}finally{
}
- 要捕获多个异常,从小到大捕捉异常
多线程
1.Process和Thread
- 程序是指令和数据的有序集合,其本身没有任何运行含义,是一个静态的概念。
- 而进程则是执行程序的一次执行过程,它是一个动态的概念。是资源分配的单位。
- 通常在一个进程中可以包含若干个线程,当然一个进程中至少有一个线程,不然没有存在的意义。线程是CPU调度和执行的单位。
2. 核心知识
- 线程是独立的执行路径
- 在程序运行时,即使没有自己创建线程,后台也会有多个线程,如主线程,gc线程
- main() 称之为主线程,为系统的入口,用于执行整个过程
- 在一个进程中,如果开辟了多个线程,线程的运行由调度器安排调度,调度器是与操作系统紧密相关的,先后顺序是不能人为干预的
- 对同一份资源操作时,会存在资源强夺的问题,需要加入并发控制
- 线程会带来额外的花销,如cpu调度时间,并发控制开销等
- 每个线程在自己的工作内存交互,内存控制不当会造成数据不一致
3. 三种创建方式
- 继承Thread类
- 自定义线程类继承 Thread类
- 重写 run() 方法,编写线程执行体
- 创建线程对象,调用 start() 方法启动线程
- 实现Runnable接口
- 定义 MyRunnable 类实现 Runnable 接口
- 实现 run() 方法,编写线程执行体
- 创建线程对象,调用 start() 方法启动线程
- 实现Callable接口
- 可以有返回值和抛出异常
4. 静态代理
- 真实对象和代理对象都要实现同一个接口
- 代理对象要代理真实角色
- 优点:
- 代理对象可以做很多真实对象做不了的事情
- 真实对象专注做自己的事情
5. λ表达式
- λ 表达式只能有一行代码的情况下才能简化为一行,如果有多行,就用代码块
- 前提是接口为函数式接口
- 多个参数也可以去掉参数类型,必须加上括号
6. 线程状态
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LGSihpol-1597813984241)(https://s1.ax1x.com/2020/05/02/JvB2es.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A3FeNM4T-1597813984242)(https://s1.ax1x.com/2020/05/02/JvBWoq.png)]
7. 停止线程
- 不建议使用stop()、destory()方法
- 推荐线程自己停止下来
- 建议使用一个标志位进行种植变量 当flag= false,终止线程运行
8. 线程休眠
- sleep(时间)指定当前线程阻塞的毫秒数;
- sleep存在异常InterruptedException;
- sleep时间达到后线程进入就绪状态
- sleep可以模拟网络延迟,倒计时等
- 每一个对象都有一个锁,sleep不会释放锁
9. 线程礼让
- 礼让线程,让当前正在执行的线程暂停,但不阻塞
- 让线程从运行状态转为就绪状态
- 让CPU重新调度,礼让不一定成功。看CPU心情
10. Join
- Join合并线程,此线程执行完成后,再执行其他线程,其他线程阻塞
- 可以想象成插队
11. 优先级
-
Java提供一个线程调度器来监控程序中启动后进入就绪状态的所有线程,线程调度器按照优先级决定应该调度哪个线程来执行
-
线程的优先级用数字表示,范围从1-10
Thread.MIN_PRIORITY = 1; Thread.MAX_PRIORITY = 10; Thread.NORM_PRIORITY = 5;
-
使用一下方式改变或获取优先级
thread.getPriority(); thread.setPriority(2);
-
优先级低只是意味着获得调度的概率低,并不是优先级低就不会被调用,这都是看CPU调度
12. 守护(daemon)线程
- 线程分为用户线程和守护线程
- 虚拟机必须确保用户线程执行完毕 main() gc()
- 虚拟机不用等待守护线程执行完毕
- 如,后台记录操作日志,监控日志,垃圾回收日志
13. 线程同步
-
并发
- 同一个对象被多个线程同时操作
-
由于同一进程的多个线程共享同一块存储空间,在带来方便的同时,也带来了访问冲突问题,为了保证数据在方法中被访问时的正确性,在访问时加入锁机制 synchronized ,当一个线程获得对象的排他锁,独占资源,其他线程必须等待,使用后释放锁计科,存在以下问题:
- 一个线程持有锁会导致其他所有需要此锁的线程挂起;
- 在多线程竞争下,加锁,释放锁会导致比较多的上下文切换 和 调度延时,引起性能问题;
- 如果一个优先级高的线程等待一个优先级低的线程释放锁 会导致优先级倒置,引起性能问题
-
同步方法
-
由于我们可以通过private关键字来保证数据对象只能被方法访问,所以我们只需要针对方法提出一套机制,这套机制就是synchtonized 关键字,它包括两种用法:synchronized方法和 synchronized块
同步方法:public synchronized void method(int args){}
- 同步块
- synchronized(Obj){}
- Obj叫同步监视器
- Obj可以是任何对象,但是推荐使用共享资源作为同步监视器
- 同步方法中无需指定同步监视器,因为同步方法的同步监视器就是this,就是这个对象本身,或者是class
- 同步监视器的执行过程
- 第一个线程访问,锁定同步监视器,执行其中代码
- 第二个线程访问,发现同步监视器被锁定,无法访问
- 第一个线程访问完毕,解锁同步监视器
- 第二个线程访问,发现同步监视器没有锁,然后锁定访问
- 同步块
-
synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获取这个锁,继续支持
-
若将一个大的方法声明为synchronized 将会影响效率
-
14. 死锁
-
多个线程各自占有一些共享资源,并且相互等待其他线程占有的资源才能运行,而导致两个或多个线程都在等待对方释放资源,都停止执行的情形,某一个同步块同时拥有“两个以上对象的锁”时,就可能会发生“死锁”的问题
-
死锁避免方法:
产生死锁的四个条件:
- 互斥条件:一个资源每次只能被一个进程使用
- 请求和保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
- 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
- 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
- 破坏其中任意一个条件,就可以避免死锁的发生
15. Lock(锁)
class A{
private final ReentrantLock lock = new ReentrantLock();
public void m(){
lock.lock();
try{
//保证线程安全的代码
}finally{
lock.unlock();
//如果同步代码有异常,要将unlock()写入finally代码块
}
}
}
16. synchronized 与 Lock对比
- Lock是显示锁(手动开启和关闭锁,别忘记关闭锁)synchronized是隐式锁,出了作用域自动释放
- Lock只有代码块锁,synchronized 有代码块锁和方法锁
- 使用Lock 锁,JVM将花费较少的时间来调度线程,性能更好。而且具有更好的扩展性(提供更多的子类)
- 优先使用顺序:
- Lock > 同步代码块(已经进入了方法体,分配了相应资源) > 同步方法(在方法体之外)
17. 线程协作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BYlBQUmy-1597813984244)(https://s1.ax1x.com/2020/05/03/YpdvlT.png)]
- 解决方法
- 创建缓冲区,管程法
- 信号灯法,标志位解决
18. 线程池
-
JDK5.0起提供了线程池相关API:ExecutorService 和 Executors
-
ExecutorService: 真正的线程池接口。常见的子类 ThreadPoolExecutor
- void execute(Runnable command):执行任务/命令,没有返回值,一般用来执行Runnale
- Future submit(Callable task):执行任务,有返回值,以一般用来执行Callable
- void shutdown():关闭连接池
-
Executors:工具类、线程池的工厂类,用于创建并返回不同类型的线程池
集合
概念
- 对象的容器,实现了对对象的常用操作,类似数组功能
和数组的区别
- 数组长度固定,集合长度不固定
- 数组可以存储基本类型和引用类型,集合智能存储引用类型
位置
java.util.*
1. 集合框架
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uYxQAcJh-1597813984245)(https://s1.ax1x.com/2020/05/04/Y9BVHg.png)]
1.1 Collection 体系集合
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-p5Yq5LSO-1597813984246)(C:\Users\Li yutong\AppData\Roaming\Typora\typora-user-images\image-20200814110957470.png)]
1.2 Collection 父接口
-
特点:代表一组任意类型的对象,无需,无下标,不能重复
-
方法:
boolean add(Object obj) //添加一个对象 boolean addAll(Collection c)// 将一个集合中的所有对象添加到此集合中 void clear() //清空此集合中的所有对象 boolean contains(Object o) //检查此集合中是否包含o对象 boolean equals(Object o) // 比较此集合是否与指定对象相等 boolean isEmpty() //判断此集合是否为空 boolean remove(Object o) // 在此集合中移除o对象 int size() // 返回集合中元素的个数 Object[] toArray() // 将此集合转换为数组
2. List 集合
特点
有序,有下标,元素可以重复
方法
总结:常用方法
增:add(Object obj)
删:remove(Object obj) /Object remove(int index)
改:set(int index,Object ele)
查:get(int index)
插入:add(int index,Object ele)
长度:size()
遍历:iterator() 增强for方式 普通的循环
- List集合代表一个元素是有序的且可以重复的集合,集合中每个元素都有其对应的顺序索引
- List集合允许添加重复元素,可以通过索引来访问
- List接口中有两个最为常用的实现类 ArrayList 和 LinkedList
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Xw3ZtXHa-1597813984247)(https://s1.ax1x.com/2020/05/09/Ylgnd1.png)]
2.1 List 实现类
-
ArrayList
- 数组结构实现,查询块,增删慢
- 运行效率快,线程不安全
-
Vector
- 数组结构实现,查询快,增删慢
- 运行效率慢,线程安全
-
LinkedList
- 链表结构实现,增删快,查询慢
ArrayList源码解读
DEFAULT_CAPACITY = 10 // 默认容量大小 注意:如果没有向集合中添加任何元素时,容量0;添加一个元素之后,容量变为10
elementData; // 存放元素的数组
size // 实际元素个数
/*add底层源码**/
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
}
private static int calculateCapacity(Object[] elementData, int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
return Math.max(DEFAULT_CAPACITY, minCapacity);
}
return minCapacity;
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
3. Set集合
- Set集合类似于一个瓶子,“装进”Set集合中的多个对象之间没有明显的顺序
- Set集合不允许包含相同的元素,如果视图将两个相同元素加入同一个Set集合中,则添加操作失败,add方法返回false,且新元素不会被加入其集合中
- 无序、无下标、元素不可以重复
- HashSet具有以下特点:
- 不能保证元素的排列顺序,顺序可能与添加顺序不同,顺序也有可能发生变化
- 集合元素值可以是null
3.1 HashSet
- 基于HashCode计算元素存放位置
- 当存入元素的哈希码相同时,会调用equals方法进行确认,如结果为true,则拒绝后者存入;
3.2 TreeSet
- 基于排列顺序实现元素不重复
- 实现了 SortedSet 接口,对集合元素自动排序
- 元素对象的类型必须实现 Comparable 接口,指定排序规则
- 通过 CompareTo 方法确定是否为重复元素
4. Map集合
- Map用于保存具有映射关系的数据,Map集合中保存着两组值,一组值用于保存 Map 中的 key,另外一组值保存 Map 的 value
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1QJqM9iA-1597813984248)(https://s1.ax1x.com/2020/05/09/YlWlWV.png)]
特点
- 用于存储任意键值对
- 键:无序、无下标、不允许重复(唯一)
- 值:无序,无下标,允许重复
`public V put(K key, V value)`: 把指定的键与指定的值添加到Map集合中。
public V remove(Object key): 把指定的键 所对应的键值对元素 在Map集合中删除,返回被删除元素的值。
public V get(Object key) 根据指定的键,在Map集合中获取对应的值。
boolean containsKey(Object key) 判断集合中是否包含指定的键。
public Set<K> keySet(): 获取Map集合中所有的键,存储到Set集合中。
public Set<Map.Entry<K,V>> entrySet(): 获取到Map集合中所有的键值对对象的集合(Set集合)
4.1 HashMap
总结:
(1)HashMap刚创建时,table是null, 为了节省空间工当添加第一个元素是,table容 量调整为16
(2)当元索个数大于阅值(16*0.75-12)时,会进行扩容,扩容后大小为原来的2倍。目的是减少调整元索的个数。
(3)jdk1.8当每个链表长度大于8,并且元索个数大于等于64时,会调整为红黑树,目的提高执行效率
(4)jdk1.8当链表长度小于6时,调整成链表
(5)jdk1.8以前,链表时头插入,jdk1. 8以后时是尾插入
4.2 TreeMap
5. 泛型
-
本质:参数化类型,把类型作为参数传递
-
常见形式有泛型类、泛型接口、泛型方法
-
语法:
- <T…> T 称为类型占位符,表示一种引用类型
-
好处:
- 提高代码重用性
- 防止类型转换异常,提高代码安全性
上一篇: 检查字符串中是否有外链