欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java基础学习笔记

程序员文章站 2024-02-07 23:11:10
...

Java 学习

基础

1. Java特性和优势

  1. 简单性(和C++相比没有指针,没有头文件,不需要分配内存)
  2. 面向对象
  3. 可移植性(跨平台)(write once,run anywhere)(JVM虚拟机)
  4. 高性能(即时编译)
  5. 分布式
  6. 动态性(反射机制)
  7. 多线程(一边听音乐,一边玩游戏)
  8. 安全性(没有指针,不分配内存)(异常机制)
  9. 健壮性

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.类型转换

Java基础学习笔记

  • 不能对布尔值进行转换
  • 不能把对象类型转换为不相关的类型
  • 在把高容量转换到低容量的时候,强制转换
  • 转换的时候可能存在内存溢出,或者精度问题
  • 强制转换 (类型)变量名 高->低

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内存

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
        • 同步监视器的执行过程
          1. 第一个线程访问,锁定同步监视器,执行其中代码
          2. 第二个线程访问,发现同步监视器被锁定,无法访问
          3. 第一个线程访问完毕,解锁同步监视器
          4. 第二个线程访问,发现同步监视器没有锁,然后锁定访问
    • synchronized方法控制对“对象”的访问,每个对象对应一把锁,每个synchronized方法都必须获得调用该方法的对象的锁才能执行,否则线程会阻塞,方法一旦执行,就独占该锁,直到该方法返回才释放锁,后面被阻塞的线程才能获取这个锁,继续支持

    • 若将一个大的方法声明为synchronized 将会影响效率

14. 死锁

  • 多个线程各自占有一些共享资源,并且相互等待其他线程占有的资源才能运行,而导致两个或多个线程都在等待对方释放资源,都停止执行的情形,某一个同步块同时拥有“两个以上对象的锁”时,就可能会发生“死锁”的问题

  • 死锁避免方法:

    产生死锁的四个条件:

    1. 互斥条件:一个资源每次只能被一个进程使用
    2. 请求和保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放
    3. 不剥夺条件:进程已获得的资源,在未使用完之前,不能强行剥夺
    4. 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系
    • 破坏其中任意一个条件,就可以避免死锁的发生

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 称为类型占位符,表示一种引用类型
  • 好处:

    • 提高代码重用性
    • 防止类型转换异常,提高代码安全性