初级java开发(javaSE基础)

原创声明

本文作者:泉幽

转载请务必在文章开头注明出处和作者。

  1. 基础环境搭建

作为刚入门的小白如何快速进入java初级开发?我们首先需要通过系统的环境变量搭建以下环境,以及准备以下基础工具(任选),可自行去相关官网下载:

核心:java,jdk,jre(三者必备)

        注:jdk包含jre,是开发工具包;jre(Java Runtime Environment),是运行环境。

数据库:MySql/Orcale/PLSQL...

数据库连接工具:MySql Connector Java...

数据库可视化管理工具:Navicat/DataGrip/DBeaver...

开发工具:Idea/Eclipse/MyEclipse...

服务器:Tomcat...

包管理:Maven...

画类的关系图工具:Rational Rose...

构建用户需求工具:UMl(用列图)...

图1.1 Java环境配置

图1.2 JDK环境配置

图1.3 MySql数据环境配置

图1.4 数据库连接java环境配置

图1.5 Tomcat环境配置

图1.6 Maven环境配置

图1.7 Maven配置文件设置仓库地址

图1.8 Idea中设置Maven路径

通过以上的环境搭建与配置,我们已经可以进行初步的java项目开发。当然以上只是后端配置,如果是涉及现在流行的前后端分离机制,前端使用Vue,后端使用SpringBoot,我们还需要在Idea中进行相关的配置。

  1. 基础语法

标识符

  • 标识符组成:

数字,字母,下划线,$

首位不能是数字 。并且 Java关键字不能作为标识符 。

Unicode 字符集中符号大于 0xC0 的所有符号组合构成(各符号之间没有空格)

变量

  • 变量三要素:

数据类型、变量名、变量的值;

  • 变量的分类:

成员变量:方法体外,类体内;

实例变量:new对象,存在方法区,引用访问。
静态变量:static修饰,存在内存中,类名访问。

局部变量:方法体中,方法结束后该变量的内存就释放了;

数据类型

  • 基础数据类型:

数值型: byte,short,int,long,float,double
字符型:char(转义字符\t、\r、\n、\\、\'、\"、\u,使用Unicode编码)
布尔型:boolean
  • 引用数据类型:

类:class
接口:interface
数组:【】

运算符

以下根据优先级自上而下,由左到右排序。

  • 算术运算符:

()、【】、++、--、*、/、%、+、-
  • 关系运算符:

<、>、<=、=<
  • 位运(效率高),逻辑,条件运算符:

<<、>>、>>>(优先级高关系运算符)==、!=、&、^、|、〜、&&、||、?::

案例:^表示异或 就是相同是0 不同是1
    14二进制:1110
    3二进制:0011
    所以14^3=1101,即13
案例:<<
    2<<3
    2二进制10
    左移动三位:10000,即16
    等同于:2*(2的3次方),即2*8=16
  • 扩展赋值运算符(优先级最低):

*=、/=、%=、+=、-=、<<=、 >>= 、>>>=、 &=、 ^=、 |=
注:数据超出范围,不会改变运算的结果类型。

控制语句

循环语句:if else,swith case(使用整数表达式/枚举常量),for,while,do while

结束语句:break,continue,return

  1. 基础jvm

  • 基本概念:JVM 是可运行 Java 代码的假想计算机 (虚拟机),包括一套字节码指令集、一组寄存器、一个栈、一个堆(垃圾回收)和一个存储方法域。

图3.1 简易JVM图

1, 栈帧 ,随着方法调用而创建,随着方法结束而销毁,即为压栈入栈,出栈。
2, 堆内存 中,存储了new出来的对象,数组,也是垃圾回收(含有新生代,老生代,其中新生代又细分为,Eden区/ServivorForm区/ServivorTo区)的重要区域。最终通过MinorGC 采用复制算法进行垃圾回收(复制—>清空—>互换)。
3, 方法区 中,存储了jvm的类加载机制,编译后的代码数据,常量池(String/class/runtime),静态变量等等。
注: 方法区,堆 是线程共享数据。 是线程私有数据。
  • 运行过程:JVM 是运行在操作系统之上的,它与硬件没有直接的交互。java源文件,通过编译生字节码文件(.class),再通过jvm中解释器编译成机器码。

① Java 源文件—-> 编译器—->字节码文件
② 字节码文件—->JVM中 解释器—->机器码
注:每一种平台的 解释器 是不同的,但是实现的虚拟机(jvm)是相同的,这也就是 Java 为什么能够跨平台的原因。
  1. 基础java

  • 基础

  • 4.1.1面对对象基本概念
  • 面对对象注重的是对象,将现实世界细分为每一个单元,每个单元就是对象,着重与对象与对象之间的互动。例如:java语言

  • 面对过程注重的是过程,适用于小型项目,着重实现的每一个步骤,步骤的顺序等。例如:C语言

  • C++属于半面对对象。

  • 4.1.2面向对象设计原则

单一职责原则

一个对象单封装一个类,功能单一

OCP开闭原则

对扩展开放,对修改关闭

里氏代换原则

所有引用基类的地方,必须能够透明,使用其子类对象

依赖倒转原则

高层模块,不依赖,底层模块,都依赖抽象

接口隔离原则

客户端,不依赖,不需要的接口

合成复用原则

优先使用对象,其次继承

迪米特法则

软件单位,知识局限于相关,软件单位

注:面向抽象编程,不要面向具体。

  • 4.1.3面对对象三大特征
  • 封装(隐藏内部代码):

  • 私有化private,提供set/get。

  • 继承(复用现有代码):

  • 继承类

1)类和类之间只支持单继承。

2)构造方法不能被继承。

3)私有属性不能在子类中直接访问。

  • 继承抽象类

1)抽象类中不一定有抽象方法。

2)抽象方法必须出现在抽象类中。

3)抽象类中有构造方法,但只用于初始化变量,而不是创建对象。

  • 实现接口

1)类与接口可以多实现(implements),接口与接口可以多继承(extends)。

2)接口是完全抽象的,没有构造方法,无法实例化(只有常量/抽象方法)。

3)接口中所有的数据都是public修饰的(public static final/public abstract可省略)。

4)一个非抽象的类实现接口必须将接口中所有的方法加以实现。

注:事物的本质的时候,用抽象类;事物操作的时候,用接口。

  • 多态(改写对象行为):

  • 接口通过子类创建对象。

  • 向上转型(upcasting):子转换成父,又叫做自动类型转换。

  • 向下转型(downcasting):父转换成子,又叫做强制类型转换,需要加强制类型转换符。

注:多态在开发中的作用:降低程序耦合度,提高程序扩展力。


典型的多态代码是父类型引用指向子类型对象,程序分编译阶段和运行阶段,编译阶段绑定的是父类中的方法(父类中没有这个方法,编译器会报错),但运行阶段和堆内存中实际对象有关,运行的时候绑定的是实际对象的方法。
什么情况下必须做向下转型:当访问子类中特有方法的时候。
instanceof运算符:boolean = 引用 instanceof 类名,为ture时候,就进行强转。
  • 4.1.4类和类之间的关系
  • 泛化关系(A is a B):类之间继承,接口之间继承。

  • 实现关系 (A like B):类实现接口。

  • 关联关系 (A has B)

  • 单向关联:A含有B引用。

  • 双向关联:A含有B引用,B含有A引用。

  • 聚合关系:特殊的关联关系,整体不决定部分的生命周期(比如班级---->List<学生>)。

  • 组合关系:特殊的关联关系,整体决定部分的生命周期(比如人---->List<肢体>)。

  • 依赖关系:A类与A方法中局部变量(B类的引用)关系。

  • 4.1.5访问控制权限修饰符

public

任何位置都可访问

protected

其他包子类可访问

缺省

在同一个包下可以访问

private

只能在本类中访问

  • 4.1.6方法重载/方法重写

定位

方法名

参数

返回类型

方法重载

同一个类中

相同

不同

无关

方法重写

继承关系中,方法体不同

相同

相同

相同

(1)重写的方法不能比被重写的方法拥有更低的访问权限;

(2)重写的方法不能比被重写的方法抛出更宽泛的异常;

(3)私有的方法无法重写;

(4)构造方法无法继承,无法重写;

(5)静态的方法不存在重写,会被隐藏;

注意:返回Object类,重写时可以返回任何属于Object的类型。

  • 4.1.7关键字this/super/static
  • this概念:存储在堆内存的对象内部,代表本类对象引用。

  • this的使用:

①this不能使用在静态方法中(静态方法存在方法区中没有对象)。

②通过本类引用调用父类方法(方法没被重写)。

③this()只能出现在构造方法第一行,通过本类引用调取本类中其他构造方法。

  • super概念:不是引用,也不保存内存地址,也不指向任何对象,代表当前this对象的父类特征。

  • super的使用:

①super不能使用在静态方法中(super是this的一部分)。

②super.属性名:通过父类引用调用父类中属性。

③super.方法名():通过父类引用调用父类中被重写的方法。

④super():只能出现在构造方法第一行,通过父类引用调取父类的构造方法。

注意:super运行原理,类加载(静态代码块/静态变量)—>new方法调用(压栈)—>调用构造方法中super()。

  • static关键字:

静态代码块

static{ }

静态变量

运行时和堆内存中的对象无关,类名访问

静态方法

运行时和堆内存中的对象无关,类名访问

构造代码块

每一次new对象都会执行

注意:执行顺序:父类静态—子类静态—父类实例—父类构造—子类实例—子类构造。


public class TestStatic {
    public static void main(String[] args) {new  TestB();}
}
class TestA {
    static  {System.out.println( "父类--静态代码块" );}
    public  TestA() {System.out.println( "父类--构造函数" );}
    {System.out.println( "父类--非静态代码块" );}
}
class TestB extends TestA {
    static  {System.out.println( "子类--静态代码块" );}
    {System.out.println( "子类--非静态代码块" );}
    public  TestB() {System.out.println( "子类--构造函数" );}
}
/*输出结果:
父类--静态代码块
子类--静态代码块
父类--非静态代码块
父类--构造函数
子类--非静态代码块
子类--构造函数
  • 4.1.8 final、finalize、finally
  • final:是java关键字,被修饰的数据不可变。

(1)final修饰的类无法被继承,无法修饰抽象类。

(2)final修饰的方法无法被覆盖,但可以访问。

(3)final修饰的变量,一旦赋值不可重新赋值(引用变量不能变)。

如:final String a = new String(...);a = new String(...) 输出结果:错误

(4)final修饰的实例变量必须手动赋值。

(5)final修饰的实例变量一般和static联合使用,称为常量。

  • finalize:是Object类中方法名,该方法在对象,被回收时被垃圾回收器调用(通常情况内存足够,不会被调用)。

  • finally:无论是否抛出异常,finally代码块总是会被执行。主要用来释放资源,比如:I/O缓冲区,数据库连接。

  • 4.1.9 常用的包

java.awt包

提供了绘图和图像类,主要用于编写GUI程序,包括按钮、标签等常用组件以及相应的事件类。

java.lang包

核心包,默认导入到用户程序,包中有object类,数据类型包装类,数学类,字符串类,系统和运行时类,操作类,线程类,错误和异常处理类,过程类。

java.io包

包含提供多种输出/输入功能的类。

java.net

包含执行与网络有关的类,如URL,SCOKET,SEVERSOCKET等。

java.applet包

包含java小应用程序的类。

java.util包

包含集合框架、遗留的 collection 类、事件模型、日期和时间设施、国际化和各种实用工具类(字符串标记生成器、随机数生成器和位数组、日期Date类、堆栈Stack类、向量Vector类等)。集合类、时间处理模式、日期时间工具等各类常用工具包。

java.sql包

提供使用 JavaTM 编程语言访问并处理存储在数据源(通常是一个关系数据库)中的数据的 API。

java.math包

提供数学类,例如BigDecimal类(调用add()求和,具有高精度性)

  • 4.1.10 String

String默认对象存储在方法区的String常量池中(不可变)new出来的String对象存储在堆中,详细请看这篇文章:String存储位置

图7.1 String的原理


public static void main(String[] args) {
    String s1 = new String("hello");
    String s2 = new String("hello");
    int arr1[] = {1,2};
    int arr2[] = {1,2};
    System.out.println(s1 == s2);
    System.out.println(s1.equals(s2));
    System.out.println(arr1.equals(arr2));
}
//结果
//false(引用类型,故而比较的是地址不相等)
//true(String对equals重写,故而比较的是值相等)
//false(引用类型,数组没有对equals重写,故而比较的是地址不相等)
//问:以上String创建了几个对象?
//答:3个对象,对象S1,S2存储在方法区String常量池中;“hello”被new出来储存在堆中;
  • 4.1.11 StringBuilder

动态字符串,基础容量:16;非线程安全

图7.2 StringBuilder源码

  • 4.1.12 StringBuffer

动态字符串,基础容量:16;添加了锁synchronized线程安全(效率不高)

图7.3 StringBuffer源码

  • 4.1.13 Integer包装类
  • 包装类的值都是final 不可变的,存储在方法区,对应的常量池中。

  • Integer包装类通过IntegerCache类,定义范围,在-128~127范围内则返回cache这个数组中的值,反之创建一个对象。


    Integer a1 = 127; Integer a2 = 127; System.out.println(a1 == a2);
    Integer b1 = 128; Integer b2 = 128; System.out.println(b1 == b2);
//结果
//true,127在范围内,integer是不变的,故而内存地址,值都一样。
//false,128不在范围内,则创建一个对象,故而内存地址依然不变,但是值不一样。

int——>Integer

例如:Integer i = 10;

自动装箱:将基本数据类型自动转换成对应的包装类

Integer——>int

例如:int a = i.intValue();

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

注:int/Integer转换成String,使用valueOf(),toString()方法;String转换成int/Integer,使用valueOf(),parseInt()方法。

  • 4.1.14 java中传递方式
  • 值传递(不会改变本身,只是传递拷贝数值):例如基本数据类型,以及String创建字符串等。

  • 引用传递(实参引用传给形参,通过形参找地址进行改变):例如数组,对象,除String以外。


public class TestArgs {
    public static void main(String[] args) {
        int A = 666;
        int B[] = {11,22,33};
        System.out.println("值传递初始值:"+A+"引用传递初始值:"+B[0]);
        m1(A);
        m2(B);
        System.out.println("值传递,结果:"+A+"引用传递,结果:"+B[0]);
    }
    public static void m1(int A){
        A=999;//赋值
        System.out.println("m1执行了,值没有改变");
    }
    public static void m2(int[] B){
        B[0]=100000;//赋值
        System.out.println("m2执行了");
    }
}
/*输出结果:
值传递初始值:666引用传递初始值:11
m1执行了,值没有改变
m2执行了
值传递,结果:666引用传递,结果:100000
*/
  • 4.1.15 java中比较方式

数据类型

引用类型

==

比较值

比较地址

equals

比较地址

Comparable

实现Comparable接口,重写CompareTo/Compara方法,自定义比较

注:String底层对equals,toString进行了重写(比较内容)。

  • 4.1.16 java中创建对象方式
通过 new对象,调用构造方法。
运用 克隆手段,调用对象的clone()方法。
运用 反射手段,调用java.lang.Class,或者java.lang.reflect.Constructor类中的newInstance()实例方法。
运用 反序列化手段,调用java.io.ObjectInputStream对象的readObject()方法。
  • 异常

  • Error:java运行时,系统内部错误/内存耗尽;不会抛出类对象,程序安全终止

  • Exception:

    • 方法不能按照正常的途径完成任务,会抛出一个封装了错误信息的对象。此时,方法会立刻退出,且不执行代码,同时不返回任何值。

    • 异常处理机制会将代码执行交给异常处理器,在下一个垃圾回收过程中被回收掉

  • RuntimeException(运行时异常)

1.数组索引越界异常: ArrayIndexOutOfBoundsException。

2.空指针异常 : NullPointerException。

3.类型转换异常:ClassCastException。

4.迭代器遍历没有此元素异常:NoSuchElementException。

5.数学操作异常:ArithmeticException。

6.数字转换异常: NumberFormatException。

  • CheckedException(检查时异常)

1、输入输出异常:IOException。

2、文件不存在异常:FileNotFoundException。

3、SQL语句异常:SQLException。

注:空值(NULL)代表了所有未初始化的对象,因此空值可以被分配为任何类型(java不报错,但运行时报错,空指针异常)

throws

类级别,声明可能发生的异常

throw

成员级别,抛出具体的问题对象(异常)

try...catch

————

try...finally

————

try...catch...finally

————

注:finally在return语句之后执行,但返回值是在finally执行前return确定的。

  • 反射

  • 概念能被任意类,动态获取信息以及动态调用对象方法称为,反射

  • 作用编译时无法预知对象和类属于哪些类,程序只能依靠运行时信息来发现该对象和类的真实信息,此时就必须使用到反射。

  • 例如:映射class,实例化对象,通过反射访问对象的Field,Method。大多用于反射接口,调用接口实现类的方法。

  • 获取class的三种方式


第一种:
Class c = Class.forName("完整类名带包名");
Class c = Class.forName("全限定类名");//c是一个引用,保存内存地址指向方法区中的字节码;
第二种:
Class c = 类型名.class;
第三种:
Class c = 引用.getClass();
  • 注解

  • 概念:Annatation(注解)是一个接口,程序可以通过反射来获取指定程序中元素的 Annotation

对象,然后通过该 Annotation 对象来获取注解中的元数据信息。分别为标准注解,元注解。

  • 四种标准元注解:

  • @Target:声明对象范围

  • types(包、类、接口、枚举、Annotation 类型);

  • 类型成员(方法、构造方法、成员变量、枚举值);

  • 方法参数;

  • 本地变量(如循环变量、catch 参数);

  • @Retention:定义被保留的时间长短。

  • @Documented:定义为公共API,使其成为javadoc工具文档化

  • @Inherited:阐述了某个被标注的类型是被继承的(字父同有该注解类)。

  • 泛型

  • 概念:将类<T>/方法<E>/通配符<?>定义为同一个类型参数变量,本质是参数化类型

  • 作用:能够编译时,具有类型安全检测机制。

  • 内部类

定义在类内部的类,称为内部类,根据位置不同,共有四种内部类。

静态内部类

概念:定义在类内部的静态类

作用:①可以访问外部类所有的静态变量和方法,即使是 private 的也一样;

②外部使用时,通过外部类.静态内部类的方式来new实例;

场景:和外部类关系密切的,且不依赖外部类实例

成员内部类

概念:定义在类内部的非静态类

局部内部类

概念:定义在方法中的类

匿名内部类

概念:定义在方法中的类,本质是一个new出来的对象(类名省略),不含class,必须继承一个父类或者实现一个接口。

作用:①可以方便直接,作为某个方法的类参数。

②可以方便直接,作为某个方法的类返回值。

③可以使用多态,给匿名内部类命名。


public class Test {
    public static void main(String[] args) {
        new Father() {  //new了一个父类抽象类的子类对象.匿名的
            public void m1() { System.out.println("重写了父类中的抽象方法");}
    };
}
abstract class Father {
    public abstract void m1();
}

注:Java集合类HashMap内部就有一个静态内部类Entry(用于存储HashMap的抽象元素)。

注:类初始化的时候先初始化静态成员,故而成员内部类,不允许出现静态任何变量。

  • 序列化

  • 概述:能够创建可复用的 Java 对象,JVM停止运行之后能够保存(持久化)指定的对象状态(成员变量)到磁盘/内存中,并不保存静态变量。

  • 作用:实现Serializable 接口,那么它就可以被序列化,并由序列化 ID决定版本号。

                     ②Transient 关键字能阻止该变量被序列化到文件中(例如在加密解密过程中使用)。

        注:当应用程序,希望把内存对象跨网络传递,到另一台主机或者是持久化到存储的时候,就必须要把对象在内存里面的表示转化成合适的格式。这个过程就叫做Marshalling,反之就是demarshalling。

                        

设计模式

java中常见的设计模式有24种,分别以类,对象为范围,分为三种模型(创建型,结构型,行为型)。

  • 目的分类

创建型模式:创建对象

结构型模式:处理类或对象的组合

行为型模式:描述类或对象交互与职责分配

  • 范围分类

类模式:处理类和子类的关系

对象模式:处理对象之间关系

图5.1 设计模式结构

  • 工厂模式

例如Spring中的,BeanFactory就是采用的工厂模式。把@Controller、@Service、@Repository 加载到工厂中,需要的时候由工厂帮忙创建。

  • 简单工厂模式

图5.2 简单工厂模式思维导图

  • 工厂方法模式

图5.3 工厂方法模式思维导图

  • 抽象工厂模式

图5.4 抽象工厂模式思维导图

  • 单例模式

例如Spring中的Bean默认为单例模式,也可以用多例(一般存在老代码中)。

图5.5 单例模式思维导图

  • 桥接模式

由于是多层次的继承结构,我们可以看SpringBoot与Dubbo(分布式结构)整合,底层采用的就是桥接模式,需要连接多个数据库,并且每次根据需求不同,每次访问的数据库不同。

图5.6 桥接模式思维导图

  • 代理模式

代理模式的主要作用一个中介,能在客户端与目标对象之间承上启下,增强访问,增强代码功能。Spring,SpringBoot中采用的为JDK动态代理/CGLIB字节码生成技术。核心是如何创建动态代理,如何使用动态代理。

静态代理

手动创建代理类,实现接口方法,目标固定

动态代理(JDK)

①实现InvocationHandler接口,重写invoke()方法;

②使用Proxy.newProxyInstance创建实例;

动态代理(CGLIB)

继承的目标类,目标方法不得是final修饰,由第三方工具库,创建代理对象

  1. 算法设计与分析

算法是一种编程思想,解决问题。操作对象是数据结构。

  • 算法设计

必须有输入/输出,含有三个特性(有限性(时间),确定性(指令清晰),可行性(正常执行))。

  • 算法分析

  • 时间复杂度:CPU资源,执行、读取次数。

  • 空间复杂度:存储空间,内存。

  • 渐进复杂度:T(n)=T‘(n),n->00。

  • 上界:f(n)=O(g(n))。


当n>=m,f(n)<=Cg(n)时,g(n)为f(n)上界==f(n)的阶低g(n),f(n)为g(n)的大O;
//常用公式
O(f)+O(g)=O(max(f,g)):f+g的阶之和,等于,f与g中较大的阶;
O(f)+O(g)=O(f+g):f+g的阶之和,等于,f+g的阶;
O(f)*O(g)=O(f*g):f*g的阶之积,等于,f*g的阶;
f=O(f):f上界不高于自身;
如果g(n)=O(f(n)),则O(f)+O(g)=O(f)
如果C为正整数,则O(C*f(n))=O(f(n))
  • 下界:f(n)=Ω(g(n))。


当n>=m,f(n)>=Cg(n)时,g(n)为f(n)下界==f(n)的阶高g(n),f(n)为g(n)的大Ω;
  • 同阶:f(n)=θ(g(n))。


当n>=m,C2g(n)>=f(n)>=C1g(n)时,g(n)为f(n)同阶,f(n)为g(n)的上界,也为下界;
  • 常用算法

  • 冒泡排序

原理:从左到右比较大小,得出最大值放置末尾,进行交互(不断重复)。

  • 选择排序

原理:从左到右比较大小,得出最小放在左边。

  • 二分法查找

原理:由开始位置值,末尾位置值。获得中间位置值。目标<中间,左边查找;目标>中间,右边查找(直到查到为止)。

  • 加密算法

  • 单钥密码(对称算法)

  • 特征:不可抗抵赖

  • 明文---加密密钥 --- 密文 --- 解密密钥---明文

图6.1 对称算法加密解密流程

  • 双钥密码(RSA算法/非对称算法)

  • 公开密文:不可鉴别,不可抗抵赖

  • 公开加密密钥/解密密钥:不可机密性

例如:磁盘加密软件(Truecrypt)邮件加密软件PGP(基于RSA算法)。

图6.2 非对称算法加密解密流程

  • DES算法

  • 扩散:明文统计,被扩散,消失到密文统计

  • 混乱:密文统计,密钥取值---二者关系尽量复杂

  • 雪崩效益:明文或密钥变化1bit,密文所有bit都可能变化

  • DES原理56位密钥--加密--64位明文-->16轮运算--64位密文

图6.3 DES加密流程简图

图6.4 DES解密流程简图

  1. java集合

  • Iterable接口/iterator迭代器

    • Iterable(接口):
      • 是List、Set、Collection的最高父类接口。
      • 定义了返回iterator的方法,相当于对iterator(迭代器)的封装,同时实现了iterable接口的类可以支持forEach循环。
    • iterator(迭代器):
      • 含有 iterator() 方法,能对List、Set 和 Map 等通过for-each() 循环进行遍历,通过hasNext()方法获取下一个元素,通过 remove() 方法来删除迭代器返回最后一个元素 ,不可以修改、添加元素。
      • Iterator 只支持从前向后遍历集合。
      • Iterator 没有提供获取元素索引的方法。
    • Listiterator(迭代器):
      • ​​​​​​​只能对List集合进行遍历。
      • ListIterator 支持从前向后遍历和从后向前遍历两个方向。
      • ListIterator 同时支持使用 set() 修改当前元素,以及使用 add() 方法在当前元素之前添加元素
      • ListIterator 可以通过 nextIndex() previousIndex() 方法获取下一个元素和上一个元素的索引值

图8.1 集合整体结构图

  • fail-fast/fail-safe

    • ​​​​​​​快速失败,集合遍历过程中一旦检测容器数据被修改(modCount的值被改变),直接抛出异常(Concurrent Modification Exception。)。
    • 安全失败,通过拷贝原集合的方式进行遍历,即使数据被修改了,也不能被迭代器检测到。
  • List接口

  • 数组优点:检索效率高

  • 数组缺点:随机增删效率低(末尾添加元素效率高)

  • 双向链表优点:随机增删效率高(内存地址不连续)

  • 双向链表缺点:检索效率低

  • Set接口

  • HashSet不可重复原理:会调用Object的hashCode方法判hashCode是否已经存在,如不存在则直接插入元素;如果存在则调用equals进行比较判断是否重复。

图8.2 Conllection集合结构图

  • Map接口

  • 哈希表:实际上就是一维数组单向链表结合体。

  • 二叉树(红黑树):可排序二叉树遵循左小右大原则,遍历方式包括前序遍历、中序遍历(TreeMap)、后序遍历;当节点低于6个,数据结构转为单向链表

  • 单向链表:含有Node节点2个属性①存储数据②下一个节点内存地址;当节点数超过8个,数据结构转为二叉树(红黑树)

图8.3 Map集合结构图

  • 扩展:HashMap中put/get实现原理:

Java中的HashMap使用hashCode()和equals()方法来确定键值对的索引
通过key调用 hashCode得到hash值转为数组,再通过 equals进去比较vule,最后 存进去哈希表中,或者取出。
注:存放在HashMap集合key部分的元素需要同时重写 hashCode+equals 方法(重写equals的时候必须同时重写hashCode,重写hashCode的时候不一定重写equals)。
  • 扩展:TreMap中key如何进行自动排序的:

创建TreeMap集合时通过构造方法传递一个比较器,存放在key部分的元素实现 Comparable接口
  • 扩展:ConcurrentHashMap与HashMap,HashTable联系/区别

ConcurrentHashMap底层是HashMap,也是 “数组+链表+红黑树”结构。
初始化数组/头节点时没有加锁;插入数据的时候会加锁,锁住链表头节点, 并发性好
  1. 多线程并发

  • 继承Thread

  • 启动:当前线程继承的Thread实例,调用start()。

  • 执行:重写父类中的run()方法。


//创建Threadt线程对象
Thread t1 = new MyThreadt();
t1.start();
  • 实现Runnable

  • 启动:实例化Thread类,参数传入当前线程实现的Runnable实例,调用start()。

  • 执行:重写父类中的run()方法。


 //创建Runnable线程对象
Thread t2 = new Thread(new MyRunablet());
t2.start();
  • 实现Callable

  • 启动:实例化FutureTask类,参数传入当前线程实例。

实例化Thread类,参数传入FutureTask实例,调用start()。

  • 获取返回值(默认Object):FutureTask实例,调用get()。

  • 执行:重写父类中的call()方法。


//创建Callable线程对象
FutureTask ft = new FutureTask(new MyCallable());
Thread t3 = new Thread(ft);
t3.start();
//获取返回值
Object obj = ft.get();
  • 线程生命周期

  • 新建状态:new创建线程对象。

  • 就绪状态:start()方法被调用,此时JVM开出新的栈空间,线程开始抢夺CPU时间片。

  • 运行状态:run()方法的开始。

  • 阻塞状态(wait/sleep/join/lock):放弃CPU时间片。

  • 死亡状态(正常结束/异常/stop):run()方法的结束。

注:调用stop()是线程不安全的,因为同时释放该线程所有的锁,导致不可控。

  • 线程常用方法

wait(),Object类

当前线程等待,释放锁,让出CPU时间片(阻塞),调用notify()/notifyAll()后才会获取锁。

join(),底层是wait()

t合并到当前线程,释放锁,当前线程让出CPU时间片(阻塞),t执行直到终结,当前线程执行。

sleep(),Thread类

当前线程休眠,不释放锁,让出CPU时间片(阻塞)

yield(),Thread类

当前线程让位不释放锁回到就绪状态,重新抢夺CPU时间片

interrupt()

当前线程打上中断标识,当存在标识返回ture,不存在标识返回false(一个线程抛出抛InterruptedException异常前,都会清除中断标识位

  • 守护线程

  • 概念:服务于用户线程(普通线程),权重是比较低;当用户线程结束,守护线程自动结束。

  • 用法:使用Thread中的方法setDaemon(true),将该线程设置为守护线程。

  • 案例:垃圾回收器GC,当垃圾回收线程是JVM上仅剩的线程时,垃圾回收线程会自动结束。

注:线程是JVM级别,例如当WEB停止时,JVM中的线程可能还在运行。

  • 三种核心锁

  • 多线程三大特性:

  • 原子性(存在多线程共享成员变量中,要么执行完毕要么没有发生);

  • 可见性(及时同步线程信息,例如私有/公共/内存中的数据);

  • 有序性(阻止指令重排,保证指令按序执行);

  • volatile

  • 只能修改变量。

  • 不会出现阻塞。

  • 保证线程间有序性,只保证变量可见性,不保证原子性(例如long/double)。

  • synchronized(同步锁)

  • 可以修饰,类,方法(对象锁),静态方法(类锁唯一),以及代码块。

  • 会出现阻塞。

  • 保证线程间有序性,间接保证可见性,保证原子性

  • Lock

  • 具有synchronized所有功能,需手动释放锁,try..finally连用

  • lock.lock()加锁

  • lock.unlock()释放锁

  • 扩展其他的锁

死锁

多个线程同时被阻塞,它们中的一个或者全部都在等待某个资源被释放。

乐观锁

每次去拿数据的时候都认为别人不会修改,所以每次读写,不会上锁;但在更新的时候,会比较版本号然后加上锁。

悲观锁

每次去拿数据的时候都认为别人会修改,所以每次读写,都会上锁。

例如Synchronized,AQS框架下的锁则是先尝试cas乐观锁去获取锁,获取不到,才会转换为悲观锁。

自旋锁

当持有锁的线程能快速短时间释放资源,则让当前需要锁的线程等待,而不是进入阻塞。

可重入锁

又称递归锁,同一线程 外层函数获得锁之后 ,内层递归函数仍然有获取该锁的代码,但不受

影响。

例如ReentrantLock 和 synchronized 都是可重入锁

公平锁

加锁前检查是否有排队等待的线程,优先排队等待的线程,先来先得。

非公平锁

加锁时不考虑排队等待问题,直接尝试获取锁,获取不到自动到队尾等待。

例如synchronized 是非公平锁,ReentrantLock 默认的 lock()方法采用的是非公平锁

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值