Java基础 (适合新手入门保姆级)

基础1

1、进制的转换

    1. 十进制数据转成二进制数据:使用除以2获取余数的方式

    2. 二进制(0B/b开头)转换为十进制:1001 = 1*2^0+0*2^1+0*2^2 +1*2^3 = 9

    3. 二进制转八进制(0开头)方便观察二进制:把八个二进制数从右向左每三个分一组进行运算          (0-7)

   4. 二进制转十六进制(0X/x开头)把八个二进制数从右向左每四个分一组运算(0-9,A-E)

2、字节和位

    1.  字节(Byte):计量存储容量的一种计量单位,一字节等于八 位,也表示一些计算机编程语言中的数据类型和语言字符。
    2.  位(bit):是数据存储的小单位。也就是二进制。二进制数系统中,每个0或1就是一个位,叫 做bit(比特),其中8 bit 就称为一个字节(Byte)

     3.常用DOS命令(win+R输入cmd进入dom模式)

    1. 盘符切换命令: 盘符名:
    2. 查看当前文件夹内容: dir
    3. 进入文件夹命令: cd 文件夹名
    4. 退出文件夹命令: cd ..
    5. 退出到磁盘根目录: cd \
    6. 清屏 :cls
    7. 退出 :exit

4.Java语言概述

    1. Java技术平台

   JavaME(小型版):是为开发电子消费产品和嵌入式设备提供的解决方案,但已经被Android所取 代。 

   JavaSE(标准版):是为开发普通桌面应用程序和商务应用程序提供的解决方案。

   JavaEE(企业版):是为开发企业环境下的应用程序提供的一套解决方案,主要针对于Web应用程 序开发。 

    2. Java语言的特点

   完全面向对象:Java语言支持封装、继承、多态,面对对象编程,让程序更好达到高内聚 ,低耦合的标准。 支持分布式:Java语言支持Internet应用的开发,Java应用编程接口中有一个网络应用编 程接口(java net),它提供了用于网络应用编程的类库,包括URL、URLConnection、Socket、 ServerSocket等。Java的RMI(远程方法激活)机制也是开发分布式应用的重要手段。 

   健壮型:Java的强类型机制、异常处理、垃圾的自动收集等是Java程序健壮性的重要保证。对指针 的丢弃是Java的明智选择。 

   安全:Java通常被用在网络环境中,为此,Java提供了一个安全机制以防恶意代码的攻击。如:安 全防范机制(类ClassLoader),如分配不同的名字空间以防替代本地的同名类、字节代码检查。 

   跨平台性:Java程序(后缀为java的文件)在Java平台上被编译为体系结构中立的字节码格式(后 缀为class的文件),然后可以在实现这个Java平台的任何系统中运行。

   3. 跨平台原理

   跨平台:Java编写的软件运行在任何的操作系统上,这个特性称为Java语言的跨平台特性。该特性是由JVM实现的,我们编写的程序运行在JVM上,而JVM运行在操作系统上。

    JVM(Java Virtual Machine ):Java虚拟机,简称JVM,是运行所有Java程序的假想计算机,是 Java程序的运行环境之一,也是Java 具吸引力的特性之一。我们编写的Java代码,都运行在JVM 之上。

   4. JRE和JDK (三者关系: JDK > JRE > JVM )
   JRE  (Java Runtime Environment) :是Java程序的运行时环境,包含 JVM 和运行时所需要的 核心 类库 。 JDK  (Java Development Kit):是Java程序开发工具包,包含 JRE 和开发人员使用的工具。
   我们想要运行一个已有的Java程序,那么只需安装 JRE 即可。
   我们想要开发一个全新的Java程序,那么必须安装 JDK ,其内部包含 JRE 。

5、Java基本语法

    1. 程序的开发步骤:编写后的.java源文件通过编译器compiler编译为.class字节码文件,再由解          释器interpreter解释为二进制数据运行。(DOS模式下,javac 文件名.java进行编译,然后              java 文件名进行运行)

     2. 注释:单行注释://    多行注释:/* */    文档注释:/**   */

     3. 关键字:在程序中被赋予特殊含义的英文单词
                特点:1.关键字被赋予特殊的语法含义
                         2.关键字全部小写
                         3.在部分文本编辑器中关键字颜色高亮显示
                注意:1.关键字一共53个,其中常用关键字51个,保留关键字2个
                         2.main和java不是关键字

    4. 变量:在程序中其值可以发生改变的量      前提(三要素):数据类型、标识符(变量名)、初始化值
                格式:直接声明初始化:数据类型 变量名 = 初始化值;
                        先声明后初始化:数据类型 变量名;变量名 = 初始化值;

    5. 数据类型:在程序中数据的类型
   分类:
           基本类型
                整数型:存储整数数据的数据类型
                   关键字分类:
                        byte:每声明一个byte类型变量,在内存中占1个字节
                        short:每声明一个short类型变量,在内存中占2个字节
                         int(默认):每声明一个int类型变量,在内存中占4个字节
                         long:每声明一个long类型变量,在内存中占8个字节
                    浮点型:存储浮点数据的数据类型(类似小数,有别于小数)
                    关键字分类:
                          float:每声明一个float类型变量,在内存中占4个字节
                          double(默认):每声明一个double类型变量,在内存中占8个字节
                     字符型 :存储“单个字符”(字符,数字,标点,中文等)的数据类型
                     关键字:char
                      注意:char类型变量在内存中有"外码"和"内码"存储方式之分
                        内码规则:当char类型变量由底层源码进行"声明初始化,每个字符在内存中占2个字节
                         外码规则:当char类型变量由程序员自己进行声明初始化,每个字符根据开发环境编                                          码方式所确定
                          常用的编码方式:   GBK编码:字母,数字,标点,中文每个字符占2个字节     

                           UTF-8编码:字母,数字,英文标点每个字符占1个字节。中文每个字符占3个字节

   ​                  布尔型:存储真假值的数据类型
   ​                    关键字:boolean
   ​                  注意:每个boolean类型变量的初始化值占4个字节(栈)
   ​                          在程序中声明初始化布尔数组,数组中"每个元素占"用内存1个字节(堆)

6. 标识符:

              在程序中给包,类,接口,方法,变量等起的名字
             硬性规则:
                 1.标识符由英文大小写字母,0-9数字,美元符$,下划线_,部分中文字符
                 2.0-9数字不能作为标识符的开始
                 3.标识符不能是Java语言中的关键字
             软性规范:
                 1.标识符不推荐使用中文字符
                 2.标识符做到"见名知意"
                 3.给不同的内容进行命名时要遵循不同的规范
                     类的命名规范: 每个单词的首字母都大写
                     方法的命名规范: 首字母小写,往后每个字母首字母大写
                     变量的命名规范: 首字母小写,往后每个字母首字母大写 

7. 初始化值:在程序中给变量赋的数据值(或地址值)
   注意:1.变量使用前,必须先赋值再使用
            2.初始化值要在声明的数据类型的取值范围内
            3.long类型的初始值要在其后写上字母L或l,"推荐字母L"
            4.float类型的初始值要在其值后加字母F或f,"推荐字母F"
            5.double类型的初始化值,需要在其值后加字母D或d,推荐不写
            6.给char类型初始化值需要使用' '进行表示,且' '中的字符仅有一个字符
            7.给char类型变量进行初始化时,初始化值常用有两种表示方式,无论哪种表示方式都是以单字符形式进行使用

   ​         8.给boolean类型变量进行初始化时,初始化值只有两个true和false
   ​         9.给变量进行赋值时,可以将一个变量名赋值给另外一个变量,前提必须遵循基本类型的转换和引用类型的转换

   补充:
           ASCII码表:十进制数字和字符进行一一对应的码表,里面共128组对应规则(数字0~127)
               字符0        十进制数字48
               字符A        十进制数字65
               字符a        十进制数字97
           Unicode码表(数字0~65535)    

8. 变量声明初始化的注意事项:

   1.遵循数据类型,标识符,初始化值的注意事项
   2.在同一作用域(当前大括号)内不可以声明同名变量
   3.变量的使用不能超过所属的作用域范围
   4.可以通过一个数据类型在一行上直接声明多个变量,中间用逗号“,”进行间隔

   5.变量的执行结果不是取决于初始化值的数据类型,而是取决于声明变量的数据类型

基础2

 1、数据类型的转换

   类型转换:数据类型之间的转换
               基本类型间的转换
               引用类型间的转换
               基本类型和包装类型间的转换
               基本类型和字符串类型间的转换

基本类型转换:将基本类型的数据进行类型转换
           分类:隐式转换(自动转换)、显式转换(强制转换)
           格式:数据类型A 变量名 = (数据类型A)数据类型B的数据值;
           注意:基本类型转换的格式适用于自动转换,也适用于强制转换,在自动转换时可以省略不写

2. 自动转换(隐式转换):

将取值范围较小的数据类型转换成取值范围较大的数据类型(也可以使用强转格式)

1.在自动转换时,可以将类型转换的格式省略不写
2.boolean不可以进行基本类型转换根据基本类型取值范围大小关系总结如下:
    byte <short、char < int < long < float < double(byte、short和char不能自动转换)

3. 强制转换(显式转换):将取值范围较大的数据类型转换为取值范围较小的数据类型
    格式:取值范围较小的数据类型 变量名 = (取值范围较小的数据类型)取值范围较大数据类                          型 的数据值;
     注意:尽量避免强制转换,因为可能会发生精度的损失和数据的溢出

4. 基本类型转换的注意事项:
   1.基本类型转换的格式适用于自动转换和强制转换,在自动转换时,格式可以省略不写;
   2.基本类型转换是七种数值类型间的转换,与boolean类型无关
   3.尽量避免强制转换,因为可能会发生精度的损失和数据的溢出
   4.byte,short,char这三种数据类型只要参与数学运算,先将数据越级提升成int类型,再参与运算操作;如果没有参与数学运算,依然遵循取值范围的特点转换

2、常量

1. 常量:在程序中其值不可以发生改变的量
                分类:字面值常量、自定义常量

   字面值常量:单独的一个值,不具备任何意义,需要结合其它语句进行使用
   分类:整数字面值常量、浮点字面值常量、字符字面值常量、布尔字面值常量、字符串字面值常量、空字面值常量

2. 常量的注意事项:
   1.给byte,short,char类型变量进行赋值操作时,如果右边的初始化值是字面值常量,且还在该数据类型的取值范围内,JVM的编译器自动在编译时期将其优化为byte类型数据,我们将这一优化称之为"常量优化机制"
    2.给变量进行赋值操作时,如果右边的初始化值是一个数学运算式子,且运算的符号两边都是字面值常量和运算后的结果还在该数据类型的取值范围内,JVM的编译器会将这一运算过程由运行时期提前至编译时期,在成.class文件已运算完毕,我们将这一优化称之为"常量优化机制"

3. 两种常见的输出语句
   换行输出语句:
                格式:System.out.println(输出内容);
                特点:在控制台打印内容后,进行"回车换行"处理
            直接输出语句:
                格式:System.out.print(输出内容);
                特点:在控制台打印内容后,不做任何处理
            注意事项:
                换行输出语句如果里面没有任何内容,直接进行回车换行处理
                直接输出语句如果里面没有任何内容,编译报错

   回车:将光标移动到该行的行首
   换行:将贯标移动到下一行相同的位置

3、运算符(Operator)

1. 运算符:在程序中用来连接变量或常量的符号

   表达式: 在程序中用运算符连接起来的式子

   常见运算符的分类:算术运算符、赋值运算符、关系运算符、逻辑运算符、三元运算符、位运算符

2. 算术运算符:在程序中针对变量或常量进行运算操作的运算符
                分类:
                 数学运算符:+, - , * , / , %(取余)
                 自增运算符:++(与其他表达式一起用时,++在前先赋值再使用,++在后先使用后赋值)
                 自减运算符:--(与其他表达式一起用时,--在前先赋值再使用,--在后先使用后赋值)

   ​              注:int i1 = 2;   i1 *= i1++;  结果为4,此处的++在最后不参与运算

数学运算符的注意事项:      /:取的是两个数相除的商    %:取的是两个数相除的余数

3. +号的多种用法:
   1.加法运算符          2.字符串连接符字符串连接符
            含义:当+号两边有任何一边出现了字符串时,+号不再起到加法运算操作,而是转换成字符串连接符,将两边的内容进行连接操作,得到新的字符串

4. 赋值运算符:进行赋值操作的运算符
             分类:
                 基础赋值运算符:=
                 扩展赋值运算符:+= , -= , *= , /= , %= , ......
             含义:将运算符两边的内容进行运算操作,再将运算后的结果赋值给左边变量
             注意:扩展的赋值运算符再将结果赋值给左边的变量之前,会根据左边的变量的数据类型针对结果进行隐式的强制转换

5. 关系运算符:针对变量进行比较的运算符
   分类:< , <= , > , >= , == , != 
           注意:1.关系表达式的结果一定是boolean值

   ​                  2.在程序中不要将==写成=,也不要将=写成==
   ​        ==的含义:比较基本类型数据值是否相等

   ​         !=的含义:比较基本类型数据值是否不等

6. 逻辑运算符:用来连接boolean值结果的运算符


            分类:基础逻辑运算符:& , | , ^ , !                                        
                     短路逻辑运算符:&& , ||
        基础逻辑运算符
            运算符&:与,且
                特点:有false则false
                场景:判断多个条件是否同时满足
            运算符|:或
                特点:有true则true
                场景:判断多个条件是否至少满足一个
            运算符^:(了解)异或
                特点:相同为false,不同为true
                场景:判断两个条件结果是否不等
            运算符!:非
                特点:非false则true,非true则false
                场景:针对boolean值结果进行取反

7. 短路逻辑运算符:&&  ||

   运算符&&:双与,短路与
       特点:有false则false
       注意:&和&&的结果是一样的;&&具有短路效果,当运算符前面的表达式结果为false时,运算符后面的表达式不会被执行;如果是&的话,无论运算符前面的表达式结果是true还是false,运算符后面的表达式都会被执行,在实际应用中更推荐是用&&
   运算符||:双或,短路或
       特点:有true则true
       注意:|和||的结果是一样的;||具有短路效果,当运算符前面的表达式结果为true时,运算符后面的表达式不会被执行;如果是|的话,无论运算符前面的表达式结果是true还是false,运算符后面的表达式都会被执行,在实际应用中更推荐是用||

8. 三元运算符


             含义:含有三个未知量的运算符
             格式:关系表达式 ? 结果值1 : 结果值2;
             流程:1.先确认关系表达式的结果是true还是false
                     2.在确认关系表达式结果的同时,统一结果值1和结果值2的数据类型
                     3.如果是true,执行统一数据类型后的结果值1;
                        如果是false,执行统一数据类型后的结果值2;

9. 原码反码补码:


             相同点:
                 在程序中都是针对二进制数据进行定点表示法:
                     (1)原反补 针对二进制规定了符号位,最高位即符号位,正数为0,负数为1
                     (2)原反补 针对存储占用的字节数进行二进制补全,不足位数,在符号位后面进行补0操作
                         int类型的1:
                             二进制1
                             "定点表示法":
                                 00000000 00000000 00000000 00000001
             不同点:
                 原码:是屏幕显式数据的二进制定点表示法
                 补码:计算机中所有的数据操作都拿原码的补码形式进行计算操作
                 反码:针对原码和补码进行转换的中间量
         数据存储操作过程:
             1.显式的数据==>数据的原码
                 如果数据是正整数,符号位确认为0,并补足位数
                 如果数据是负整数,符号位确认为1,并补足位数
             2.数据的原码==>数据的反码
                 如果数据是正整数,数据的反码与其原码相同
                 如果数据是负整数,数据的反码是针对原码进行逐位取反,符号位保持不变
             3.数据的反码==>数据的补码
                 如果数据是正整数,数据的补码与其反码相同
                 如果数据是负整数,数据的补码在其反码的基础上进行+1运算
             4.数据的补码==>结果的补码
                 数据的存储或操作
             5.结果的补码==>结果的反码
                 如果结果是正整数,结果的反码与其补码相同
                 如果结果是负整数,结果的反码在其补码的基础上进行-1运算
             6.结果的反码==>结果的原码
                 如果结果是正整数,结果的原码与其反码相同
                 如果结果是负整数,结果的原码是针对反码进行逐位取反,符号位保持不变
             7.结果的原码==>显式的结果
                 如果结果是正整数,直接转换显式结果
                 如果结果是负整数,忽略符号位,将其直接转换显式结果并添加负号
         将int类型的130强制转换成byte类型     (byte-128到127)
             1.显式的数据==>数据的原码
                 数据的原码:00000000 00000000 00000000 10000010
             2.数据的原码==>数据的反码
                 数据的反码:00000000 00000000 00000000 10000010
             3.数据的反码==>数据的补码
                 数据的补码:00000000 00000000 00000000 10000010                
             4.数据的补码==>结果的补码   
                 结果的补码:10000010
             5.结果的补码==>结果的反码
                 结果的反码:10000001
             6.结果的反码==>结果的原码
                 结果的原码:11111110
             7.结果的原码==>显式的结果
                 显式的结果:-126

10. 位运算符:针对二进制进行操作的运算符


            目的:1.查看源码
                     2.面试题
            分类:
                按位运算符:& , | , ^ , ~
                移位运算符:<< (左移几位就乘几个2), >>(右移几位就除几个2) , >>>
        按位运算符&:按位与,当两位都为1时才为1
        按位运算符|:按位或,只要有一位为1即为1
        按位运算符^:按位异或。两位相同为0,不同为1

    ​    按位运算符~:按位非,将操作数的每个位(包括符号位)全部取反

4、运算符的优先级

分隔符 . 、 [] 、 () 、 {} 、 , 、;
单元运算符 ++ 、--、 ~ 、 !
强制类型转换运算符 (type)
乘法、除法、求余 * 、 / 、 %
加法、减法 + 、
移位运算符 << 、 >> 、 >>>
关系运算符 < 、 <= 、 >= 、 > 、 instanceof
等价运算符 == 、 !=
按位与 &
按位异或 ^
按位或 |
条件与 &&
条件或 ||
三元运算符 ? :
赋值运算符 = 、 += 、-= 、 *= 、 /= 、 %=

(分单强乘加移关,等按按按条条三,赋)

基础3

 1、流程控制语句1

1. 顺序结构:代码从上至下依次执行
   流程控制作用于顺序结构中
       流程控制语句:
                分支结构:if语句、switch语句
                循环结构:for语句、while语句、dowhile语句
            调用结构:方法 

2. 三种循环的区别:
   1.循环语句的执行次数(当循环条件语句为false时,循环体语句至少执行的次数)
       for语句和while语句当循环条件语句为false时,循环体语句至少执行0次
       dowhile语句当循环条件语句为false时,循环体语句至少执行1次
    2.实际开发中如何选择
       有明显的循环次数或循环范围,选择for语句
       没有明显的循环次数或循环范围,选择while语句
       在实际开发中不会选择dowhile语句

3. 控制语句:操作流程控制的语句
                分类:break、continue、return
         break关键字:1.switch语句中(结束switch语句)
                                   2.循环语句中(结束循环语句)
         continue关键字:循环语句中(跳出本次循环,继续下一次循环)
         控制语句的注意事项:在和控制语句相同的作用域内,控制语句的后面不可以编写任何代码,否则编译报错,因    为永远执行不到

4. 流程控制语句的注意事项:
   if语句,for语句,while语句如果{}中的语句体有且仅有一行时,{}可以省略不写,但是实际开发中推荐写上

 2、dowhile语句的格式:

​        do {
​            循环体语句
​        } while (循环条件语句);

执行流程:
        1.先执行循环体语句;
        2.再确认循环条件语句的结果是true还是false;
        3.如果是true,跳回第1步,继续执行;
          如果是false,dowhile语句结束;
    为了和for循环进行转换,衍生出dowhile语句的扩展格式
        初始化语句
        do {
            循环体语句
            迭代语句
        } while (循环条件语句);

 3、for语句的基本格式:    

​        for (初始化语句;循环条件语句;迭代语句) {
​            循环体语句
​        }
​        初始化语句:声明初始化循环变量的语句
​        循环条件语句:循环的判断条件
​        循环体语句:重复执行多次的代码
​        迭代语句:循环的后续操作
​    执行流程:
​        1.先执行初始化语句;
​        2.确认循环条件语句的结果是true还是false;
​        3.如果是true,执行循环体语句;
​          如果是false,for语句结束;
​        4.执行迭代语句;
​        5.跳回第2步,继续执行

 4、if语句

1. 第一种格式

​        if (条件判断语句) {
​            语句体
​        }
​    执行流程:
​        1.先确认条件判断语句的结果是true还是false;
​        2.如果是true,执行语句体,if语句结束;
​          如果是false,if语句语句;
​    需求:判断指定的整数是否为偶数,如果是进行打印

  2.第二种格式:
        if (条件判断语句) {
            语句体1
        } else {
            语句体2
        }
    执行流程:
        1.先看条件判断语句的结果是true还是false;
        2.如果是true,执行语句体1;
          如果是false,执行语句体2;
    注意事项:
        if语句的语句体可以是多行逻辑代码,三元运算符只能是结果值,具有一定的局限性,在实际开发中更推荐使用if语句的第二种格式
    需求:判断指定的整数的奇偶性

3.第三种格式:
        if (条件判断语句1) {
            语句体1
        } else if (条件判断语句2) {
            语句体2
        } 
        ......
        else if (条件判断语句n) {
            语句体n
        } else {            
            语句体n+1
        }
    执行流程:
        1.先确认条件判断语句1中的结果是true还是false
        2.如果是true,执行语句体1,if语句结束;
          如果是false,确认条件判断语句2中的结果是true还是false
        ......
        3.当所有条件判断语句的结果都是false,执行else中的语句体n+1
    注意:
        if语句的第三种格式,else语句在部分场景中可以省略不写,但是推荐写上
        (个人理解:否则会出现虚拟机判断出错的情况,虽然这种情况极少)

 5、switch

1. switch语句的基本格式:
   switch (选择值) {
                case 数据值1:
                    语句体1
                    break;
                case 数据值2:
                    语句体2
                    break;
                ......
                case 数据值n:
                    语句体n
                    break;
                default:
                    语句体n+1
                    break;
            }
        执行流程:
            1.先确认选择值的最终结果是多少
            2.选择数据值1和选择值进行匹配,看是否匹配成功;
            3.如果匹配成功,执行语句体1,执行break,switch语句结束;
              如果匹配失败,选择数据值2和选择值进行匹配,看是否匹配成功;
            ......
            4.当所有的数据值和选择值都匹配失败,执行default中的语句体n+1,执行break,switch语句结束;
2. switch语句的注意事项:
   1.switch语句()中选择值的数据类型只支持以下几种:
                基本类型:原则上在内存中只支持int类型,因为自动转换可以衍生出byte,short,char
                引用类型:
                    JDK5.0(包含)以后:支持枚举Enum类型
                    JDK7.0(包含)以后:支持字符串String类型
            2.swtich语句中的default和if语句的第三种格式中else类似,可以省略不写,推荐写上
            3.swtich语句中的default和case位置可以互换,但不影响执行流程
            4.switch语句中的break可以省略不写,但是会出现case穿透效果
3. if语句和switch语句的区别:
   if语句可以针对范围或条件进行判断,但switch语句不能,在实际应用中更推荐使用if语句,在底层中switch语句的执行效率比if语句高,但是在硬件过剩的今天,这点效率可以忽略不计

 6、while

1. while循环的格式:
   while (循环条件语句) {
                循环体语句
            }
        执行流程:
            1.先确认循环条件语句的结果是true还是false;
            2.如果是true,执行循环体语句;
              如果是false,while语句结束;
            3.跳回第1步,继续执行
        为了和for语句之间进行转换,衍生出while循环扩展格式:初始化语句
            while (循环条件语句) {
                循环体语句
                迭代语句
            }

 7、break、continue、return的区别

1. break用于switch和循环,用于结束switch和当前循环
2. continue用于循环,用于结束本次循环
3. return用于结束当前方法,还可以用于return返回值返回结果

8.运算符优先级

1. 运算符优先级的注意事项
   1.Java中运算符的优先级和数学中的优先级不一样,不是谁优先级高,就最先执行谁,而是式子从左到右依次执行,遇到运算符的时候,再考虑优先级问题,先执行谁后执行是谁的问题
   2.不要把一个表达式写得过于复杂,如果一个表达式过于复杂,则把它分成几步来完成;
   3.不要过多的依赖运算的优先级来控制表达式的执行顺序,这样可读性太差,尽量使用()来控制表达式的执行顺序
   4.如果表达式中出现了自增自减运算符,并且出现了(),这个时候需要特殊注意优先级问题
   5.如果表达式中出现了自增自减运算符,且=的两边出现了相同的变量,这个时候需要特殊注意优先级问题
   6.如果表达式中出现了扩展的赋值运算符,需要将扩展的赋值运算符拆分成基础赋值运算符再进行计算
   7.除了上述情况外,不需要特殊关注运算符优先级问题

基础4

 1、流程控制语句2

1. 死循环:判断条件永远为true的循环语句
   for的死循环格式:
             for (;;) {
                 循环体语句
             }
         while死循环格式:
             while (true) {
                 循环体语句
             }
         两种死循环语句的区别:
             1.在实际开发中,更推荐使用while的死循环格式,原因:格式简洁明了,死循环是属于没有明显的循环范围或次数
             2.在使用两种死循环执行相同的代码时,for的死循环格式执行效率比while的死循环格式更高,往往将for的死循环格式应该在算法中或者是源码中,而在其它的情况下,可以忽略提高的效率,使用while的死循环

2. 循环嵌套语句:在循环语句中存在另外的循环语句
                注意:在循环前提中,在外层的循环称之为外层循环语句;
                      在内存的循环称之为内层循环语句,内层循环和外层循环是一对相对的概念
             格式:
                 for (外层循环的初始化语句;外层循环的循环条件语句;外层循环的迭代语句) {
                     for (内层循环的初始化语句;内层循环的循环条件语句;内层循环的迭代语句) {
                         内层循环的循环体语句
                     }
                 }
             执行流程:
                 1.执行外层循环的初始化语句;
                 2.确认外层循环的循环条件语句的结果是true还是false;
                 3.如果是false,循环嵌套语句结束;
                    如果是true,执行内层循环语句(a~e步);
                     a.执行内层循环的初始化语句;
                     b.确认内层循环的循环条件语句的结果是true还是false;
                     c.如果是false,内层循环语句结束,继续执行第4步;
                       如果是true,执行内层循环的循环体语句;
                     d.执行内层循环的迭代语句;
                     e.跳回第b步,继续执行
                 4.执行外层循环的迭代语句;
                 5.跳回第2步,继续执行

    循环嵌套语句的特点(注意事项):
            1.循环嵌套语句中外层循环的初始化语句执行了(1)次
       2.循环嵌套语句中内层循环的初始化语句执行了(外层循环的次数)次
             3.循环嵌套语句中内层循环的循环体语句执行了(外层循环的次数 * 内层循环的次数)次

 2、方法

1. 调用结构:方法
   方法:
             含义:封装特殊功能的代码块
             好处:1.提高代码的复用性,从而提高开发效率
                      2.降低代码的耦合性
             代码与代码之间的关联,代码越独立耦合性越低,方法在栈里先进后出,后进先出。
2. 调用结构的特点:
       1.方法与方法之间的关系是:调用结构
             2.不调用,不执行
             3.方法的执行有两个关键性因素:传参和返回
                     传参:将实参传递给形参的过程(当自定义方法需要使用到调用者方法中的数据时,是无法直接进行使用的,需要通过传参的形式进行数据的传递)
                     实参:调用方法时()中的参数,实参是具体的数据值或地址值
                     形参:声明方法时()中的参数,形参是声明变量类型和变量名        
                     返回(返回结果):当调用者方法需要使用到自定义方法中的结果数据时,将自定义方法的最终结果返回给调用者方法的过程
3. 方法调用的图解

1. 方法的声明格式:
   修饰符 返回类型 方法名 (形参类型1 形参名1 , 形参类型2 形参名2 , ...... ,  形参类型n 形参名n) {
                方法体语句
                return 返回值;
            }
            修饰符:给方法添加语法限定的关键字
            返回类型:方法返回结果数据的数据类型
                返回类型可能是:无返回类型,基本类型,引用类型
            方法名:方法的名字,符合标识符的特点,做到见名知意即可
            ():形参列表
                形参可能是:没有任何形参,基本类型,引用类型
            方法体语句:特殊功能的代码片段
            return:控制语句:(1)结束方法(2)如果return后面出现返回值,在结束方法的同时,将返回值返回给调用者;
            返回值:方法需要返回的结果数据

2. 方法声明前的两个明确:
   明确方法的返回类型
                清楚方法结果数据的数据类型
            明确方法的形参列表:
                清楚自定义方法需要使用外界几个参数
                清楚每个参数的数据类型

3. 方法的调用:
   1.如果方法归属"对象",需要通过对象名进行调用
                直接调用(单独调用)
                    对象名.方法名(实参);
                输出调用(打印调用)
                    System.out.println(对象名.方法名(实参));
                赋值调用
                    数据类型 变量名 = 对象名.方法名(实参);
            2.如果方法归属"类",需要通过类名进行调用
                直接调用(单独调用)
                    类名.方法名(实参);
                输出调用(打印调用)
                    System.out.println(类名.方法名(实参));
                赋值调用
                    数据类型 变量名 = 类名.方法名(实参);
            3.调用同一个类中且修饰符相同的方法:
                直接调用(单独调用)
                    方法名(实参);
                输出调用(打印调用)
                    System.out.println(方法名(实参));
                赋值调用
                    数据类型 变量名 = 方法名(实参);

   注:同一类中,实例方法可以直接调用静态方法和实例方法,而静态方法中不能直接调用实例方法,需要通过对象进行调用

4. void关键字:
   含义:表示方法没有返回值
            作用:当方法声明时,如果确认方法没有返回值时,返回类型的位置也不能空着,需要使用void关键字进行占位
            注意:1.当方法的返回类型是void时,方法的调用方式只能使用单独调用
                     2.当方法的返回类型是void时,方法体中的return关键字可以省略不写

5. 方法的小结:
       1.方法声明的位置:类中方法外,无法形成方法的嵌套
                   2.方法中可以含有多个return语句,但最终执行的return只有一个
                   3.方法的核心特点:不调用,不执行
                   4.当方法没有返回值时,声明方法时返回类型的位置也不能空着,需要使用void关键字进行占位;
                   5.当方法的返回类型是void时,方法体中的return可以省略不写
                   6.当方法的返回类型是void时,方法的调用方式只能单独调用(直接调用)
                   7.当方法的返回类型不是void时,方法的调用方式推荐赋值调用

 3、方法的重载

1. 含义:在同一个类中(或子父类继承关系中)出现了方法名相同,形参列表不同的现象
   方法重载的前提条件
             1.必须在同一个类中(或子父类继承关系中)
             2.方法名必须相同
             3.形参列表必须不同(至少满足以下一点)
                 (1)形参的数据类型不同
                 (2)形参的个数不同
                 (3)形参的数据类型顺序不同
2. 方法重载的注意事项:
   执行重载的方法具体执行哪个和方法本身无关,和方法的实参列表和形参列表有关

 4、方法的递归

1. 含义:方法自身调用自身形成循环现象
   分类:直接递归
                方法A中调用方法A
                    间接递归
                方法A中调用方法B,方法B中调用方法C,方法C中调用方法A
            注意:1.使用递归时需要给递归添加限定的条件,否则会发生StackOverflowError(堆栈内存溢出错误)
                    2.使用递归时即使有限定条件,也不能让递归的层数过深,否则会发生StackOverflowError(堆栈内存溢出错误)
2. 好处:可以解决一些for和while循环无法解决的问题

​       递归的弊端:递归层数越多,程序执行效率越低

5、JVM中的内存:栈内存

1. 栈内存(方法栈) :JVM中存储"正在运行方法"的内存
                名词:进栈(压栈):将方法进入栈内存的过程
                         出栈(弹栈):将方法在栈内存中消失的过程
                 特点:1.方法中的内容会随着方法的进栈而进栈,会随着方法出栈的消失
                          2.方法的出栈是指在栈内存中立刻消失
                          3.方法进栈和出栈遵循"先进后出,后进先出"原则

基础5

 1、数组

 含义:存储同一种数据类型多个元素的固定容器       自己的话(是一个固定容器,存储同一类型数据,放多个元素)

特点:1.初始化后长度大小不可变

​         2.只能存储同一类型的数据

​         3.数组长度可以随意定义,但是定义0或1时没有意义

数组的声明含义:就是将数组进行定义

分类:数据类型[] 数组名;(推荐)    通过字面描述:int[] arr

声明存储int类型元素的数组,数组名为arr

​        数据类型 数组名[];

通过字面描述:int arr[]

声明存储int类型元素的变量,变量名为arr数组

解释:数据类型:数组中元素的数据类型[]:数组

​         数据类型[]:数组的数据类型

数组的初始化:

 1. 含义:将数组在内存中进行创建

 2. 分类:

    动态初始化:声明数组时只初始化数组的长度,不初始化数组中具体的存储元素,JVM可以直接获取到数组的长度

    静态初始化:声明数组时不进行数组长度的初始化,只初始化数组中具体的元素,JVM可以间接获取到数组的长度

 3. 格式:

    动态初始化:数据类型[] 数组名 = new 数据类型[数组长度];

    静态初始化:

    标准版(完整版):数据类型[] 数组名 = new 数据类型[]{元素1,元素2,......,元素n};

    简化版:数据类型[] 数组名 = {元素1,元素2,......,元素n};

 4. 注意:

    通过数组静态初始化的简化版创建数组时,JVM会根据数组的数据类型在内存中申请并创建数组,new 数据类型[]由JVM在创建数组时隐式填充  解释:     new:申请并开辟内存空间

数组声明初始化的注意事项:

  1. 数组中的元素支持变量的类型转换,保证内存中是同一种数据类型即可
  2. 数组不可以通过动静结合的方式进行初始化
  3. 数组一旦初始化,其长度不可以改变
  4. 静态初始化的简化版不可以先声明后初始化
  5. 原因:静态初始化简化版直接声明初始化时,是根据数组名前面的数据类型[]在内存中申请并开辟内存空间,new 数据类型[]由JVM隐式
  6. 进行提供;静态初始化简化版如果先声明后初始化,在初始化过程中无法直接获取数组名前面的数据类型[],JVM不会隐式提供new 数据类型[]

 2、获取和使用数组中的元素

  1、索引值:

​        含义:JVM针对数组中元素的动态编号

​        特点: 1.索引值从0开始,依次递增,数组中最大的地址值是其长度-1

​                  2.长度为0的数组没有索引值

​        格式:数组名[索引值]

​        注意:获取数组中元素的时,不能访问不存在的索引或错误索引,否则会发生索引越界异常                       (ArrayIndexOutOfBoundsException) 

   2、数组长度的动态获取:数组名.length

   3、数组的应用:

​         基本应用:不会针对数组中元素的索引位置进行任何改动的应用

​         举例:求和,求最值,......

​         高级应用:针对数组中元素的索引位置进行改变

​         举例:反转,排序

​         综合应用:和之前讲解的方法进行综合使用

​         举例:数组的动态扩容,动态删除,动态插入

 3、数组的动态初始化内存图解

 4、数组静态初始化的内存图解

5、两个数组指向同一地址的内存图解

 6、JVM中的内存划分

1. JDK6.0(包含)以前

   寄存器(程序计数器):存储和计算机硬件(CPU)相关的内容

   本地栈内存:存储和操作系统相关的内容

   本地方法栈:俗称"栈内存",正在运行的方法

   堆内存:存储隐式和显式new出来的东西

   方法区:存储字节码文件对象(类文件Class)

   JDK7.0:将方法区划归堆内存中

   JDK8.0(包含)以后  :  元空间:存储特殊值的空间

2. 栈内存(本地方法栈)的特点

   含义: JVM中存储"正在运行方法"的内存

   特点: 1.方法中的内容会随着方法的进栈而进栈,会随着方法出栈的消失

   ​         2.方法的出栈是指在栈内存中立刻消失

   ​         3.方法进栈和出栈遵循"先进后出,后进先出"原则

3. 方法区的特点:

   含义: 所应用到的字节码文件对象

   包含: 静态区和常量区

   特点: 方法区内部已有的数据,在二次获取时不会创建新的内容,会拿已有数据进行使用

4. 堆内存的特点:

   含义:存储显式或隐式new出来的内容

   特点: 1.堆内存中的每块区域都有独立的地址值

   ​          2.堆内存中 “每块区域中的数据都有默认值”  -》数据都有默认值

   *              整数型         0

   *              浮点型         0.0

   *              字符型         空白字符 '\u0000'

   *              布尔型         false

   *              引用型         null

   3.在堆内存中有一个特殊的对象,该区域存储的是"垃圾回收器"

   作用:垃圾回收器类似于生活中的"扫地机器人",有规则的扫描堆内存,遇到垃圾数据进行回收

   4.堆内存中每块区域在内存中消失的特点

   该区域和其它内存区域没有任何的关联性时,该区域会被JVM标记为"垃圾数据",等待垃圾回收器的回收,垃圾回收器扫描到该区域时进行回收

5. JVM图解

基础6

 1、 数组的反转

1. 含义:将数组中首尾对应的索引位置上的元素进行互换

2. 进行反转的前提条件

   1.首次待互换位置元素的对应索引变量:int i = 0;int j = arr.length - 1;

   2.进行互换后索引移动的规律:i++;j--;

   3.进行互换的条件:i < j;

   4.如何进行两个元素互换?

   int temp = arr[i];

   arr[i] = arr[j];

   arr[j] = temp;

   5.i和j之间的关系

   i + j = arr.length - 1

   j = arr.length - 1 - i

   6.优化i < arr.length - 1 - i

   i + i < arr.length - 1

   2 * i < arr.length - 1

   i  < (arr.length - 1)/2

   i < arr.length/2 - 1/2

   i < arr.length/2

 2、数组的排序

1. 含义:针对数组中元素的某项数值进行升序或降序的排序操作

   数组排序的分类:冒泡排序、插入排序、归并排序、希尔排序、选择排序堆排序、基数排序、快速排序......

2. 冒泡排序:

   原理:获取最大值排序,将最大值依次移动到数组最右侧

   步骤:外层循环确定轮数,内层循环确定比较次数

3. 查找指定元素在数组中出现的第一次索引优化

   二分查找法(折半查找法)

   原理:在没有查找到元素的时候,通过二分查找可以排除一半的数据,从而提高查找效率

   前提:数组必须是有序的

 3、数组的动态操作

动态添加:将指定的元素添加至数组元素末位

动态插入:将指定的元素添加至数组中指定的索引位置处

动态删除:根据指定索引删除指定数组中对应位置上的元素

4、方法进行传参时的特点

基本类型参数传递:进行传递的是基本类型的数据值,形参不影响实参的值

引用类型参数传递:

​      1.进行参数传递的是引用类型的地址值

​      2.形参地址值的改变不会影响实参地址值

​      3.形参地址值不改变,形参地址值中的元素值的改变影响实参地址值中的元素值

 基础7  

1、二维数组

1. 多维数组:除了一维数组外,数组中的元素依然是数组的数组

​        分类:

​                一维数组

​                二维数组(数组中的元素是一维数组)

​                三维数组(数组中的元素是二维数组)

​                 ......

​          二维数组:数组中的元素是一维数组的数组

​          声明:数据类型[][] 数组名;(推荐)

​          数据类型 数组名[][];

​          数据类型[] 数组名[];

​          初始化:

​          动态初始化:

​          格式1:初始化二维数组的同时,也初始化二维数组中每个一维数组

​                    数据类型[][] 数组名 = new 数据类型[x][y];(新建了x+1个数组,其中1个二维数组,x个一维数组)

​                    x:二维数组的长度

​                    y:二维数组中每个一维数组的长度

​          格式2:初始化二维数组的同时,不会初始化二维数组中的一维数组

​                     数据类型[][] 数组名 = new 数据类型[x][];(新建了1个数组,就1个二维数组)

​      静态初始化:

​      格式1:数据类型[][] 数组名 = new 数据类型[][]{new 数据类型[]{元素1,元素2,......,元素n},new 数据类型[]{元素1,元素                 2,......,元素n},......,new 数据类型[]{元素1,元素2,......,元素n}};

​      格式2:数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2,......,元素n},{元素1,元素2,......,元素n},......,{元素1,元素2,......,元素n}};

​       格式3:数据类型[][] 数组名 = {new 数据类型[]{元素1,元素2,......,元素n},new 数据类型[]{元素1,元素2,......,元素n},......,new 数据类型[]{元素1,元素2,......,元素n}};

格式4:数据类型[][] 数组名 = {{元素1,元素2,......,元素n},{元素1,元素2,......,元素n},......,{元素1,元素2,......,元素n}};

2、二维数组中元素的访问和遍历

​      格式:数组名[x][y];

​       x:访问元素所在一维数组在二维数组中的索引值

​       y:访问元素在一维数组中的索引值

​       遍历:嵌套for循环,外层遍历二维数组中的一维数组坐标,内层访问以为数组中元素的变量

 3、面向对象 

1. OOP(Object Oriented Programming)

   面向对象程序设计(核心:设计)

   面向过程思想:    代表:C语言      单位:函数     

   特点:比喻为"执行者"身份,偏重事情"怎么做",强调的是"过程"

   面向对象思想:   代表:Java语言  单位:类文件(.class文件或Class对象)

   特点:比喻"指挥者"身份,偏重事情"找谁做",强调的是"对象"

   面向过程往往解决的是一些较小的问题

   面向对象往往解决的是一些较大的问题

   面向过程和面向对象没有好坏之分,都是人们在生活中解决问题的手段,在不同的情况使用不同的解决方案

   面向对象思想三个阶段:面向对象基础思想(Java基础阶段)

   ​                                       面向接口编程思想(JDBC,web阶段)

   ​                                       面向切面编程思想(Spring框架)

2. 类与对象的关系

   类:针对生活中事物的属性和行为的具体描述

   属性:这件事物的属性信息(基本信息)

   行为:这个事物的行为动作(做的事情)

   对象:针对生活中事物的具体体现

   举例:

   类:人类

   属性:姓名,年龄,身高,体重......

   行为:吃,睡,玩,......

   对象:那个叫"彤彤"的小姐姐

   属性:彤彤,18,170,45

   行为:怎么吃,怎么睡,怎么玩

   关系:类是对象的抽象,模版

   ​        对象是类的实例,实体

3. 类的分类

   类从由来的角度进行分类:自定义的类       Java系统中提供的类

   类从功能的角度进行分类:(现阶段)模版类      测试类

4. 类的设计过程

   1.在类中声明实例变量和方法完成"模版类"的设计

   2.在类中添加基础的封装思想

   3.在类中添加构造器概念

   4.将类中的构造器和封装思想进行标准化,完成"标准类"的设计

   5.在类中添加构造器代码块

   6.在类中添加静态的概念

   7.在类中添加继承思想

   8.在类中添加抽象概念

   9.在类中添加完整的封装思想

   10.在类中添加final概念

   11.在类中添加接口概念

   12.在类中添加内部类概念

   13.了解特殊类(枚举类)的概念

5. 类的成员和内容:

   类的成员:归属于"类"或"对象"的内容

   ​                包含:成员量(类的属性)、成员方法(类的行为)、成员内部类(暂不涉及)

   类的内容:不归属"类"或"对象"的内容

   ​                包含:构造器

    成员量:在程序中,成员变量和成员常量的统称

   ​       成员变量:在程序中声明在类中方法外,且没有final关键字进行修饰的变量

   ​            实例变量:在程序中,声明在类中方法外,且没有static关键字修饰的成员变量,实例变量归属"对象"(对象变量)

   ​            静态变量:在程序中,声明在类中方法外,且含有static关键字修饰的成员变量,静态变量归属"类"(类变量,全局变量)

   ​       成员常量:在程序中声明在类中方法外,且含有final关键字进行修饰的变量(暂不涉及)

   ​          实例常量:在程序中,声明在类中方法外,且没有static关键字修饰的成员常量,实例常量归属"对象"(对象常量)

   ​          静态常量:在程序中,声明在类中方法外,且含有static关键字修饰的成员常量,静态常量归属"类"(类常量,全局常量)

   成员方法:在程序中,声明在类中的方法

   ​        实例方法:在程序中声明在类中且没有static关键字修饰的成员方法,实例方法归属"对象"(对象方法)

   ​        静态方法:在程序中声明在类中且含有static关键字修饰的成员方法,静态方法归属"类"(类方法)

6. 模版类的设计格式:

   public class 类名 {

   实例变量

   实例方法

   }

7. 面向对象基础思想的学习小技巧

   1.查找是否存在可以帮助我们解决问题对象的类

   如果有,第2步

   如果没有,自定义

   2.根据模版类创建对象

   3.根据对象调用方法

8. 对象的创建和使用

   ​    创建格式:

   ​         类名 对象名 = new 类名(实参);

   ​    获取属性格式:

   ​         对象名.实例变量名;

   ​    赋值属性格式:

   ​        对象名.实例变量名 = 初始化值;

   ​    调用实例方法格式:

   ​       对象名.实例方法名(实参);

   ​      System.out.println(对象名.实例方法名(实参));

   ​    数据类型 变量名 = 对象名.实例方法名(实参);

    对象创建和使用的内存图解

9. 实例变量:声明在类中方法外,且没有static关键字修饰的成员变量

   局部变量:声明在方法内部或方法声明上的变量

   实例变量和局部变量的区别:

   代码中的位置不同:    实例变量:类中方法外      局部变量:方法内部或方法声明上

   内存中的位置不同:  实例变量:堆内存    局部变量:栈内存

   默认值不同:实例变量:含有默认值  局部变量:没有默认值

   代码中作用域不同:  实例变量:所属类中(静态成员除外)    局部变量:所属方法中

   内存中生命周期不同:  实例变量:随着对象的创建而加载,随着对象的回收而消失

   ​                                     局部变量:随着方法的调用而加载,随着方法的出栈而消失

   变量的加载方式和次数不同:实例变量:随着对象的创建而加载,每创建一次对象就会加载一次

   ​                                               局部变量:随着方法的调用而加载,每调用一次方法就会加载一次

   修饰符不同:实例变量:可以添加修饰符       局部变量:只能被final关键字修饰

   注:同名变量按照就近原则使用

 4、this关键字第一种用法

场景:(子)类中的实例方法或构造器中

格式:this.实例变量名;

​         this.实例方法名(实参);

作用:用来区分同一个类中同名的实例变量和局部变量

含义:哪个对象调用了this所在的构造器或实例方法,this就代表哪个对象

注意:在类中使用所有的实例变量或调用所有的实例方法,都有隐式的this进行修饰

 5、封装

1. 封装:给程序中的成员或内容根据不同的情况添加不同的权限访问级别

   核心:四种权限访问级别

   好处:针对类中的属性提供数据安全性

2. 权限访问级别(四种)

   分类:权限从小到大的顺序

   private < 缺省(sheng什么都不写) < protected < public

   修饰:成员变量, 成员常量, 类中的成员方法, 接口中默认方法, 接口中的静态方法, 成员内部类, 构造器

   private关键字:私有的

   作用:被private修饰的内容只能在本类中进行访问,在本类之外无法进行访问,否则编译报错

   私有变量:被private修饰的成员变量

   作用:被private修饰的成员变量只能在本类中进行访问,在本类之外无法进行访问,否则编译报错

   格式:private 数据类型 变量名;

   步骤:1.将模版类中所有的成员变量或成员常量进行私有化

   ​         2.针对每个被私有化的成员变量或成员常量对外提供一对的公共访问方式(set和get方法)

   存储数据方法的两个明确:

   ​        返回类型:void

   ​        形参列表:数据的数据类型 变量名

   获取数据方法的两个明确:

   ​        返回类型:数据的数据类型

   ​        形参列表:()中什么都不写

3. 构造器(构造方法):在创建对象时,需要使用构造器针对对象中的成员进行初始化

   格式:修饰符 类名 () {}

   作用:1.进行成员的初始化

   ​         2.如果是有参的构造器可以针对对象成员进行赋值操作

   注意:

   ​        1.构造器的声明格式和使用特点和方法类似,但是有别于方法,构造器也称之为"构造方法"

   ​        2.构造器的名字必须与类名相同,否则编译报错

   ​        3.构造器没有返回类型,而且连void关键字都不能有

   ​        4.当一个类没有任何的构造器的时候,JVM的编译器自动提供一个public无参的构造器,供其创建对象时进行对象成员的初始化;一旦这个类含有任何的构造器时,JVM的编译器不再进行提供

   ​        5.构造器支持方法的重载

   ​        6.接口中没有构造器

   ​        7.构造器中的{}有很多隐式的代码,执行的时候遵循优先级(实例初始化过程)

   ​                  第一优先级:隐式或显式的super(实参),显式的this(实参)

   ​                  第二优先级:实例成员和构造器代码块

   ​                  第三优先级:构造器中除了第一优先级的显式代码

4. 构造代码块:定义在类中,可以用来提取构造器中相同的代码

   格式:{ 所有构造器中相同的代码}

   特点:构造代码块在new对象时都会被调用一次

   ​            构造器代码块中的内容总是优先于构造器中的显示内容执行

5. JavaBean标准类:在实际开发中,没有上级特殊规定要求的情况下,程序员间针对模版类的设计一种约定俗成的规范

   内容:1.程序中所有的类必须使用public进行修饰(一个.java文件中只允许声明一个类)

   ​          2.必须有:

   ​                       (1)所有的成员变量和成员常量必须进行私有化

   ​                       (2)针对每个被私有化的成员变量和成员常量提供一对的公共访问方式

   ​                       (3)无参构造器

   3.可以有:(1)根据实际需求添加有参的构造器

   ​                (2)根据实际需求添加构造器代码块

   ​                (3)根据实际需求添加静态代码块

   ​                (4)根据实际需求添加成员内部类

   ​                (5)根据实际需求添加toString(),equals(),hashCode()

6、修饰符

1. 访问修饰符:private、缺省、protected、public
2. 非访问修饰符:static、final、abstract、synchronized

基础8

 1、匿名对象

1. 匿名对象

   匿名对象:没有名字的对象

   格式:new 类名(实参);

   好处:提高堆内存空间的使用率,降低对象的生命周期

   ​         弊端:匿名对象只能使用唯一的一次

2. 对象数组:元素是对象的数组

3. 类中的私有方法:被private关键字修饰的成员方法

   特点:被private关键字修饰的成员方法只能在本类中进行调用,在本类之外无法进行调用,否则编译报错

   格式:private 修饰符 返回类型 方 法名 () {}

4. 构造器代码块

   位置:类中方法外

   作用:抽取所有构造器中相同的代码,并在构造器显式代码之前执行

   格式:{所有构造器中相同的代码}

   注意:构造器代码块由构造器中的隐式代码进行调用,只有构造器进行实例化时才会调用

5. this关键字的第二种用法(外包)

   场景:(子)类的构造器中

   格式:this(实参);

   作用:调用同一个类中其它构造器

   含义:当构造器无法进行实例初始化过程时,需要通过this(实参)将实例初始化工作外包给其它的构造器完成

   注意:1.this(实参)必须在构造器中的第一行,否则编译报错

   ​         2.在构造器中调用this(实参),该构造器不会进行实例初始化过程

2、static

1. static关键字:静态修饰符,静态的,共享的

   作用:被static关键字修饰的内容不再属于对象,而是归属于类,会被这个类创建的所有对象所共享

   修饰:成员量,成员方法,成员内部类,代码块

2. 静态变量:被static关键字修饰的成员变量

   作用:被static关键字修饰的成员变量,不再归属于对象,而是归属于类,会被这个类创建的所有对象所共享

   格式:修饰符 static 数据类型 变量名;

   调用:对象名.静态变量名;

   ​         类名.静态变量名;(推荐)

3. 三种变量的区别(静态变量,实例变量,局部变量)

   代码中的位置不同:  静态变量:类中方法外   实例变量:类中方法外    局部变量:方法内部或方法声明上

   内存中的位置不同:静态变量:堆内存    实例变量:堆内存   局部变量:栈内存

   默认值不同:静态变量:含有默认值   实例变量:含有默认值   局部变量:没有默认值

   代码中作用域不同:静态变量:所属类中   实例变量:所属类中(静态成员除外)   局部变量:所属方法中

   内存中生命周期不同:静态变量:随着类的加载而加载,随着类的回收而消失

   ​                                    实例变量:随着对象的创建而加载,随着对象的回收而消失

   ​                                    局部变量:随着方法的调用而加载,随着方法的出栈而消失

   变量的加载方式和次数不同:静态变量:随着类的加载而加载,只加载唯一的一次

   ​                                               实例变量:随着对象的创建而加载,每创建一次对象就会加载一次

   ​                                               局部变量:随着方法的调用而加载,每调用一次方法就会加载一次

   修饰符不同:静态变量:可以添加修饰符,但必须含有static关键字修饰

   ​                    实例变量:可以添加修饰符

   ​                    局部变量:只能被final关键字修饰

4. 静态方法:被static关键字修饰的成员方法

   格式:修饰符 static 返回类型 方法名 () {}

   作用:

   ​       1.从代码角度看,被static关键字修饰的成员方法不再属于对象本身,而是归属于类,会被这个类创建所有的对象所共享

   ​        2.在实际开发中,创建某个类的对象,完全是因为要调用这个类中的大量实例方法,该对象始终在堆内存中驻留,导致堆内存的使用率过低,可以将这个类所有的实例方法修饰为static,并且将构造器进行私有化,直接使用类名进行调用

   调用: 1.对象名.静态方法名(实参);

   ​          2.类名.静态方法名(实参);(推荐)

5. 静态方法的注意事项

   1.静态方法随着类的加载而加载,而且只加载唯一的一次

      静态方法加载:静态方法进入静态区

      静态方法调用:静态方法进入栈内存

   2.静态方法可以通过类名和对象名进行调用,推荐使用类名进行调用

   3.在静态方法中不可以使用非静态成员

   4.在静态方法中不可以使用this关键字

6. 静态代码块:被static修饰的代码块

   位置:类中方法外

   格式:static {  }

   目的:1.给静态常量进行赋值初始化

   ​         2.类初始 过程的笔试题

   ​         3.封装工具类提高某个对象加载的优先级

   注意:

   ​         1.静态代码块随着类的加载而加载,而且只加载唯一的一次

   ​         2.在静态代码块中不可以使用非静态成员

   ​         3.在静态方法中不可以使用this关键字

7. 静态成员的内存图

 

8. 设计模式和框架

   设计模式:解决某一类问题专用的解决方案

   框架:半成品项目

   单例设计模式:解决创建唯一实例对象的专用解决方案

   分类:立即加载(饿汉式)

   ​                在类加载的同时进行对象的创建

   ​        延迟加载(懒汉式)

   ​               什么时候使用对象什么时候再进行对象的创建

9. 立即加载模式的步骤(单线程环境中):

   1.将构造器进行私有化

   2.在成员位置上创建唯一对象

   3.为了在外界可以进行唯一对象的访问,通过static进行修饰

   4.为了唯一对象的数据安全性,通过private进行修饰

   5.对外提供公共的获取方式

   立即加载模式的弊端:

   在实际应用中可能加载到唯一对象所对应的类,加载后对象直接在堆内存中进行创建,但是没有马上进行使用,导致内存使用偏低

10. 延迟加载模式(懒汉式,仅适用于单线程环境中)

   1.将构造器进行私有化

   2.在成员位置上声明唯一对象变量;

   3.为了在外界可以进行唯一对象的访问,通过static进行修饰

   4.为了唯一对象的数据安全性,通过private进行修饰

   5.对外提供公共的获取方式并且在第一次获取对象时进行对象的创建

 3、import

1. import关键字导包

   作用:在当前包下可以访问其它包下的类

   位置:package > import > 类文件(class,interface,enum)

   格式:import 包名.*;

   ​        将指定包下所有的类和接口进行导入

   ​        import 包名.类名;(推荐)

   ​        将指定包下指定的类或接口进行导入

2. Java API(应用程序接口)

   Java系统中提供的类文件(class,interface,enum)

   Java API文档:查询Java系统中提供类文件的文件

   注意:查询的API文档必须和技术版本对应

   关注:类的特点    类的位置

   注意:在java.lang的根路径下,直接使用无需导包

   ​         类的构造器

   ​         类的方法

基础9

 1、Scanner类

1. Scanner类

   类的特点:针对基本类型数据和字符串类型数组进行简单扫描的工具类

   类的位置:java.util

   类的构造器:public Scanner(InputStream source)

   ​                       构造一个新的 Scanner,它生成的值是从指定的输入流扫的。

   实参:System.in

   类的方法:public void close()

   ​                         关闭此扫描器。

   ​                   public byte nextXxx()

   ​                        将输入信息的下一个标记扫描为一个 xxx基本类型的数据。

   public String next()

   查找并返回来自此扫描器的下一个完整标记

   public String nextLine()

   此扫描器执行当前行,并返回跳过的输入信息。

2. Scanner类的注意事项:

   1.Scanner类没有提供关于扫描char类型数据的方法

   2.Scanner类扫描键盘录入的数据时,录入的数据必须在其扫描的数据类型取值范围内,否则运行报错(InputMismatchException)

   3.Scanner类的next()和扫描基本类型数据的方法遇到"空白符号"停止扫描

   4.Scanner类的next()和扫描基本类型数据的方法遇到"回车换行"不会扫描

   5.使用Scanner类的nextLine()时,需要保证整个方法调用之前,不能使用next()和扫描基本类型数据的方法

3. next()和nextLine()的区别

   nextLine可以识别空白字符和换行,next不能够识别

 2、Math类

1. Math类的特点:针对数学运算操作的工具类

   类的位置:java.lang

   类的构造器

   构造器私有化

   类的方法

   public static double random()

   返回带正号的 double 值,该值大于等于 0.0 且小于 1.0。

   获取指定范围内数字的小技巧

   (int)(Math.random() * a + b)

   a:指定范围内所有数据的个数

   b:指定范围内起始数字

3、BigXxx类

1. BigInteger类

   类的特点:不可变的任意精度的整数。如果在实际开发中使用到超出long的取值范围时,可以使用BigInteger

   类的位置:java.math

   类的构造器

   public BigInteger(String val)

   将 BigInteger 的十进制字符串表示形式转换为 BigInteger。

2. BigDecimal类

   类的特点:不可变的、任意精度的有符号十进制数。

   类的位置:java.math

   类的构造器

   public BigDecimal(String val)

   将 BigDecimal 的字符串表示形式转换为 BigDecimal。

 4、Arrays类

1. 类的特点:针对数字进行操作的工具类

2. 类的位置:java.util

3. 类的构造器:构造器私有化

4. 类的方法:

   public static String toString(int[] a)

   ​    返回指定数组内容的字符串表示形式。

   public static int binarySearch(int[] a,int key)

   ​    使用二分搜索法来搜索指定的 int 型数组,以获得指定的值。

   public static int[] copyOf(int[] original,int newLength)

      复制指定的数组,截取或用 0 填充(如有必要),以使副本具有指定的长度。

   public static void sort(int[] a)

      对指定的 int 型数组按数字升序进行排序。

   public static <T> void sort(T[] a,Comparator<? super T> c)

      根据指定比较器产生的顺序对指定对象数组进行排序。

   Arrays.sort()的排序规则:

      如果是基本类型数组(boolean数组除外):针对元素数据大小进行升序排序

      如果是字符串类型数组:针对元素字符对应的Unicode码表进行升序排序

      如果是自定义类型数组:必须手动进行比较器的定义

   ​          自然顺序比较器:实现Comparable<T>

   ​          定制顺序比较器:实现Comparator<? super T>

 5、System类

1. 类的特点:针对常用属性和方法进行封装的工具类

2. 类的位置:java.lang

3. 类的构造器:构造器私有化

4. 类的方法:

   public static long currentTimeMillis()

   ​     返回以毫秒为单位的当前时间。

   public static long nanoTime()

   ​     返回最准确的可用系统计时器的当前值,以毫微秒为单位。

基础10

 1.继承

1. 继承:就是子类继承父类的属性和行为,使得子类对象具有与父类相同的属性、相同的行为

   好处:1.提高代码的复用性,从而提高开发效率

   ​         2.提高程序的扩展性

   ​         3.学习继承关系是学习"实现关系"的前提条件

   ​         4.学习继承关系是学习"多态"的前提条件之一

   ​         5.学习继承关系是学习"匿名内部类"的前提条件之一

   注意:私有构造器的类没有子类,因为子类构造器中的super()无法访问父类构造器

2. 继承的格式:

   public class 父类类名 {}

   public class 子类类名 extends 父类类名{}

3. 继承关系中成员的特点

   1. 自己总结:子类可以继承父类的私有成员,但受限于private关键字的特点无法直接使用,如需访问可以通过公共访问方式进行获取和存储

   2. 子类可以继承父类的静态成员  (静态常量   静态变量  静态方法)

   3. 子类可以继承父类的实例成员  (实例常量  实例变量  实例方法)

   4. 子类可以继承父类的实例成员内部类和静态成员内部类

   5. super关键字的第一种用法:

      场景:子类的实例方法中或子类的构造器中

      格式:super.实例变量名;

      ​         super.实例方法名(实参);

      作用:区分子父类继承关系中同名实例变量和同名并同参的实例方法

4. 继承关系中构造器的特点:

   ​       1.子类无法继承父类的构造器

   ​       2.初始化子类成员之前,先初始化父类成员

   ​       3.当构造器中没有任何的this(实参)或super(实参),JVM的编译器自动给其提供一个无参的super(),供其初始化子类成员之前,先初始化父类成员;一旦构造器有this(实参)或super(实参),JVM的编译器不再进行提供

5. 继承的注意事项:

   ​        1.类与类之间只支持单继承,不支持多继承, 但是支持多层继承

   ​        2.继承关系中的子类和父类是一对相对的概念,不区分"辈分",只区分"直接"和"间接"

   ​        3.继承关系中,子类只能拥有一个直接父类,但父类可以拥有多个直接子类

   ​        4.所有的类都有一个最顶级的父类Object类

   ​              当一个类没有任何extends关键字时,JVM让其默认继承Object类(枚举类除外)

 2、方法的重写

1. 含义:在子父类继承关系中(或实现关系中),出现了方法名相同,形参列表相同, 权限访问级别和返回类型遵

   ​        循相关规则的现象

   场景:1.上级布置功能需求时,会提供没有方法实体的方法(将两个明确准备好),需要自己完成过程代码的编写

   ​         2.二次开发

2. 方法重写的前提条件:

   1.必须有子父类继承关系或实现关系

   2.子类重写方法的方法名和形参列表必须和父类的相同

   3.子类重写方法的权限访问级别必须大于或等于比父类方法的权限访问级别,且遵循权限访问级别的修饰范围

   4.子类重写方法的返回类型在内存中必须和父类方法的返回类型相同

3. 方法重写的注意事项

​        1.方法重写的注解:用于检测是否满足方法重写的语法规则,如果不满足,编译报错

​          位置:子类重写方法声明上

​          格式:@Override

​                   修饰符 返回类型 子类重写方法名 () {}

​       2.父类中的私有方法不能被子类进行重写

​       3.父类和子类不在同一个包下,父类的缺省方法不可以被子类进行重写

​       4.父类中的静态方法不能被子类进行重写,但子类的静态方法代码必须遵循方法重写的语法格式(继承关系中)

​       5.父类的最终方法不能被子类进行重写

​       6.父类的抽象方法必须被子类进行重写

​       7.子类重写方法的返回类型在代码中:

​             当父类被重写方法的返回类型是void时,必须和父类被重写方法的返回类型相同;

​             当父类被重写方法的返回类型是基本类型时,必须和父类被重写方法的返回类型相同;

​             当父类被重写方法的返回类型是引用类型时,必须和父类被重写方法的返回类型相同或者是该返回类型的

​             子类类型(其实就是后面即将讲解"多态")

 3、super的第二中用法

​      场景:子类的构造器

​      格式:super(实参);

​      作用:根据实参调用父类中的对应的构造器

​      含义:在初始化子类对象成员之前,通过super(实参)调用父类中对应的构造器完成父类成员的初始化

​      this关键字和super关键字的注意事项:

​            1.在代码中,this关键字可以进行打印,super关键字不可以进行打印

​            2.this(实参)和super(实参)必须在构造器中的第一行,否则编译报错

​            3.this(实参)和super(实参)不可以在同一个构造器使用

​            4.在静态方法和静态代码块中不可以使用this关键字或super关键字

4、Object类

1. 类的特点

   1.Object类是类层次的顶级父类

   2.所有的对象或数组都可以调用Object类中的方法

   3.所有的接口都继承Object类抽象形式(暂不涉及)

   ​       类的位置:java.lang

   ​       类的构造器:public Object()

   ​       类的方法:

   ​               public boolean equals(Object obj):指示其他某个对象是否与此对象“相等”。

   ​               public String toString():返回该对象的字符串表示。

2. eqauls()和运算符==的区别

   ​            1. ==既可以比较基本类型数据,也可以比较引用类型数据

   ​                    当==比较基本类型数据时,比较的是基本类型数据值是否相等

   ​                    当==比较引用类型数据时,比较的是引用类型地址值是否相等

   ​             2. eqauls()只可以比较引用类型数据

   ​                    eqauls()比较的是引用类型地址值是否相等

   ​                    如果比较类型重写了Object类的eqauls(),需要按照重写后的规则进行比较 

3. toString()方法的注意事项: 

​             使用输出语句打印对象名的时候,其实就是打印该对象的toString()的返回内容,char类型数组除外

5、权限访问级别

1. 四种权限访问级别修饰范围从小到大的关系:

   private < 缺省 < protected < public

2. private权限访问级别(私有的)作用范围: 本类内,被private修饰的内容在本类中有效,在本类之外无法进行访问

3. 缺省权限访问级别(什么都不写)

   作用范围:  1.兼容private权限访问级别的作用范围

   ​                   2.在同一个包下有效,缺省的内容在同一个包下有效,超出同一个包无法进行访问

4. protected权限访问级别(受保护的)

   作用范围:

   1.兼容缺省权限访问级别的作用范围

   2.如果是三级结构(项目,包,类文件),在同一个项目中并且跨包情况下具有子父类继承关系有效,跨包且没有继承关系时无法进行访问

   如果是四级结构(项目,模块,包,类文件),在同一个模块中,具有子父类继承关系有效,跨包且没有继承关系时无法进行访问,如果在同一项目不在同一个模块下,需要手动修改项目的配置文件后,具有子父类继承关系被protected修饰的内容有效

5. public权限访问级别(公共的)

   作用范围:

   1.兼容protected权限访问级别的作用范围

   2.如果是三级结构(项目,包,类文件),在同一个项目中有效,跨项目无法进行访问

   如果是四级结构(项目,模块,包,类文件),在同一个模块中有效,在同一个项目中不同模块,需要手动修改项目的配置文件后有效,跨项目无法进行访问

6. 封装思想的核心就是将不同的内容添加不同权限访问级别

7. 思考:如果存在多个项目,某些数据需要跨项目进行访问,怎么办?

   序列化和反序列化(第一种序列化和反序列化:对象流)


6、权限访问级别补充

1. 类文件(class,interface,enum):  只能public和缺省,推荐public

2. class中的成员量(成员变量和成员常量):  四种都可以,推荐private

3. class中的成员方法:  四种都可以,推荐public,private,protected

4. class中的成员内部类:  四种都可以,推荐缺省,private

5. class中的构造器:  四种都可以,public,private,protected

6. class中的构造器代码块和静态代码块  :只能缺省

7. 代码块中的局部成员:  只能缺省

8. interface中静态常量  抽象方法  默认方法  静态方法  内部接口:

   ​        只能public,即使没有不写public,JVM的编译器自动填充public

9. interface中私有方法:  只能private

10. enum中的枚举对象:  只能隐式修饰为public,如果显式修饰为public,编译报错

11. enum的成员量(成员变量和成员常量,除枚举对象):  四种都可以,推荐private

12. enum中的成员方法:  四种都可以,推荐public,private,protected

13. enum中的成员内部类:  四种都可以,推荐缺省,private

14. enum中的构造器:  只能private,即使没有不写private,JVM的编译器自动填充private

15. enum中的构造器代码块和静态代码块:  只能缺省


7、抽象类

1. 继承关系中的BUG:

   1.父类存储多个子类相同的属性和相同的行为,希望这个父类不可以被实例化对象,实际上这个父类可以被实例化对象;

   2.父类的实例方法需要子类们进行重写,但是最终执行肯定是子类的重写后方法,父类被重写方法的方法体就不是很重要了,希望在开发中不编写父类被重写方法的方法体,实际上如果父类被重写方法的方法体省略不写的话编译报错;

   3.父类的实例方法需要子类们进行重写,希望在忘记重写时,开发环境编译报错进行提示,实际上什么提示都没有

   抽象的出现就是为了解决继承关系中上述的3个BUG

2. abstract关键字:抽象的

   修饰:类==>抽象类       方法==>抽象方法

   抽象类:被abstract关键字修饰的"父类",抽象类也被称之"加强版父类"

   格式:public abstract class 父类类名 {}

   注意:1.抽象类不可以实例化对象

   ​         2.抽象类中可以含有构造器,构造器的作用是用来创建子类对象时先初始化父类成员的

3. 抽象方法:被abstract关键字修饰,且没有方法体的实例方法

   格式:

   修饰符 abstract 返回类型 方法名 ();

   注意:1.抽象类中可以没有抽象方法,但抽象方法所在的类必须是抽象类

   ​         2.抽象类的子类必须重写抽象类中所有的抽象方法,否则编译报错,除非该子类也是抽象类

基础11

1、final关键字

1. final关键字:最终的,不可改变的

   修饰:类,方法,变量

   特点:被final修饰的类就是最终类(不可改变类),不可以被继承

   ​         被final修饰的方法就是最终方法(不可改变方法),不可以被重写

   ​          被final修饰的变量就是最终量(不可改变量,其实就是自定义常量),不可以被重新赋值

2. 最终类:被final修饰的类

   特点:被final修饰的类不可以被继承

   格式:修饰符 final class 类名 {}

   注意:abstract关键字和final关键字不可以同时修饰一个类

3. 最终方法:被final关键字修饰的方法

   特点:被final关键字修饰的方法,不可以被重写

   格式:修饰符 final 返回类型 方法名 () {}

   注意:abstract关键字和final关键字不可以同时修饰一个方法

4. 自定义常量:被final修饰的变量

   特点:1.被final修饰的变量,不可以被重新赋值

   ​         2.直接声明初始化的自定义常量会被JVM识别为"字面值常量"

   分类:局部常量、实例常量、静态常量

   格式:

   ​    直接声明初始化:修饰符 final 数据类型 常量名 = 初始化值;  (会被JVM识别为"字面值常量")

   ​    先声明后初始化:修饰符 final 数据类型 常量名;

   ​    常量名 = 初始化值;

   ​    常量名的命名规范:  一个单词:单词全部大写

   ​                                     多个单词:所有单词全部大写,且每个单词间使用_进行连接

5. 局部常量:被final修饰的局部变量

   注意:局部常量的权限访问级别只能是"缺省"

6. 实例常量:被final修饰的实例变量

   注意:1.堆内存在识别实例变量被final修饰后,不会给其进行默认值赋值操作

   ​         2.实例常量如果进行先声明后初始化操作,需要在实例常量所在类的所有构造器中给其进行赋值操作如果

   ​            所有的构造器中初始化赋值的数据相同,直接在构造器代码块中进行简化操作如果所有的构造器中初

   ​            始化赋值的数据不同,只能在各自构造器中进行赋值操作

7. 静态常量:被final修饰的静态变量

   注意:1.堆内存在识别静态变量被final修饰后,不会给其进行默认值赋值操作

   ​         2.静态常量如果进行先声明后初始化操作,需要在静态常量所在类的静态代码块中给其进行赋值操作

2、接口interface

1. 接口interface:规定了一组数据和行为的标准

   好处:1.提高程序的扩展性

   ​         2.提高程序的复用性,从而提高开发效率

   ​         3.学习接口是学习多态的前提条件之一

   ​         4.学习接口是学习匿名内部类的前提条件之一

   格式:

   public interface 接口名 {静态常量   抽象方法   默认方法   静态方法   私有方法   内部接口(暂不涉及)   }

   实现格式:

   格式1:有继承,也有实现

   ​    public class 实现类名 extends 父类类名 implements 接口名1,接口名2,......,接口名n {}

   格式2:无继承,有实现

   ​    public class 实现类名 implements 接口名1,接口名2,......,接口名n {}

   使用步骤:

   ​    1.创建接口的实现类

   ​    2.在实现类中重写接口中的抽象方法

   ​    3.在测试类中创建实现类的对象

   ​    4.通过实现类对象调用方法完成需求

2. 接口的注意事项:

   1.接口不可以实例化对象,因为接口中没有构造器

   2.使用接口需要进行接口的实现,并且可以进行"多实现"

   3.程序中类文件的关系:

   ​    class和class之间的关系:单继承

   ​    class和interface之间的关系:多实现

   ​    interface和interface之间的关系:多继承

   ​          格式:public interface 接口名 extends 父接口名1,父接口名2,......,父接口名n {}

   4.与继承基本相似, 接口中的成员只能有6种,除此之外无其它成员

3. 接口中的静态常量:声明在接口中的静态常量(可以被实现类继承)

   格式:public static final 数据类型 常量名 = 初始化值;

   调用:接口名(实现类名).常量名;

   注意:1.接口中的静态常量只能直接声明初始化,无法进行先声明后初始化

   ​         2.public,static,fianl这三个关键字缺少任何一个,JVM的编译器在编译时都会自动补全

   ​         3.接口中静态常量可以被实现类所继承

   ​         4.子类的父类和父接口中出现同名常量时,会有歧义,产生编译报错

4. 接口中的抽象方法:声明接口中的抽象方法(必须被实现类实现)

   格式:public abstract 返回类型 方法名 ();

   注意:public,abstract这两个关键字可以省略不写,缺少任何一个JVM的编译器在编译时都会自动补全

5. 接口中的默认方法(JDK8.0)声明在接口中的实例方法,接口无法实例化对象,需要将类中实例方法修改为默认方法格式(可以被实现类继承)

   格式:public default 返回类型 方法名 () {}

   注意:public关键字可以省略不写,JVM的编译器在编译时都会自动补全

   场景:1.源码    2.面试题

   默认方法的注意事项:

   1.当子类继承父类,也实现父接口,父类中实例方法和父接口中的默认方法同名,当子类调用该方法时,如果子类重     

      写该方法时,执行子类重写后的该方法;如果子类没有重写该方法,执行父类的实例方法;

   2.当子类不继承父类,但实现多个父接口,多个父接口中存在同名的默认方法,子类必须以实例方法重写该同名的

   ​    默认方法

6. super关键字的第三种用法:

   ​     场景:实现类的实例方法中

   ​     格式:父接口名.super.默认方法名(实参);

   ​     作用:调用指定父接口的默认方法

   ​     含义:哪个对象调用的super的实例方法,super就代表哪个对象的指定父接口引用

7. 接口中的静态方法(JDK8.0):声明在接口中的静态方法(不能被实现类继承)

   格式:public static 返回类型 方法名 () {}

   场景:源码

   调用:接口名.静态方法名(实参);

   注意:1.public关键字可以省略不写,JVM的编译器在编译时都会自动补全

   ​         2.继承和实现的区别:

   ​                (1)关系中的类文件不同

   ​                         继承关系:class与class之间的单继承

   ​                                         interface和interface之间的多继承

   ​                         实现关系: class和interface之间的多实现

   ​                (2)静态方法的继承性不同

   ​                        继承关系:子类可以继承父类的静态方法

   ​                        实现关系:实现类不可以继承父接口的静态方法

8. 接口中的私有方法(JDK9.0):声明在接口中的私有方法

   格式:针对默认方法处理的私有方法格式:

   ​         private 返回类型 方法名 () {}

   ​         针对静态方法处理的私有方法格式:

   ​         private static 返回类型 方法名 () {}

3、多态:事物(对象)的多种形态

1. 生活中的多态:

   对象:Tom猫(数据类型:猫)

   ​      多态:那只喵星人(数据类型:喵星人),那只小可爱(数据类型:小可爱),那只小动物(数据类型:动物)

   程序中的多态:

   ​      对象在程序编译和运行的过程中有两种数据类型,分别为编译时类型和运行时类型

2. 单态:对象在编译时类型和运行时类型一致: 举例:Student s = new Student();

   多态:对象在编译时类型和运行时类型类型不一致: Animal a = new Cat();

   多态的前提条件

   ​    1.必须要有继承关系或实现关系

   ​    2.必须要有方法的重写(没有方法重写也可以从格式的角度构成多态,但是这样的多态没有任何实际意义)

   ​    3.如果是继承关系:

   ​        父类的引用指向子类对象: 父类类名 对象名 = new 子类类名(实参);

   ​        父接口的引用指向实现类对象: 父接口名 对象名 = new 实现类名(实参);

   ​        特殊情况下的多态(笔试题):this关键字的第三种用法

3. 多态关系下的构造器特点:   构造器的执行和多态没有任何关系

4. 多态关系中实例变量的特点:   

   ​        实例变量的执行和多态没有任何关系(变量的执行结果不是取决于初始化值的数据类型,而是取决于声明变量的数据类型)

5. 多态关系下实例方法的特点:

   ​     多态关系下对象调用实例方法,先进行虚调用父类或父接口的被重写方法,如果父类或父接口存在该方法,实调用子类或实现类重写后的方法;如果父类或父接口不存在该方法,编译报错;

   ​    实调用:平时调用方法,调用的是静态方法或实例方法

   ​    虚调用:调用方法,不会执行方法实体,而是判断所调用方法在代码中是否存在

6. 多态的好处

   ​    声明方法时,如果需要声明多个引用类型作为形参的重载方法,且多个引用类型存在相同的父类或父接口,直接声明一个方法即可,形参类型就是多个引用类型的父类或父接口,从而提高程序的复用性和开发效率

7. 多态的弊端:  多态形式的对象无法调用子类或实现类的特有方法

8. 引用类型转换

   前提:具有子父类继承关系或实现关系的类之间的转换

   分类:   向上转型:将子类类型的对象转换成父类类型(多态)

   ​            向下转型:将父类类型的对象转换成子类类型

   格式:子类类型 对象名 = (子类类型)父类类型的对象名;

   注意:进行向下转型的时候,可能会发生类型转换异常(ClassCastException)

9. instanceof关键字:包含

   作用:判断指定的对象在内存中的本质是否为指定类型或指定类型的子类类型,如果是返回true,如果不是返回false

   格式:对象名 instanceof 数据类型

 基础12

 1、内部类

1. 内部类(嵌套类):在类中声明另外的一个类

   分类(根据类文件不同):内部类

   成员内部类

   ​      实例成员内部类(实例内部类)、静态成员内部类(静态内部类)

   局部内部类

   ​      标准局部内部类(局部内部类)、匿名局部内部类(匿名内部类):内部枚举类、内部接口

2. 成员内部类的学习目的:需求:某个类只想本类中进行访问或者本包内可以访问,不想被外界所访问,可以将这个类声明到某个类的成员中

3. 实例成员内部类(实例内部类)

   学习目的:某个类只想本类中进行访问或者本包内可以访问,不想被外界所访问,且该类的所有成员都是非静态的,可以将这个类以实例成员内部类的形式声明到某个类的成员中

   权限访问级别:四种都可以,推荐private,缺省

   格式:public class 外部类类名 {

   ​               修饰符 class 内部类类名 {

   ​            }   }

   注意事项

   1.内部类对象创建的方式:

   ​     如果内部类的权限访问级别是"缺省",且在外部类之外进行对象创建:

   ​          外部类类名 外部类对象名 = new 外部类类名();

   ​          外部类类名.内部类类名 内部类对象名 = 外部类对象名.new 内部类类名();

   ​     后续不用使用外部类对象方式:

   ​             外部类类名.内部类类名 内部类对象名 = new 外部类类名().new 内部类类名();  

   ​     如果内部类的权限访问级别是"私有",且在外部类内部进行对象创建:

   ​             内部类类名 内部类对象名 = new 内部类类名(实参);

   2.在实例成员内部类不能声明静态成员,如果含有静态成员,需要声明静态成员内部类

   3.在外部类的实例成员中可以通过内部类对象访问内部类中的私有成员

   4.如果在内部类中访问同名的外部类实例变量,需要使用外部类类名.this.实例变量名;

4. this关键字的第四种用法:

   场景:成员内部类的实例方法或成员内部类的构造器中

   格式:外部类类名.this.实例变量名;

   ​         外部类类名.this.实例方法名(实参);

   作用:用来区分外部类实例变量和内部类实例变量或局部变量同名的情况

   ​         用来区分外部类实例方法和内部类实例方法同名的情况

   含义:哪个对象调用了含有"外部类类名.this"的实例方法或构造器,"外部类类名.this"就代表哪个内部类对象的外部类对象

   super关键字的第四种用法:

   场景:成员内部类的实例方法或成员内部类的构造器中

   格式:外部类类名.super.实例变量名;

   ​         外部类类名.super.实例方法名(实参);

   作用:用来区分外部类父类实例变量和内部类实例变量或局部变量同名的情况

   ​         用来区分外部类父类实例方法和内部类实例方法同名的情况

   含义:哪个对象调用了含有"外部类类名.super"的实例方法或构造器,"外部类类名.super"就代表哪个内部类对象的外部类对象的父类引用

5. 静态成员内部类(静态内部类)

   学习目的:某个类只想本类中进行访问或者本包内可以访问,不想被外界所访问,且该类含有静态成员或想提高该类的加载时机,可以将这个类

   以静态成员内部类的形式声明到某个类的成员中

   权限访问级别:四种都可以,推荐private,缺省

   格式:public class 外部类类名 {

   ​                   修饰符 static class 内部类类名 {}

   ​             }

   注意事项

   ​    1.如果想访问静态成员内部类中的静态成员

   ​        如果在该静态成员内部类的外部类的外界进行访问:

   ​               外部类类名.内部类类名.静态变量名;

   ​               外部类类名.内部类类名.静态变量方法(实参);

   ​        如果在该静态成员内部类的外部类的内部进行访问:

   ​                内部类类名.静态变量名;

   ​                内部类类名.静态变量方法(实参);

   ​     2.静态成员内部类中既可以有静态成员,也可以有实例成员,但是如果在外界访问内部类中的实例成员,还需要创建该内部类的对象

   ​     3.在外部类的成员中可以访问内部类的私有静态成员

6. 标准局部内部类(局部内部类)

   学习目的:1.为"匿名内部类"进行铺垫

   ​                 2.笔试题

   权限访问级别:只能缺省

   格式:public class 外部类类名 {

   ​               修饰符 返回类型 方法名 () {

   ​                   修饰符 class 内部类类名 {

   ​                          }  }  }

   注意事项:

   ​    1.局部内部类不能被static关键字进行修饰

   ​    2.局部内部类在所属方法的外界不能被实例化,只能在所属方法中进行内部类对象的实例化操作

   ​    3.局部内部类对象的实例化操作必须在局部内部类声明的后面,否则编译报错

   ​    4.局部内部类所属方法的外部类局部变量和该局部内部类中的实例变量或局部变量发生同名的时候,在该局部内部类中无法进行访问

   ​    5.局部内部类所属方法的外部类局部变量如果进行重新赋值,则无法在该局部内部类中进行使用

   ​    6.局部内部类所属方法的外部类局部变量如果在局部内部类中进行使用,JVM的编译器会自动将其隐式修饰为final(常量)

   原因:变量的赋值必须取决于该变量的数据类型

7. 匿名局部内部类(匿名内部类)

   学习目的:1.简化接口的使用步骤

   ​                2.学习Lambda表达式的前提条件

   权限访问级别:只能缺省

   1.是内部类的简化写法,他的本质是一个"带具体实现的","父类或者父接口的","匿名的","子类对象".开发中,最常用到的内部类就是匿名内部类,以接口为例,当我们使用一个接口时,写如下几步:
    a.创建实现类
     b.实现接口
    c.重写抽象方法
     d.创建实现类或者子类对象,调用重写的方法
   2.匿名内部类:没有名字的实现类或者子类
   3.作用: 可以用一种格式,将上面的四步,四合一  
   4.匿名内部类格式:
     new 接口/抽象类(){
       重写方法
     }.重写的方法();
     或者
     接口名/抽象类名 对象名 = new 接口/抽象类(){
       重写方法
     }
     对象名.重写的方法()
   5.注意:匿名内部类看上去new的是接口或者抽象类,实际上代表的是实现类对象或者子类对象

   补充:类名为什么不能以数字开头?
   因为匿名内部类的地址以数字为序号进行了使用,如果以数字开头时,会混淆。

2、枚举

1. 枚举含义:针对创建固定数量对象的简化方式

2. 枚举类的格式:

   public enum 枚举类类名 {

   对象名1(实参),对象名2(实参),......,对象名n(实参);

   }

3. 枚举类的注意事项:

   1.枚举类无法通过new进行实例化对象的创建,否则编译报错

   2.当枚举类没有任何构造器的时候,JVM的编译器会提供一个private的无参构造器供其使用,当枚举类含有任何的构造器时,JVM的编译器则不会提供

   3.枚举类的构造器只能使用private进行修饰,如果没有private关键字,也不是"缺省",JVM的编译器会自动补全

   4.枚举类的构造器中无法使用super(实参)

   5.枚举类中枚举对象如果使用无参构造器进行对象的初始化,枚举对象名后面的()可以省略不写

   6.枚举类中的枚举对象必须编写在枚举类的第一行,否则编译报错;

   7.枚举类中的枚举对象隐式被public static final关键字进行修饰,如果显式修饰编译报错

   8.所有的枚举类都隐式继承Enum类,所以不能再继承其他类

   9.所有的枚举类不可以被其它的类进行继承

   10.所有的枚举类可以实现多个接口

3、初始化

1. 初始化:程序中内容加载到"堆内存"

   分类:实例初始化过程    类初始化过程

2. 无继承关系的实例初始化过程

   1.实例成员和构造器代码块,谁在前,优先加载谁

   2.构造器中的显式代码

3. 有继承关系的实例初始化过程

   1.显式或隐式的super(实参),显式的this(实参)

   2.实例成员和构造器代码块,谁在前,优先加载谁

   3.构造器中除了super(实参)或this(实参)的显式代码

   注意事项:构造器中一旦含有this(实参),该构造器不会进行实例初始化过程

4. this关键字的第三种用法:

   场景:父类的实例方法中或父类的构造器中

   格式:this.实例变量名;

   ​        this.实例方法名(实参);

   作用:使用多态形式的对象调用实例变量或实例方法

   含义:哪个对象调用了this关键字所在的构造器或实例方法,this关键字就代表所在类型(this关键字所在的类名)的哪个多态形式对象

5. 无继承关系的类初始化过程

   静态成员和静态代码块谁在前优先加载谁

   注意事项:静态成员随着的类的加载而加载,而且只加载唯一的一次

6. 有继承关系的类初始化过程

   静态成员和静态代码快先加载父类的,在加载子类的

   注意事项:静态成员随着的类的加载而加载,而且只加载唯一的一次

 4、this、super用法总结                   

1. this

   1. this关键字第一种用法

      场景:(子)类中的实例方法或构造器中

      格式:this.实例变量名;

      ​         this.实例方法名(实参);

      作用:用来区分同一个类中同名的实例变量和局部变量

      含义:哪个对象调用了this所在的构造器或实例方法,this就代表哪个对象

      注意:在类中使用所有的实例变量或调用所有的实例方法,都有隐式的this进行修饰

   2. this关键字的第二种用法(外包)

      场景:(子)类的构造器中

      格式:this(实参);

      作用:调用同一个类中其它构造器

      含义:当构造器无法进行实例初始化过程时,需要通过this(实参)将实例初始化工作外包给其它的构造器完成

      注意:1.this(实参)必须在构造器中的第一行,否则编译报错

      ​         2.在构造器中调用this(实参),该构造器不会进行实例初始化过程

   3. this关键字的第三种用法:

      场景:父类的实例方法中或父类的构造器中

      格式:this.实例变量名;

      ​         this.实例方法名(实参)

      作用:使用多态形式的对象调用实例变量或实例方法

      含义:哪个对象调用了this关键字所在的构造器或实例方法,this关键字就代表所在类型(this关键字所在的类名)的哪个多态形式对象

   4. this关键字的第四种用法:

      场景:成员内部类的实例方法或成员内部类的构造器中

      格式:外部类类名.this.实例变量名;

      ​         外部类类名.this.实例方法名(实参);

      作用:用来区分外部类实例变量和内部类实例变量或局部变量同名的情况

      ​        用来区分外部类实例方法和内部类实例方法同名的情况

      含义:哪个对象调用了含有"外部类类名.this"的实例方法或构造器,"外部类类名.this"就代表哪个内部类对象的外部类对象

2.super

1. super关键字的第一种用法:

   场景:子类的实例方法中或子类的构造器中

   格式:super.实例变量名;

   ​         super.实例方法名(实参);

   作用:区分子父类继承关系中同名实例变量和同名并同参的实例方法

2. super的第二中用法

   场景:子类的构造器

   格式:super(实参);

   作用:根据实参调用父类中的对应的构造器

   含义:在初始化子类对象成员之前,通过super(实参)调用父类中对应的构造器完成父类成员的初始化

   this关键字和super关键字的注意事项:

     1.在代码中,this关键字可以进行打印,super关键字不可以进行打印

     2.this(实参)和super(实参)必须在构造器中的第一行,否则编译报错

     3.this(实参)和super(实参)不可以在同一个构造器使用

     4.在静态方法和静态代码块中不可以使用this关键字或super关键字

3. super关键字的第三种用法:

   场景:实现类的实例方法中

   格式:父接口名.super.默认方法名(实参);

   作用:调用指定父接口的默认方法

   含义:哪个对象调用的super的实例方法,super就代表哪个对象的指定父接口引用

4. super关键字的第四种用法:

   场景:成员内部类的实例方法或成员内部类的构造器中

   格式:外部类类名.super.实例变量名;

   ​         外部类类名.super.实例方法名(实参);

   作用:用来区分外部类父类实例变量和内部类实例变量或局部变量同名的情况

   ​        用来区分外部类父类实例方法和内部类实例方法同名的情况

   含义:哪个对象调用了含有"外部类类名.super"的实例方法或构造器,"外部类类名.super"就代表哪个内部类对象的外部类对象的父类引用

基础13

1、包装类

1. 包装类:Java中针对8种基本类型提供对应的引用数据类型

   分类:

   ​    整数型:Byte(byte),Short(short),Integer(int),Long(long)

   ​    浮点型:Float(float),Double(double)

   ​    布尔型:Boolean(boolean)

   ​    字符型:Character(char)

   学习目的:1.基本类型数据和包装类型数据的转换

   ​                2.基本类型数据和字符串数据的转换

   ​                3.笔试题

2. 拆箱和装箱:

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

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

   装箱的方式:1.包装类型的构造器

   ​                    2.包装类型的静态方法valueOf(基本类型数据)

   ​                    3.自动装箱(JDK5.0)推荐:由JVM隐式调用valueOf()完成装箱的过程

   拆箱的方式:1.包装类型的实例方法xxxValue()  备注:xxx为对应实例的基本类型单词

   ​                    2.自动拆箱(JDK5.0)(推荐)由JVM隐式调用xxxValue()完成拆箱的过程

3. 基本类型数据和字符串类型数据的转换

   将基本类型数据转换成字符串类型数据的方式:

   ​    1.字符串连接符

   ​    2.先进行装箱,在调用包装类型的实例方法toString()

   ​    3.包装类型的静态方法toString(基本类型数据)

   ​    4.String类的静态方法valueOf(基本类型数据)(推荐)

   将字符串类型数据转换成基本类型数据的方式:

   ​    1.包装类型的构造器,再进行拆箱

   ​    2.包装类型的静态方法valueOf(字符串类型数据)

   ​    3.包装类型的静态方法parseXxx(字符串数据)(推荐)

   备注:Xxx为对应实例的基本类型单词

   注意事项:

   ​    1.将字符串类型数据转换成基本类型数据时,字符串中的内容必须在该基本类型的数据范围内,否则发生数据格式化异常(NumberFormatException)

   ​    2.Character类并没有提供将字符串类型数据转换成char类型数据的方式

2、String类

1. String类

   类的特点:String 类代表字符串。

   类的位置:java.lang

   类的构造器:public String()

   ​    初始化一个新创建的 String 对象,使其表示一个空字符序列

   public String(byte[] bytes)

   ​    通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String。

   public String(byte[] bytes,int offset,int length)

   ​    通过使用平台的默认字符集解码指定的 byte 子数组,构造一个新的 String。

   public String(char[] value)

   ​    分配一个新的 String,使其表示字符数组参数中当前包含的字符序列。

   public String(char[] value,int offset,int count)(从下标几到下标几,后面的几不包含在内)

   ​    分配一个新的 String,它包含取自字符数组参数一个子数组的字符。

   public String(String original)

   ​    初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;

   public String(StringBuffer buffer)

   ​    分配一个新的字符串,它包含字符串缓冲区参数中当前包含的字符序列。

   public String(StringBuilder builder)

   ​    分配一个新的字符串,它包含字符串生成器参数中当前包含的字符序列。

   类的方法:判断功能方法、获取功能方法、转换功能方法、分割功能方法

   String对象的创建方式:1.字符串字面值赋值

   ​                                       2.通过new创建

2. String类的特点及源码分析:

   1.在程序中所有的字符串字面值都是String类的实例

   2.字符串实例是常量,一旦创建不可以改变

   ​    String str = "中国";  此str存的是“中国“在字符串常量池中的地址

   ​    str = "华夏";   把华夏的地址值赋值给str

   ​    System.out.println(str);  此处执行结果为”华夏“,而"中国"并没有改变,只是改变了str指向的地址值

   3.字符串实例不可变性的原理:底层封装了一个被final修饰的数组

   4.字符串底层数组的数据类型是:

   ​         JDK8.0(包含)以前:char[]

   ​         JDK9.0(包含)以后:byte[]

   5.在JDK9.0中,为什么将char[]的底层数组修改为byte[]的底层数组?

   时间复杂度

   ​    如果底层数组是char[],数组中元素类型是char,进行底层操作时,先将char转换byte,再由byte转换成二进制位

   ​    如果底层数组是byte[],就会直接将byte转换成二进制位

   空间复杂度

   ​    底层数组是char[],会根据内码的存储规则进行存储,

   ​         当存储字符串内容是"abc"时,每个字符根据内码规则占2个字节

   ​    底层数组是byte[],会根据开发环境的编码规则进行存储,

   ​         如果是utf8编码,当存储字符串内容是"abc"时,每个英文字符占1个字节

   6.String实例为什么可以存储中文?

   ​    JVM的底层和String类的底层都有UTF-16编码完成,仅支持Unicode码表中的中文

   7.String实例的极限长度是多少? 0-65535

   8.""的null的区别

   ​                   "",字面值常量,字符串对象

   ​                   null字面值常量,引用类型的默认值

3. String类判断功能的方法

   public boolean equals(Object anObject)

   ​    将此字符串与指定的对象比较

   public boolean equalsIgnoreCase(String anotherString)

   ​    将此 String 与另一个 String 比较,不考虑大小写。

   public boolean contains(CharSequence s)

   ​    当且仅当此字符串包含指定的 char 值序列时,返回 true。

   public boolean startsWith(String prefix)

   ​    测试此字符串是否以指定的前缀开始。

   public boolean endsWith(String suffix)

   ​    测试此字符串是否以指定的后缀结束。

   public boolean isEmpty()

   ​    当且仅当 length() 为 0 时返回 true。

4. String类获取功能的方法

   public char charAt(int index)

   ​    返回指定索引处的 char 值。

   public int length()

   ​    返回此字符串的长度。

   public int indexOf(String str)

   ​    返回指定子字符串在此字符串中第一次出现处的索引。

   public int lastIndexOf(String str)

   ​    返回指定子字符串在此字符串中最右边出现处的索引。

   public String substring(int beginIndex)

   ​    返回一个新的字符串,它是此字符串的一个子字符串

   public String substring(int beginIndex,int endIndex)

   ​    返回一个新字符串,它是此字符串的一个子字符串。

5. String类转换功能的方法

   public String concat(String str)

   ​    将指定字符串连接到此字符串的结尾。

   public byte[] getBytes()

   ​    使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中。

   public char[] toCharArray()

   ​    将此字符串转换为一个新的字符数组。

   public String replace(CharSequence target,CharSequence replacement)

   ​    使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。

   public String toLowerCase()

   ​    使用默认语言环境的规则将此 String 中的所有字符都转换为小写。

   public String toUpperCase()

   ​    使用默认语言环境的规则将此 String 中的所有字符都转换为大写。

6. String类分割功能的方法:

   public String[] split(String regex)

   ​    根据给定的"规则"的匹配拆分此字符串。

   String类split()的注意事项:

   ​    1.在根据指定的规则进行分割后,指定规则会消失

   ​    2.如果给的规则不在字符串的最后,连续的规则进行多次分割,分割后的内容是长度为0的字符串

   ​    3.如果给的规则在字符串的最后,在最后的规则进行分割时忽略不计

3、StringBuilder和StringBuffered

2. StringBuffer类和StringBuilder类的相同点和不同点:

   相同点:1.二者拥有相同的父类

   ​                2.与String不同,二者是可变的字符序列

   不同点:

   线程安全性不同:

   ​    StringBuffered类是线程安全的,适用于多线程程序,如果在单线程中进行使用,相比StringBuilder类低很多

   ​    StringBuilder类是线程不安全的,适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全

3. StringBuilder类

   类的特点

   1.一个可变的字符序列。原因:底层数组没有被final进行修饰

   2.StringBuilder类是线程不安全的,适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全

   类的位置:java.lang

   类的构造器:public StringBuilder()

   构造一个不带任何字符的字符串生成器,其初始容量为 16 个字符。

   类的方法

   public StringBuilder append(String str)

   ​    将指定的字符串追加到此字符序列

   public StringBuilder insert(int offset,String str)

   ​    将字符串插入此字符序列

   public StringBuilder reverse()

   ​    将此字符序列用其反转形式取代。

4. StringBuilder类的源码分析:

   1.StringBuilder类底层数组的初始容量是多少

   初始容量是多少取决于创建对象时所选择的构造器

   (1)StringBuilder()

   初始容量:16

   (2)StringBuilder(CharSequence seq)

   初始容量:参数长度+16

   (3)StringBuilder(String str)

   初始容量:参数长度+16

   (4)StringBuilder(int capacity)

   初始容量:自定义

   2.StringBuilder类底层数组的扩容原理(规则)

   JDK8.0(包含)以后:  (原来数组长度 << 1 ) + 2

   JDK7.0(包含):  原来数组长度 * 2 + 2;

   JDK6.0(包含)以前:  (原来数组长度 + 1) * 2;

   3.StringBuilder类底层数组扩容的时候,为什么+2?

   ​    为了防止通过自定义初始容量数组传0的特殊情况

基础14

异常

1. 异常的好处:  学习异常,了解异常,处理异常,从而保证程序可以正常的运行

2. Throwable类

   类的特点

   ​    Throwable 类是 Java 语言中所有错误(Error)或异常(Exception)的父类

   ​    错误(Error):Java程序出现了不可以通过后期自动补救方法进行解决的错误,只能改写代码

   ​    异常(Exception):Java程序出现可以通过后期自动补救方法进行解决的错误,不用后期改写代码,提前做好准备

   类的位置:java.lang

   类的构造器: public Throwable()

   构造一个将 null 作为其详细消息的新 throwable。

   ​    public Throwable(String message)

   构造带指定详细消息的新 throwable。

   类的方法

   public void printStackTrace()

   ​    将此 throwable 及其追踪输出至标准错误流

   public String getMessage()

   ​    返回此 throwable 的详细消息字符串。

3. 异常的分类:  运行时异常           编译时异常

   运行时异常:代码没有任何语法格式错误,在运行代码的时候出现了非正常的情况导致JVM停止运行

   位置:RuntimeException类及其子类

   常见: 空指针异常、索引越界异常、类型转换异常、数据格式化异常.......

   编译时异常:代码没有任何语法格式错误,在编译代码的时候出现了编译报错

   位置:Exception类及其子类(RuntimeException类及其子类除外)

4. 异常处理:Java程序中所有的异常必须进行处理

   分类:异常声明处理:将异常问题交给调用者进行解决

   ​         异常捕获处理:将异常问题自己独立进行解决(推荐)

   关键字:throws,try,catch,finally

   运行时异常的处理方案:1.异常声明处理   2.异常捕获处理     3.无需程序员进行处理

   如果程序员不针对运行时异常处理JVM主动进行处理:(1)终止JVM      (2)终止的同时,将异常信息进行打印

   编译时异常的处理方案:1.异常声明处理         2.异常捕获处理

5. throw关键字:抛出指定的异常对象

   格式:throw new 异常类名(实参);

6. 异常处理方式1:异常声明处理

   含义:含有异常的方法不进行异常的处理,将异常交给其调用者进行解决

   格式:修饰符 返回类型 方法名 () throws 异常类名1,异常类名2,......,异常类名n {}

7. 异常声明处理的注意事项:继承

   继承关系出现在抛出的异常对象中

   ​     1.进行异常声明时无需关注声明异常子父类的前后顺序

   ​     2.进行异常声明时可以直接声明异常的父类

   继承关系出现在异常所在的类中

   ​     异常在父类被重写的方法中,子类重写该方法时无需理会该异常

   ​     异常在子类重写后的方法中,处理方案只有唯一的一种,异常的捕获处理

8. 异常捕获处理:捕获到程序出现的异常,针对异常进行合理的解决方案,从而保证程序可以正常运行

   格式1:

   try {   可能出现异常的代码

   } catch (异常类型 对象名) {

   出现该异常的解决方案   }

   格式2:

   try {可能出现异常的代码

   } catch (异常类型 对象名) {

   出现该异常的解决方案

   } catch (异常类型 对象名) {

   出现该异常的解决方案   } ......

   格式3:

   try {可能出现异常的代码

   } catch (异常类型 对象名) {

   出现该异常的解决方案

   } finally {

   必须执行的代码  }

   格式4:

   try {  可能出现异常的代码

   } catch (异常类型 对象名) {

   出现该异常的解决方案

   } catch (异常类型 对象名) {

   出现该异常的解决方案   }

   ......

   finally {

   必须执行的代码   }

   格式5(JDK7.0):

   try (

   类名 对象名 = new 类名();......

   ) {可能出现异常的代码

   } catch () {   出现该异常的解决方案    }

   格式6(JDK7.0):

   try (

   类名 对象名 = new 类名();......

   ) {   可能出现异常的代码

   } catch () {

   出现该异常的解决方案

   } catch () {

   出现该异常的解决方案   } .....

9. 异常捕获的注意事项:

   继承关系出现在抛出的异常对象中

   1.分别捕获,分别处理

   ​    场景:适用于每个异常都有特有的解决方案

   2.一次捕获,分别处理

   ​    场景:每个异常存在关联性,解决方案各自不同

   ​    注意:需要将异常子类的处理放在父类的上面(前面)

   3.一次捕获,一次处理

   ​    场景:每个异常存在关联性,解决方案相同

   ​        继承关系出现在异常所在的类中

   ​        异常在父类被重写的方法中,子类重写该方法时无需理会该异常

   ​        异常在子类重写后的方法中,处理方案只有唯一的一种,异常的捕获处理

10. finally关键字:在进行异常捕获声明时必须执行的代a码

    格式:

    try {  可能出现异常的代码

    } catch (异常类型 对象名) {

    出现该异常的解决方案

    } finally {   必须执行的代码    }

    try {

    可能出现异常的代码

    } catch (异常类型 对象名) {

    出现该异常的解决方案

    } catch (异常类型 对象名) {

    出现该异常的解决方案   }  ......

    finally {

    必须执行的代码  }

11. 针对关闭资源对象异常捕获处理的优化(JDK7.0)

    格式:

    try (

    类名 对象名 = new 类名();......

    ) {   可能出现异常的代码

    } catch () {

    出现该异常的解决方案  }

    try (

    类名 对象名 = new 类名();......

    ) {   可能出现异常的代码

    } catch () {   出现该异常的解决方案

    } catch () {

    出现该异常的解决方案  } .....

12. finally关键字的注意事项

    在try...catch...finally里面尽量避免使用return

13. 自定义异常:

    自定义运行时异常

    自定义编译时异常(重点)

    自定义运行时异常:

    ​    1.创建自定义运行时异常类

    ​    2.将该类继承RuntimeException类

    ​    3.根据父类生成合适的构造器(至少包含无参和String参数的构造器)

    自定义编译时异常:

    ​    1.创建自定义编译时异常类

    2.将该类继承Exception类

    3.根据父类生成合适的构造器(至少包含无参和String参数的构造器)

基础15

1、日期时间类概述:

​    第一代(JDK1.0):Date类,DateFormat类,SimpleDateFormat类

​    第二代(JDK1.1):Calendar类

​    第三代(JDK8.0):LocalDate类,LocalTime类,LocalDateTime类,DateTimeFormatter类

 2、Date类

1. 类的特点:类 Date 表示特定的瞬间,精确到毫秒。

   类的位置:java.util

   类的构造器

   public Date()

   ​     分配 Date 对象并初始化此对象,以表示分配它的时间(精确到毫秒)。

   public Date(long date)

   ​    分配 Date 对象并初始化此对象,以表示自从标准基准时间(称为“历元(epoch)”,即 1970 年 1 月 1 日 00:00:00 GMT)以来的指定毫秒数。

   public Date(int year,int month,int date,int hrs,int min,int sec)

   ​     分配 Date 对象,并初始化此对象,以表示本地时区中由 year、month、date、hrs、min 和 sec 参数指定的秒的开始瞬间。

   public Date(int year,int month,int date,int hrs,int min)

   ​    分配 Date 对象,并初始化此对象,以表示本地时区中由 year、month、date、hrs、min参数指定的秒的开始瞬间。

   public Date(int year,int month,int date)

   ​    分配 Date 对象,并初始化此对象,以表示本地时区中由 year、month、date参数指定的秒的开始瞬间。

   类的方法

   public long getTime()

   ​    返回自 1970 年 1 月 1 日 00:00:00 GMT 以来此 Date 对象表示的毫秒数。

2. Date对象的格式化和解析:

   格式化:Date对象==>文本(String)

   解析:文本(String)==>Date对象

   DateFormat类

   类的特点:针对Date对象进行格式化和解析操作工具类的父类

   类的位置:java.text

   类的构造器:该类是抽象类

   类的方法

   public final String format(Date date)

   ​    将一个 Date 格式化为日期/时间字符串。

   public Date parse(String source)

   ​    从给定字符串的开始解析文本,以生成一个日期。该方法不使用给定字符串的整个文本。

   SimpleDateFormat类

   类的特点:针对Date对象进行格式化和解析操作的工具类

   类的位置:java.text

   类的构造器

   public SimpleDateFormat(String pattern)

      用给定的模式和默认语言环境的日期格式符号构造 SimpleDateFormat。

   类的方法

   详见DateFormat类的方法

3. Date对象的格式化

   1.创建Date对象

   2.通过给定的格式创建SimpleDateFormat对象

   3.进行格式化操作

4. Date对象的解析:

   1.声明并初始化日期时间文本

   2.通过给定的格式创建SimpleDateFormat对象

   3.进行解析操作

3、Calendar类

1. 类的特点:针对日期时间操作的第二代工具类

   类的位置:java.util

   类的构造器:该类为抽象类

   类的方法

   public static Calendar getInstance()

   ​    使用默认时区和语言环境获得一个日历。

   public int get(int field)

   ​    返回给定日历字段的值。

4、LocalDate类

LocalDate、LocalTime、LocalDateTime

1. LocalDateTime类

   类的特点:针对日期时间操作的第三代工具类

   类的位置:java.time

   类的构造器:构造器私有化

   类的方法

   public static LocalDateTime now()

   ​    从默认时区中的系统时钟中获取当前日期时间。

   public static LocalDateTime parse(CharSequence text,DateTimeFormatter formatter)
       获得 LocalDateTime实例从使用特定格式的文本字符串。

   public int getYear()

   ​    获取年度字段。

   public int getMonthValue()

   ​    从1到12得到一个月的时间字段。

   public int getDayOfMonth()

   ​    获取月字段的一天。

   public int getHour()

   ​    获取天字段的时间。

   public int getMinute()

   ​    获取小时字段的分钟。

   public int getSecond()

      获取第二个分钟字段。

   public static LocalDateTime parse(CharSequence text,DateTimeFormatter formatter)

      获得 LocalDateTime实例从使用特定格式的文本字符串。

2. DateTimeFormatter类(LocalDate、LocalTime、LocalDateTime的格式化类)

   类的特点:针对第三代日期时间类进行格式化和解析操作的工具类

   类的位置:java.time.format

   类的构造器:构造器私有化

   类的方法

   ​    public static DateTimeFormatter ofPattern(String pattern)

   ​         创建一个格式化程序使用指定的模式。

   ​    public String format(TemporalAccessor temporal)

   ​         使用此格式化程序格式的日期时间对象。

   ​    public TemporalAccessor parse(CharSequence text)

   ​         充分分析文本产生的时空对象

   LocalDateTime对象的格式化:

   ​    1.获取LocalDateTime对象

   ​    2.获取DateTimeFormatter对象,并指定格式

   ​    3.进行格式化操作

3. LocalDateTime对象的解析

   1.声明并初始化日期时间文本

   2.获取DateTimeFormatter对象,并指定格式

   3.进行解析操作

 5、file类

1. File类

   类的特点:文件和目录路径名的抽象表示形式

   类的位置:java.io

   类的构造器

   public File(String pathname)

   ​     通过将给定路径名字符串转换为抽象路径名来创建一个新 File 实例。

   类的方法

   public String getAbsolutePath()

   ​    返回此抽象路径名的绝对路径名字符串

   public String getPath()

   ​    将此抽象路径名转换为一个路径名字符串。

   public String getName()

   ​    返回由此抽象路径名表示的文件或目录的名称。

   public long length()

   ​    返回由此抽象路径名表示的文件的长度。

   public boolean exists()

   ​    测试此抽象路径名表示的文件或目录是否存在。

   public boolean isDirectory()

   ​    测试此抽象路径名表示的文件是否是一个目录。

   public boolean isFile()

   ​    测试此抽象路径名表示的文件是否是一个标准文件。

   public boolean createNewFile()

   ​    当且仅当不存在具有此抽象路径名指定名称的文件时,不可分地创建一个新的空文件。

   public boolean mkdir()

   ​    创建此抽象路径名指定的目录。

   public boolean mkdirs()

   ​    创建此抽象路径名指定的目录,包括所有必需但不存在的父目录。

   public File[] listFiles()

   ​    返回一个抽象路径名数组,这些路径名表示此抽象路径名表示的目录中的文件。

2. 绝对路径和相对路径

   绝对路径:从盘符开始一直到所表示的文件或目录,是一个完整的路径

   构造路径:构造器中的路径,既可以是绝对路径,也可以是相对路径

   相对路径:单独的文件名或目录名,是一个不完整的路径,相对所在项目路径而言,是一个变化的路径(推荐)

6、IO流1

1. IO流:数据的输入输出

   输入:数据以"字节"或"字符"为单位从"其它硬件设备"到"内存"的流动

   输出:数据以"字节"或"字符"为单位从"内存"到"其它硬件设备"的流动

   四大基本流:

   ​    字节输入流(InputStream抽象父类)

   ​    字节输出流(OutputStream抽象父类)

   ​    字符输入流(Reader抽象父类)

   ​    字符输出流(Writer抽象父类)

   功能分类:

   ​    文件流:

   ​          文件字节流:文件字节输入流、文件字节输出流

   ​          文件字符流:文件字符输入流、文件字符输出流

   ​    缓冲流:

   ​          缓冲字节流:缓冲字节输入流、缓冲字节输出流

   ​          缓冲字符流:缓冲字符输入流、缓冲字符输出流

   ​    转换流:转换输入流、转换输出流、

   ​    对象流:对象输入流、对象输出流

   ​    标准流:标准输入流、标准输出流

7、文件流

1. FileInputStream类(文件字节输入流)

   类的特点:针对文件以字节为单位进行读取操作的工具类

   类的位置:java.io

   类的构造器

   public FileInputStream(File file)

    通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的 File 对象 file 指定。

   public FileInputStream(String name)

    通过打开一个到实际文件的连接来创建一个 FileInputStream,该文件通过文件系统中的路径名 name 指定。

   类的方法

   public void close()

   ​    关闭此文件输入流并释放与此流有关的所有系统资源。

   public int read()

   ​    从此输入流中读取一个数据字节

   public int read(byte[] b)

   ​    从此输入流中将最多 b.length 个字节的数据读入一个 byte 数组中。

2. FileOutputStream类(文件字节输出流)

   类的特点:针对文件以字节为单位进行写入操作的工具类

   类的位置:java.io

   类的构造器

   public FileOutputStream(File file)

      创建一个向指定 File 对象表示的文件中写入数据的文件输出流

   public FileOutputStream(File file,boolean append)

   ​    创建一个向指定 File 对象表示的文件中写入数据的文件输出流。

   public FileOutputStream(String name)

   ​    创建一个向具有指定名称的文件中写入数据的输出文件流。

   public FileOutputStream(String name,boolean append)

   ​    创建一个向具有指定 name 的文件中写入数据的输出文件流。

   类的方法

   public void close()

   ​    关闭此文件输出流并释放与此流有关的所有系统资源。

   public void write(int b)

   ​    将指定字节写入此文件输出流。

   public void write(byte[] b)

   ​    将 b.length 个字节从指定 byte 数组写入此文件输出流中。

   public void write(byte[] b,int off,int len)

   ​    将指定 byte 数组中从偏移量 off 开始的 len 个字节写入此文件输出流。

3. 文件的回车换行

   格式:\r\n

   含义:  回车:将光标移动到当前行的行首

   ​           换行:将光标移动到下一行相同的位置

基础16

1、文件字符流

1. 文件字节流优劣

   文件字节流的优势: 适用于进行图片,视频,音频等

   文件字节流的弊端: 操作文件(编码)==>字节(解码)==>写入(编码)==>使用文件(解码)

   ​                                  编码和解码的过程中出现了数据的转换问题,可能出现乱码情况

    文件字符流目的:在读写文本文件时,涉及中文字符不进行中文和字节的转换

2. FileReader类(文件字符输入流)

   类的特点:针对文件以字符为单位进行读取操作的工具类

   类的位置:java.io

   类的构造器

   public FileReader(File file)

   ​    在给定从中读取数据的 File 的情况下创建一个新 FileReader

   public FileReader(String fileName)

   ​    在给定从中读取数据的文件名的情况下创建一个新 FileReader。

   类的方法

   public void close():闭该流并释放与之关联的所有资源。

   public int read():读取单个字符。

   public int read(char[] cbuf):将字符读入数组

3. FileWriter类(文件字符输出流)

   类的特点:针对文件以字符为单位进行写入操作的工具类

   类的位置:java.io

   类的构造器

   public FileWriter(File file)

   ​    根据给定的 File 对象构造一个 FileWriter 对象。

   public FileWriter(File file,boolean append)

   ​    根据给定的 File 对象构造一个 FileWriter 对象。

   public FileWriter(String fileName)

   ​    根据给定的文件名构造一个 FileWriter 对象。

   public FileWriter(String fileName,boolean append)

   ​    根据给定的文件名以及指示是否附加写入数据的 boolean 值来构造 FileWriter 对象。

   类的方法

   public void close():关闭此流,但要先刷新它。

   public void write(int c):写入单个字符。

   public void write(char[] cbuf):写入字符数组。

   public void write(char[] cbuf,int off,int len):写入字符数组的某一部分。

   public void write(String str):写入字符串。

   public void write(String str,int off,int len):写入字符串的某一部分。

   public void flush():刷新该流的缓冲。

   文件字符输出流注意事项:

   close():关闭并刷新,关闭流后不能再进行使用

   flush():刷新该流,将内存缓冲区中的写入内容写入到指定文件中,后续可以继续使用该流

 2、缓冲流

1. BufferedInputStream类(缓冲字节输入流)

   类的特点:针对另外一个字节输入流添加缓冲区使之具有高效读取功能的工具类

   类的位置:java.io

   类的构造器

   public BufferedInputStream(InputStream in)

   ​     创建一个 BufferedInputStream 并保存其参数,即输入流 in,以便将来使用。

   类的方法

   详见文件字节输入流方法

2. BufferedOutputStream类(缓冲字节输入流)

   类的特点: 针对另外一个字节输出流添加缓冲区使之具有高效写入功能的工具类

   类的位置: java.io

   类的构造器

   public BufferedOutputStream(OutputStream out)

   ​     创建一个新的缓冲输出流,以将数据写入指定的底层输出流。

   类的方法: 详见文件字节输出流方法

3. BufferedReader类(缓冲字符输入流)

   类的特点:针对另外一个字符输入流添加缓冲区使之具有高效读取功能的工具类

   类的位置:java.io

   类的构造器

   public BufferedReader(Reader in):创建一个使用默认大小输入缓冲区的缓冲字符输入流。

   类的方法

   public String readLine():读取一个文本行。

4. BufferedWriter类(缓冲字符输出流)

   类的特点:针对另外一个字符输出流添加缓冲区使之具有高效写入功能的工具类

   类的位置:java.io

   类的构造器:public BufferedWriter(Writer out)

   创建一个使用默认大小输出缓冲区的缓冲字符输出流。

   类的方法:   public void newLine():写入一个行分隔符。

3、转换流

1. 转换流的学习目的

   在进行编码或者解码的过程中可以指定编码或解码的方式

2. InputStreamReader类(转换输入流)

   类的特点:InputStreamReader 是字节流通向字符流的桥梁

   类的位置:java.io

   类的构造器

   public InputStreamReader(InputStream in)

   ​    创建一个使用默认字符集的 InputStreamReader。

   public InputStreamReader(InputStream in,String charsetName)

   ​    创建使用指定字符集的 InputStreamReader。

   类的方法

   详见文件字符输入流方法

   OutputStreamWriter类(转换输出流)

   类的特点

3. OutputStreamWriter 是字符流通向字节流的桥梁:

   类的位置:java.io

   类的构造器

   public OutputStreamWriter(OutputStream out)

   ​    创建使用默认字符编码的 OutputStreamWriter。

   public OutputStreamWriter(OutputStream out,String charsetName)

   ​    创建使用指定字符集的 OutputStreamWriter。

   类的特点

   详见文件字符输出流方法

4、对象流

1. ObjectOutputStream类(对象输出流,序列化过程)

   类的特点:针对对象和基本数据类型进行输出的字节流工具类

   类的位置:java.io

   类的构造器

   public ObjectOutputStream(OutputStream out)

   ​    创建写入指定 OutputStream 的 ObjectOutputStream。

   类的方法

   public final void writeObject(Object obj)

   ​    将指定的对象写入 ObjectOutputStream。

   Serializable接口

   接口的特点:类通过实现 java.io.Serializable 接口以启用其序列化功能

   接口的位置:java.io

   接口的方法:没有方法

2. ObjectInputStream类(对象输入流,反序列化)

   类的特点

   ObjectInputStream 对以前使用 ObjectOutputStream 写入的基本数据和对象进行反序列化

   类的位置:java.io

   类的构造器

   public ObjectInputStream(InputStream in)

   ​    创建从指定 InputStream 读取的 ObjectInputStream。

   类的方法

   public final Object readObject()

   ​    从 ObjectInputStream 读取对象。

3. 对象流的注意事项:

   1.实现序列化操作,必须让对象所对应的类实现Serializable,否则会发生NotSerializableException

   2.如果需要通过序列化操作多个对象,需要将多个对象存储"集合容器"中,在序列化和反序列化过程中尽量操作一个序列化对象

   3.在实现序列化和反序列化过程中,针对序列化类不能做任何修改

   4.在实现序列化和反序列化过程中,针对序列化文件不能做任何修改

   5.在实现序列化和反序列化过程中,如果对象的某些属性不需要实现序列化操作,可以transient关键字进行修饰符

   transient关键字:瞬态的

   作用:被transient关键字修饰的属性不可以被序列化

   格式:修饰符 transient 数据类型 变量名;

 5、标准流

1. 标准输入流:System.in

   标准输出流:System.out

2. //实现第二种字符串的键盘录入
       BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

   ​        String str = br.readLine();

3. PrintStream类

   类的特点:针对各种类型的数据值进行方法打印操作的工具类

   类的位置:java.io

   类的构造器

   public PrintStream(OutputStream out)

   创建新的打印流。此流将不会自动刷新。

   public PrintStream(String fileName)

   创建具有指定文件名称且不带自动行刷新的新打印流。

   类的方法

 6、字符集

字符集: 十进制数字和字符进行一一对应的码表

 常见:ASCII字符集Unicode字符集、GB字符集、ISO-8859字符集

字符编码: 以某种存储规则将存储字节和字符进行转换关系

常见:

ASCII字符集:ASCII-128字符编码、ASCII-256字符编码

Unicode字符集

UTF-8字符编码、UTF-16字符编码、UTF-32字符编码

GB字符集:GB2312字符编码、GBK字符编码、GB18030字符编码

ISO-8859字符集、ISO-8859-1字符编码、ISO-8859-2字符编码

......

基础17

 1、集合概述

1. 集合和数组的区别:

   长度可变性不同:

   ​    集合:长度是可以改变的        数组:长度是固定不变的

   元素的数据类型不同:

   ​    集合:只能存储引用类型数据    数组:可以存储基本类型数据,也可以存储引用类型数据

   ​    集合:存储同一种数据类型多个对象的容器

2. 集合的分类:   

   ​          单列集合(Collection): 存储元素时以"个"为单位

   ​                  Collection接口分类: List接口、ArrayList类、Vector类、LinkedList类

   ​                  Set接口:HashSet类、LinkedHashSet类、TreeSet类

   ​           双列集合(Map): 存储元素时以"对"为单位

   ​                  Map接口分类: HashMap类、LinkedHashMap类、TreeMap类、Hashtable类、Properties类

 2、Collection接口

1. Collection接口

   接口的特点:单列集合的顶级接口

   接口的位置:java.util

   接口的方法

   boolean add(E e):确保此 collection 包含指定的元素(可选操作)。

   void clear():移除此 collection 中的所有元素(可..选操作)。

   boolean contains(Object o):如果此 collection 包含指定的元素,则返回 true。

   boolean isEmpty():如果此 collection 不包含元素,则返回 true。

   Iterator<E> iterator():返回在此 collection 的元素上进行迭代的迭代器。

   boolean remove(Object o):从此 collection 中移除指定元素的单个实例,如果存在的话(可选操作)。

   int size():返回此 collection 中的元素数

2. Collection集合的面试题

   使用多态的形式创建Collection集合对象,而多态的特点主要和方法有关,当多态的对象调用方法,先虚调用父类或父接口中的方法,如果有执行子类或实现类重写后的方法,如果没有,编译报错,在打印集合对象时,其实就是调用集合多态对象的toString(),调用该toString()会先需调用父接口Collection中的toString(),通过查看源码发现Collection接口及其父接口都没有toString(),代码应该编译报错,但实际上并没有报错,为什么?

   所有的接口都继承Object类抽象形式或者所有的接口都含有Object类中方法的抽象形式

3.Collection集合的遍历

1. Collection集合通用的遍历方式1:迭代器(list.iterator)

   Iterator接口

   接口的特点:对 Collection 进行迭代的迭代器。

   原理:通过单列集合对象获取迭代器对象时,将集合的元素数据存储到迭代器对象中,再针对迭代器对象进行遍历

   接口的位置:java.util

   接口的方法:

   boolean hasNext():如果仍有元素可以迭代,则返回 

   true:E next():返回迭代的下一个元素。

   void remove():从迭代器指向的 collection 中移除迭代器返回的最后一个元素(可选操作)。

   迭代器的注意事项:

   1.迭代器对象只能进行唯一的一轮迭代器,如果多轮迭代,需要每轮重新获取迭代器对象,否则发生没有元素异常NoSuchElementException

   2.在使用迭代器的过程中,不能针对集合中的元素做任何增删操作,否则发生并发修改异常ConcurrentModificationException

2. Collection集合通用遍历方式2:增强for

   增强for(JDK5.0)

   ​    注意:针对迭代器使用的简化方式(本质就是迭代器)

   ​    格式:  for (元素数据类型 元素名 : 容器名) {  }

   增强for的注意事项:

   ​    1.增强for的底层其实就是一个迭代器对象

   ​    2.在使用增强for的过程中,不能针对集合中的元素做任何增删操作,否则发生并发修改异常                   ConcurrentModificationException

   ​    3.增强for既可以遍历集合,也可以遍历数组,但是不推荐使用增强for遍历数组

   ​          原因:使用增强for遍历引用类型数组时,底层会将引用类型数组先转换成Collection集合对象;

   ​                   使用增强for遍历基本类型数组时,底层会将增强for转换为普通for进行遍历

3. Collection集合通用遍历方式3:Stream流的forEach()

4. Collection集合通用遍历方式4:Iterable中的forEach()

3、泛型

1. 泛型(JDK5.0):未知的数据类型

   格式:<泛型>

   注意:1.如果使用泛型,必须在进行类,接口,方法声明的时候声明泛型

   ​         2.如果使用泛型,必须在合适的时机确认泛型,否则JVM默认确定为Object类型

   好处:更好的限制数据类型的使用

2. 泛型的基础应用

   含有泛型的接口,类,方法

   含有泛型的类

   声明格式:

   public class 类名<泛型> {}

   确认时机:创建类的对象时

   确认格式:基础JDK6.0(包含)以前,且实现类存在泛型

   ​    类名<数据类型> 对象名 = new 类名<数据类型>(实参);

   基础JDK7.0(包含)以后,且实现类存在泛型,新增格式:

   ​    类名<数据类型> 对象名 = new 实现类类名<>(实参);

   注意事项:确认泛型时,前后<>中的数据类型必须一致,否则编译报错

3. 含有泛型的接口

   声明格式:  public interface 接口名<泛型> {}

   确认时机:创建接口的实现类对象时

   确认格式:

   基础JDK6.0(包含)以前,且实现类存在泛型

   ​    父接口名<数据类型> 实现类对象名 = new 实现类类名<数据类型>(实参);

   基础JDK7.0(包含)以后,且实现类存在泛型,新增格式:

   ​    父接口名<数据类型> 实现类对象名 = new 实现类类名<>(实参);

   实现类不存在泛型:

   ​    父接口名 实现类对象名 = new 实现类类名(实参);

   注意事项:1.确认泛型时,前后<>中的数据类型必须一致,否则编译报错

   ​                2.如果含有泛型的接口含有没有泛型的实现类时,不推荐使用多态形式创建该实现类对象

4. 含有泛型的方法

   声明格式:修饰符 <泛型> 返回类型 方法名 () {}

   确认时机:调用该方法时

   确认格式:方法名(实参);

5. 泛型的高级应用:通配符

   通配符:针对含有泛型方法特殊形式的简化

   前提:该泛型方法的形参列表是一个含有该泛型类或者接口

   格式:

   优化前:修饰符 <泛型> 返回类型 方法名 (类名或接口名<泛型> 对象名) {}

   优化后:修饰符 返回类型 方法名 (类名或接口名<?> 对象名) {}

   确认时间:调用方法传参时

   ​                通配符的上限和下限

   通配符上限:格式:<? extends 数据类型>

   含义:传递的类型必须是该类型本身或者是该类型的子类类型

   通配符下限:

   格式:<? super 数据类型>

   含义:传递的类型必须是该类型本身或者是该类型的父类类型

4、List接口

1. List接口特点:

   1.List集合都是有序的集合

   ​         注:数据存储和取出的顺序一致,而非排列中的有序

   2.List集合都是含有索引的集合

   ​    集合索引:元素在集合中的位置,从0开始,依次递增,最大的索引长度-1

   3.List集合都可以存储重复元素

   4.List集合中索引的实现方式有4种(涉及数据结构)

   数组结构、链表结构、队列结构、栈结构

   5.List集合都含有特殊的迭代器

   接口的位置:java.util

   接口的方法:同下

2. List集合的常用方法

   void add(int index,E element):在列表的指定位置插入指定元素(可选操作)。

   E get(int index):返回列表中指定位置的元素。

   int indexOf(Object o):返回此列表中指定元素第一次出现的索引;如果列表不包含此元素,则返回 -1。

   int lastIndexOf(Object o):返回此列表中指定元素最后出现的索引;如果列表不包含此元素,则返回 -1。

   ListIterator<E> listIterator():返回此列表元素的列表迭代器(按适当顺序)。

   E remove(int index):移除列表中指定位置的元素(可选操作)。

   E set(int index,E element):用指定元素替换列表中指定位置的元素(可选操作)。

   List<E> subList(int fromIndex,int toIndex):返回列表中指定的 fromIndex(包括)和 toIndex(不包括)之间的部分视图

3. List集合的遍历方式:6种

   1.迭代器

   2.增强for

   3.Stream流的forEach()

   4.Iterable接口的forEach()  (集合名.forEach)

   5.普通for,配合get()使用

   6.List特有迭代器

4. 数组数据结构:其实就是前面学习的对象数组

   特点:相比链表结构:查询效率高,增删效率低

5. 链表数据结构:其实就是程序中的一个特殊类

   分类:

   ​    单向链表

   ​         链表对象至少含有两个属性:

   ​              当前元素(数据类型:泛型)

   ​              下一个链表对象(数据类型:链表类型)

   ​    双向链表

   ​         链表对象至少含有三个属性:

   ​               当前元素(数据类型:泛型)

   ​               下一个链表对象(数据类型:链表类型)

   ​               上一个链表对象(数据类型:链表类型)

   特点:相比数组数据结构:增删效率高,查询效率低

   注意:链表结构长度越长效率越低

 5、ArrayList类

1. 类的特点

   1.ArrayList集合底层数据结构是数组结构

   2.ArrayList集合可以存储null元素,在使用ArrayList集合元素之前,先针对元素进行非空校验,防止空指针异常

   3.ArrayList集合是线程不安全的集合,只适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全

   4.ArrayList集合是有序的集合

   ​    有序集合:存储元素的顺序和获取元素的顺序是一致的

   5.ArrayList集合是含有索引集合

   6.ArrayList集合可以存储重复元素

   7.ArrayList集合适用于List集合的6种遍历方式

   类的位置:java.util

   类的构造器

   public ArrayList():构造一个初始容量为 10 的空列表。

   类的方法详见Collection接口和List接口的常用方法

   注意事项:针对多个元素进行查询操作较多的时候

2. ArrayList集合的源码分析(基于JDK8.0):

   1.ArrayList集合底层数组的初始容量

      初始容量是多少取决于创建对象时所选择的构造器

   ​        (1)ArrayList():初始容量:0

   ​        (2)ArrayList(Collection<? extends E> c):初始容量:参数集合的长度

   ​        (3)ArrayList(int initialCapacity):初始容量:自定义

   2.无参构造器的扩容原理: 

   ​       初始为0, 在第一次添加元素时扩容为10, 后续添加元素时扩容为原来数组长度 + (原来数组长度 >> 1);

   3.JDK6.0(包含)以前和JDK7.0(包含)以后的区别:

   ​       (1)无参构造器初始容量不同:

   ​               JDK6.0(包含)以前初始容量:10

   ​               JDK7.0(包含)以后初始容量:0

   ​       (2)无参构造器的扩容原理不同:

   ​              JDK6.0(包含)以前:  (原来数组长度 * 3)/2 + 1;

   ​              JDK7.0(包含)以后: 初始为0, 第一次添加元素时扩容为10,  后续添加元素时扩容为

   ​                                              原来的数组长度 + (原来数组长度 >> 1);

基础18

 1、vector

1. Vector类

   类的特点

   ​    1.Vector集合底层数据结构是数组结构

   ​    2.Vector集合可以存储null元素,在使用Vector集合元素之前,先针对元素进行非空校验,防止空指针异常

   ​    3.Vector集合是线程安全的集合,只适用于多线程程序,如果在单线程中进行使用,执行效率低

   ​    4.Vector集合是有序的集合

   ​           有序集合:存储元素的顺序和获取元素的顺序是一致的

   ​    5.Vector集合是含有索引集合

   ​    6.Vector集合可以存储重复元素

   ​    7.Vector集合适用于List集合的6种遍历方式

   类的位置: java.util

   类的构造器

   public Vector(): 构造一个空向量,使其内部数据数组的大小为 10,其标准容量增量为零。

   类的方法: 详见Collection接口和List接口常用方法

2. ArrayList集合和Vector集合的区别

   1.线程安全性:

   ​    ArrayList集合:ArrayList集合是线程不安全的集合,只适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全

   ​    Vector集合:Vector集合是线程安全的集合,只适用于多线程程序,如果在单线程中进行使用,执行效率低

   2.无参构造器底层的初始容量

   ArrayList集合:

   ​    JDK6.0(包含)以前: 初始容量:10

   ​    JDK7.0(包含)以后:  初始容量:0

   Vector集合: 初始容量:10

   3.底层数组影响扩容的因素不同

   ​    ArrayList集合:是否为第一次扩容

   ​    Vector集合:增量参数是否大于0

   4.底层数组的扩容规则不同

   ​    ArrayList集合:

   ​         JDK6.0(包含)以前: 扩容原理:(原来数组长度 * 3)/2 + 1;

   ​         JDK7.0(包含)以后:

   ​               扩容原理:

   ​                      第一次添加元素时: 扩容原理:10

   ​                      后续添加元素时: 原来数组长度 + (原来数组长度 >> 1);

   Vector集合:

   ​     当增量参数 > 0:   扩容原理: 原来数组长度 + 增量参数;

   ​     当增量参数 <= 0;  扩容原理: 原来数组长度 + 原来数组长度;


2、LinkedList类

1. 类的特点

   ​    1.LinkedList集合底层的数据结构为"链接列表结构",并且是一个"双向链接列表结构"

   ​    2.LinkedList集合可以存储null元素,在使用集合中元素之前需要进行非空校验,防止空指针异常

   ​    3.LinkedList集合不是线程安全的,适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全

   ​    4.LinkedList集合是有序的集合

   ​            有序集合:存储元素的顺序和获取元素的顺序是一致的

   ​    5.LinkedList集合是含有索引集合

   ​    6.LinkedList集合可以存储重复元素

   ​    7.LinkedList集合适用于List集合的6种遍历方式

   类的位置:java.util

   类的构造器

   public LinkedList():构造一个空列表。

   类的方法

   public void addFirst(E e):将指定元素插入此列表的开头。

   public void addLast(E e):将指定元素添加到此列表的结尾。

   public E getFirst():返回此列表的第一个元素。

   public E getLast():返回此列表的最后一个元素。

   public E removeFirst():移除并返回此列表的第一个元素。

   public E removeLast():移除并返回此列表的最后一个元素。

2. LinkedList集合存储过程的源码分析

3、Set接口

接口的特点

​    1.Set接口下所有集合不可以存储重复元素

​    2.Set接口下所有集合没有索引

​    3.Set接口下所有集合既有有序的集合,也有无序的集合

​    4.Set即可下所有集合只有4种遍历方式

详见Collection集合的遍历方式

接口的位置:java.util

接口的方法:详见Collection接口的常用方法

 4、HashSet类

1. 类的特点

   1.HashSet集合底层封装一个HashMap实例

   ​    HashMap集合底层的数据结构:哈希表

   ​    JDK7.0(包含)以前: 存储链接列表对象的数组

   ​    JDK8.0(包含)以后: 存储链接列表对象或红黑树对象的数组

   2.HashSet集合是无序的集合

   3.HashSet集合不可以存储重复元素

   4.HashSet集合无法保证元素在集合中的顺序永远不会改变

   ​    原因:元素的存储顺序和底层数组的长度有关,一旦数组发生扩容或缩减元素的位置有可能发生变化

   5.HashSet集合可以存储null元素,使用集合元素时,需要进行非空校验,防止空指针异常

   6.HashSet集合是线程不安全的,适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全

   类的位置:java.util

   类的构造器

   public HashSet()

   构造一个新的空 set,其底层 HashMap 实例的默认初始容量是 16,加载因子是 0.75。

   类的方法

   详见Collection接口的常用方法

2. HashSet集合如何过滤重复元素

   1.HashSet集合过滤重复元素和地址值无关

   2.HashSet集合过程重复元素和hashCode()有关,重写Object类的hashCode()

   3.HashSet集合过程重复元素和equals()有关,重写Object类的equals()

3. 重写hashCode()时重要参数为什么是31?

   1.为了减少hashCode值的重复概率,这个数必须是质数

   2.这个数不宜过小(原因:过小增大重复概率)

   3.这个数不宜过大(原因:过大会有可能超出int范围,造成数据的精度的损失,增大重复概率)

   4.通过"泊松分布"计算出数字29和31是较为合适的数字

   5.通过数学科学计数法的改写,29可以写成2^5-3,31可以写成2^5-1,31的格式和整数取值范围相似或者二进制满位原因,最终选择31

5、 LinkedHashSet类

类的特点

​    1.LinkedHashSet集合是有序,无索引,无重复的集合

​    2.LinkedHashSet集合底层的数据结构是"哈希表 + 链表"

​                                   链表:维护着LinkedHashSet集合有序

​    3.LinkedHashSet集合可以存储null元素,使用集合元素时,需要进行非空校验,防止空指针异常

​    4.LinkedHashSet集合是线程不安全的,适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全

类的位置:java.util

类的构造器

public LinkedHashSet():构造一个带默认初始容量 (16) 和加载因子 (0.75) 的新空链接哈希 set。

类的方法:详见Collection接口的常用方法

 6、 红黑树数据结构:

含义:带有红结点和黑结点的二叉树结构,其实也是程序中比较特殊的类

特点:1.查询效率高,增删效率高

​         2.结点对象可以根据int数据进行大小排序

设计:当前元素(泛型)

​         父结点对象(结点对象类型)

​         子左结点对象(结点对象类型)

​         子右结点对象(结点对象类型)

​          颜色属性(boolean)

注意:红黑树数据结构适用于数据量较多时候,不适合少量数据

​         红黑树数据结构中的每个结点比较数据必须落实在"int类型"

7、TreeSet类

类的特点

​    1.TreeSet集合底层的数据结构"红黑树"

​    2.使用元素的自然顺序对元素进行排序,或者根据创建 set 时提供的 Comparator 进行排序

​    3.TreeSet集合是无序,无索引,无重复的集合,存储元素顺序和获取顺序不一致

​    4.TreeSet集合不可以存储null元素,添加元素时需要针对每个待添加元素进行非空校验,防止空指针异常

​    5.TreeSet集合是线程不安全的集合,适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全

类的位置:java.util

类的构造器

public TreeSet():构造一个新的空 set,该 set 根据其元素的自然顺序进行排序。

public TreeSet(Comparator<? super E> comparator)

​    构造一个新的空 TreeSet,它根据指定比较器进行排序。

类的方法:详见Collection集合的常用方法

注意事项: 针对TreeSet中元素类型必须定义比较器(手动编写比较规则)

​                 自然顺序比较器

​                 实现Comparable<T>接口,重写compareTo(T o)

​                 定制顺序比较器

​                 实现Comparator<T>接口,重写int compare(T o1,T o2)

注:比较器中的compareTo()方法可以用于字符串的比较

8、自然顺序比较器

实现Comparable<T>接口,重写compareTo(T o)

步骤:1.TreeSet集合元素的类型实现Comparable<T>接口

​         2.TreeSet集合元素的类型中重写Comparable<T>接口的compareTo(T o),指定比较规则

9、定制顺序比较器

new Comprator匿名内部类并重写其中的方法

基础19

1、Map接口

1. Map接口

   接口的特点:1.双列集合的顶级接口

   ​                       2.Map集合以"对"为单位进行存储,其中一个key,一个value

   ​                       3.key和value之间的关系是"映射关系"

   ​                       4.key和value的泛型类型可以相同,也可以不同

   ​                       5.在映射关系中,key不可以重复,value可以重复

   接口的位置:java.util

   接口的方法

   V put(K key,V value): 将指定的值与此映射中的指定键关联(可选操作)。

   void clear():从此映射中移除所有映射关系(可选操作)。

   boolean containsKey(Object key):如果此映射包含指定键的映射关系,则返回 true。

   boolean containsValue(Object value):如果此映射将一个或多个键映射到指定值,则返回 true。

   V get(Object key):返回指定键所映射的值;如果此映射不包含该键的映射关系,则返回 null。

   boolean isEmpty():如果此映射未包含键-值映射关系,则返回 true。

   V remove(Object key):如果存在一个键的映射关系,则将其从此映射中移除(可选操作)。

   int size():返回此映射中的键-值映射关系数

   Set<K> keySet():返回此映射中包含的键的 Set 视图。

   Collection<V> values():返回此映射中包含的值的 Collection 视图。

   Set<Map.Entry<K,V>> entrySet():返回此映射中包含的映射关系的 Set 视图。

   default void forEach(BiConsumer<? super K, ? super V> action):针对map进行遍历

2、Map集合的遍历

1. 键找值

2. Map集合的遍历方式2:键值对对象

   Map.Entry<K,V>接口

   接口的特点:以key和value封装对象的集合

   接口的位置:Map接口中的Entry<K,V>

   接口的方法

   K getKey():返回与此项对应的键。

   V getValue():返回与此项对应的值。

3. forEach():创建一个BiConsumer内部类,并重写accept()方法

3、HashMap类

1. 类的特点

   1.HashMap集合的底层数据结构是"哈希表"

   ​     JDK7.0(包含)以前:存储链表对象的数组

   ​     JDK8.0(包含)以后:存储链表对象或者红黑树对象的数组

   2.HashMap集合可以存储null值和null键,使用键或值的时候需要进行非空校验,防止空指针异常

   3.HashMap集合是无序的集合,HashMap集合无法保证元素在集合中的位置永远不会改变

   4.HashMap集合是线程不安全的,只适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全

   类的位置:java.util

   类的构造器

   public HashMap()构造一个具有默认初始容量 (16) 和默认加载因子 (0.75) 的空 HashMap。

   类的方法:详见Map接口的常用方法

2. HashMap集合元素存储过程的源码分析(基于JDK8.0):

   1.底层数组的初始容量和初始加载因子

      初始容量和初始加载因子是多少取决于创建对象时的构造器:

   ​       (1)HashMap():  创建对象时不初始化,在第一次添加元素时初始化容量为16, 初始加载因子为0.75

   ​       (2)HashMap(int initialCapacity):  初始容量:自定义      初始加载因子:0.75

   ​       (3)HashMap(int initialCapacity, float loadFactor):  初始容量:自定义      初始加载因子:自定义

   ​       (4)HashMap(Map  m):  初始容量为参数集合的长度, 加载因子为集合长度的加载因子

   2.第一次添加元素时的扩容规则:  16

   3.确认元素在底层数组中的索引位置

   ​       先算key的哈希值,此哈希值在HashMap底层经过了特殊的计算得出
   ​       如果哈希值不一样,直接存
   ​       如果哈希值一样,再去比较内容,如果内容不一样,也存(哈希值一样,内容不一样->哈希冲突(哈希碰撞) )
   ​       如果哈希值一样,内容也一样,直接去重复(后面的value将前面的value覆盖)

​       4.后续添加元素时的扩容规则:    原来底层数组长度 << 1

​       5.底层数组中链表对象何时进行红黑树对象的转换(树化):  链表对象长度达到8且底层数组长度达到64

​       6.底层数组中红黑树对象何时进行链表对象的转换(链表化):  红黑树结构中结点对象的数量降至6个

3. JDK7.0和JDK8.0的区别

     (1)底层数组的桶元素内容不同

   ​        JDK7.0(包含)以前:null,链表对象

   ​        JDK8.0(包含)以后:null,链表对象,红黑树对象

      (2)底层数组的数据类型不同

   ​        JDK7.0(包含)以前:Entry<K,V>[]

   ​        JDK8.0(包含)以后:Node<K,V>[]

      (3)无参构造器底层数组的初始容量不同:

   ​        JDK7.0(包含)以前:16

   ​        JDK8.0(包含)以后:创建对象时没有进行初始化操作,会在第一次添加元素时进行初始化操作,初始容量为16

      (4)hash算法不同:

   ​        JDK7.0(包含)以前:  h ^= k.hashCode();   h ^= (h >>> 20) ^ (h >>> 12);    h ^ (h >>> 7) ^ (h >>> 4);

   ​       JDK8.0(包含)以后:  (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16)

      (5)底层数组的扩容规则:

   ​       JDK7.0(包含)以前:   2 * 原来底层数组长度

   ​       JDK8.0(包含)以后:  原来底层数组长度 << 1

4. 默认的加载因子为什么是0.75?

   默认加载因子 (.75) 在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查询(时间)成本;加载

   因子过低虽然减少了查询(时间)开销,但同时也增加了空间成本;

5. 外面笔试时可能会问到的变量
   default_initial_capacity:HashMap默认容量  16
   default_load_factor:HashMap默认加载因子   0.75f
   threshold:扩容的临界值   等于   容量*0.75 = 12  第一次扩容
   treeify_threshold:链表长度默认值,转为红黑树:8
   min_treeify_capacity:链表被树化时最小的数组容量:64

4、LinkedHashMap类

1. 类的特点

   1.LinkedHashMap集合的底层数据结构是"哈希表+链表"  (链表的作用:维护元素的有序性)

   2.LinkedHashMap集合是有序的集合

   3.LinkedHashMap集合可以存储null值和null键,使用键或值的时候需要进行非空校验,防止空指针异常

   4.LinkedHashMap集合是线程不安全的,只适用于单线程程序,如果在多线程中进行使用,需要手动添加线程安全

   类的位置:java.util

   类的构造器:  public LinkedHashMap():

   ​                              构造一个带默认初始容量 (16) 和加载因子 (0.75) 的空插入顺序 LinkedHashMap 实例。

   类的方法:详见Map接口的常用方法

 5、TreeMap类

1. 类的特点

   1.TreeMap集合底层的数据结构是"红黑树结构"

   2.TreeMap集合可以根据映射关系中键的自然顺序进行排序,或者根据创建映射时提供的 Comparator进行排 

      序,具体取决于使用的构造方法。

   3.TreeMap集合无序的集合

   4.TreeMap集合不可以存储null键,存储时需要针对每个键进行非空校验,防止空指针异常,并且TreeMap集合可   

      以存储null值,但获取时需要针对每个值进行非空校验,防止空指针异常

   5.TreeMap集合是线程不安全的,适用于单线程程序,如果在多线程中进行使用需要手动添加线程安全

2. 类的位置:java.util

   类的构造器

   public TreeMap():使用键的自然顺序构造一个新的、空的树映射。

   public TreeMap(Comparator<? super K> comparator):构造一个新的、空的树映射,该映射根据给定比较器进行排序

3. 类的方法:详见Map集合的常用方法

6、Hashtable类

1. 类的特点

   1.Hashtable集合底层的数据结构是"哈希表"   (哈希表:存储链表对象的数组)

   2.Hashtable集合不可以存储null键和null值,需要在存储元素时进行非空校验,防止空指针异常

   3.Hashtable集合是无序集合,Hashtable集合无法保证元素的顺序永远不会改变

   5.Hashtable集合是线程安全的,适用于多线程程序,如果在单线程中进行使用,执行效率过低

2. 类的位置:java.util

   类的构造器

   public Hashtable():用默认的初始容量 (11) 和加载因子 (0.75) 构造一个新的空哈希表。

3. 类的方法:常见Map集合的常见方法

7、HashMap和Hashtable之间的区别

​     1.null键和null值是否可以存储不同

​          HashMap:可以            Hashtable:不可以

​     2.线程安全性不同

​         HashMap:线程不安全        Hashtable:线程安全

​     3.使用无参构造器创建对象时底层数组的初始容量不同

​         HashMap:

​            JDK7.0(包含)以前:16

​            JDK8.0(包含)以后:先不进行初始化,在第一次添加元素时初始化16

​         Hashtable:11

​     4.底层数组存储桶元素不同

​         HashMap: JDK7.0(包含)以前:null,链表对象

​                          JDK8.0(包含)以后:null,链表对象,红黑树对象 

​         Hashtable:null,链表对象

​     5.底层数组的扩容规则不同:

​         HashMap:

​              JDK7.0(包含)以前: 2 * 原来底层数组长度

​              JDK8.0(包含)以后:  原来底层数组长度 << 1

​          Hashtable:

​              JDK6.0(包含)以前: 原来底层数组长度 * 2 + 1;

​              JDK7.0(包含)以后: (原来底层数组长度 << 1) + 1

 8、Properties类

1. 类的特点:Properties 类表示了一个持久(存储在硬盘中)的属性集(配置文件)。

   类的位置:java.util

   类的构造器

   public Properties():创建一个无默认值的空属性列表。

   类的方法

   public String getProperty(String key):用指定的键在此属性列表中搜索属性。

   public void load(InputStream inStream):从输入流中读取属性列表(键和元素对)。

   public void load(Reader reader):按简单的面向行的格式从输入字符流中读取属性列表(键和元素对)。

   public Set<String> stringPropertyNames():

   ​        返回此属性列表中的键集,其中该键及其对应值是字符串,如果在主属性列表中未找到同名的键,则还包括默认属性列表中不同的键

9、并发和并行:

1. 并发:在同一时间段内发生的多件事情

   并行:在同一时间发生的多件事情

2. 进程和线程:

   CPU核心执行规则:每个核心在所有进程中进行高速无规则的切换动作

   进程:操作系统中的应用程序,每个应用程序至少包含一条进程,程序进程由CPU核心进行控制

   线程:每个进程中的线程,每条进程至少包含一条线程,程序线程由CPU核心中的线程进行控制

 10、Thread类

1. 类的特点:线程是程序中的执行线程

   类的位置:java.lang

   类的构造器

   public Thread():分配新的 Thread 对象。

   public Thread(String name):分配新的 Thread 对象。

   public Thread(Runnable target):分配新的 Thread 对象

   public Thread(Runnable target,String name):分配新的 Thread 对象

   类的方法

   public static Thread currentThread():返回对当前正在执行的线程对象的引用。

   public final String getName():返回该线程的名称。

   public static void sleep(long millis):

   在指定的毫秒数内让当前正在执行的线程休眠(暂停执行),此操作受到系统计时器和调度程序精度和准确性的影响。

   public void run()

   如果该线程是使用独立的 Runnable 运行对象构造的,则调用该 Runnable 对象的 run 方法;

   否则,该方法不执行任何操作并返回。

   public void start():使该线程开始执行;Java 虚拟机调用该线程的 run 方法。

基础20

1、线程的开启方式

线程开启的方式:4种:1.继承Thread类  2.实现Runnable接口   3.实现Callable接口(暂不涉及)   4.线程池(暂不涉及)

1. 线程开启的方式1:继承Thread类

   1.创建Thread类的子类

   2.根据父类生成合适的构造器

   3.重写Thread类的run()

   ​    run():其实就是执行线程对象的执行动作

   4.在测试类中需要多少条执行线程就创建多少个Thread类的子类对象

   5.开启线程

   线程开启方式1的弊端: 单继承局限性

2. 线程开启方式2:实现Runnable接口(也可以通过匿名内部类的方式开启)

   1.创建Runnable接口的实现类

   2.重写Runnable接口中的抽象方法run()

   3.创建Runnable接口的实现类对象

   4.需要多少条线程,就将Runnable接口实现类对象作为参数创建多少个线程对象

   5.开启线程

2、线程安全问题

1. 线程安全问题

   1.同一数据被获取或操作多次

   2.出现了非法数据

2. 线程安全问题的解决方式:

   1.同步代码块(同步方法只是特殊形式的解决方案或者同步代码块的简化方式)

   2.Lock锁(暂不涉及)

   synchronized关键字: 同步

   修饰:同步代码块,同步方法

   特点:被synchronized关键字修饰的同步代码块或同步方法,同一时间只能被一条线程所执行,其它线程如果想执行,需要在同步代码块或同步方法外进行"阻塞"

3. 同步代码块:被synchronized关键字修饰的代码

   格式:

   synchronized (同步对象) {

   可能出现线程安全的代码  }

   特点:

   ​    同步代码块同一时间只能被一条线程所执行,其它线程在同步代码块外进行"阻塞",同步代码中的线程执行完毕后,再进行资源抢夺,如果抢夺到资源,执行同步代码块,如果没有抢夺到资源,继续"阻塞"

   注意:

   ​    1.多条线程执行同一个同步代码块,同步代码块中的同步对象必须是相同的,如果不同,无法保证线程安全

   ​    2.多条线程处理同一数据资源对象

   ​          如果多条线程执行动作相同,同步对象就是多条线程同一动作对象(this)

   ​          如果多条线程执行动作不同,同步对象就是多条线程处理的同一数据资源对象(同一资源对象)

   ​          如果多条线程执行动作是相同的静态方法,同步对象就是该动作所属类的字节码文件对象(类的字节码文件对象)

4. 同步方法:  被synchronized关键字修饰的方法

   特点: 同步方法在同一时间只能被一条线程所调用,该同步方法没有执行完毕前,其它线程无法进行调用,需要在外进行"阻塞"

   格式:

   修饰符 synchronized 返回类型 方法名 () {

   可能出现线程安全的代码  }

   注意:

   ​    1.当多条线程执行的动作相同时,可以使用同步方法进行同步代码块的简化;当多条线程执行的动作不同时,现阶段必须使用同步代码块解决线程安全问题

   ​    2.同步方法的权限访问级别推荐使用private

3、线程间通信

1. 线程间通信(等待唤醒机制):让多条线程间通过"等待"和"唤醒"产生通信,从而让线程可以按照一定的规则进行执行

   方法:

   public final void wait()

   ​    在其他线程调用此对象的 notify() 方法或 notifyAll() 方法前,导致当前线程等待。

   public final void notify()

   ​    唤醒在此对象监视器上等待的单个线程。

   public final void notifyAll()

   ​    唤醒在此对象监视器上等待的所有线程。

   分类:

   ​    生产者线程:负责生产同一资源对象的线程

   ​    消费者线程:负责消费同一资源对象的线程

2. 单例设计模式的线程安全问题可以在出现线程安全问题的地方添加同步代码块或者同步方法

3、线程面试题

1. 多线程的面试题1:Java中线程的状态分为几种?分别是?

   正确答案:6种

   分类:

   NEW(新建):线程对象被创建,但没有执行start()的状态

   RUNNABLE(运行):线程正常运行的状态

   BLOCKED(阻塞):线程遇到线程安全处理,但线程对象并没有抢夺到同步对象或锁对象资源的状态

   WAITING(无限等待):线程对象被执行wait()状态

   TIMED_WAITING(计时等待):线程对象被执行sleep()状态

   TERMINATED(终止):线程对象执行完毕,在内存中被垃圾回收器回收的状态

2. Java中线程如何进行状态的转化?

   新建状态的转换:被执行start()时可以转换成"运行"状态:

   运行状态的转换:

   ​    1.线程对象遇到线程安全处理,但线程对象并没有抢夺到同步对象或锁对象资源时会转换为阻塞状态

   ​    2.线程对象被执行wait()转换成"无限等待"状态: 

   ​    3.线程对象被执行sleep(时间参数)或wait(时间参数)转换成"计时等待"状态

   ​    4.线程对象执行完毕,在内存中被垃圾回收器回收时转换成"终止"状态

   阻塞状态的转换:进行线程安全处理的线程对象执行完毕,而当前线程对象抢夺到同步对象或锁对象资源时转换成"运行"状态

   无限等待状态的转换:

   ​    1.当有线程安全处理时:进行线程安全处理的线程对象执行完毕并当前线程对象被执行notify()或notifyAll(),且当前线程对象抢夺到同步对象或锁对象资源时转换成"运行"状态,如果没有抢到则转换成"阻塞"状态

   ​    2.当没有线程安全处理时:当前线程对象被执行notify()或notifyAll()时转换成"运行"状态

   计时等待状态的转换:

   ​    1.当有线程安全处理时:规则时间到( wait(时间参数)在时间内被执行notify()或notifyAll() ),当前线程对象抢夺到同步对象或锁对象资源时转换成"运行"状态,如果没有抢夺到则转换成"阻塞"状态

   ​    2.当没有线程安全处理时:规则时间到( wait(时间参数)在时间内被执行notify()或notifyAll() )时转换成"运行"状态

基础21

 1、Commons-io工具包

1. 使用步骤

   导入jar包并解压(jar包都是以.class文件形式存在的)

2. 常用方法

   IOUtils类中的方法:

   ​    IOUtils.copy(InputStream in, OutputStream out):传递字节流,实现文件的复制

   FileUtils类中的方法:

   ​    FileUtils.copyDirectoryToDirectory(File src, File dest): 进行整个目录的复制

   ​         src:要复制的文件的路径   dest:要将文件夹粘贴到哪里去

   ​     FileUtils.writeStringToFile(File file, String str):写字符串到文本中

   ​     FileUtils.readFileToString(File file):读取文本文件,返回字符串

2、网络编程

1. 软件结构

   CS:客户端服务器结构

   BS:浏览器服务器结构

2. 服务器概念:安装了服务器软件的高性能计算机

3. 网络通信协议:两台计算机在做数据交互时要遵守的规则,协议会对数据的格式,速率等进行规定,只有都遵守了这个协议,才能完成数据交互

3、通信三要素

1. IP地址:指互联网协议地址,是计算机的唯一标识

   ​    作用:用于计算机之间的连接

   ​    常用dos命令  : ipconfig: 查看ip地址     ping ip:测试是否能连接其他计算机的命令

2. 协议 

   1. TCP:面向连接协议:需要先确认连接,才能进行数据交互
          三次握手:
               第一次握手,客户端向服务器端发出连接请求,等待服务器确认。
               第二次握手,服务器端向客户端回送一个响应,通知客户端收到了连接请求。
               第三次握手,客户端再次向服务器端发送确认信息,确认连接。

      ​         四次挥手:

      ​               第一次挥手:客户端请求结束连接,让服务器做最后准备,此时的客户端不在发送数据,但是                    可以接收数据

      ​               第二次挥手:服务器接收到客户端释放连接的请求后,会将最后的数据发给客户端。并告知上层的应用进程不再接收数据。

      ​                第三次挥手:服务器发送完数据后,会给客户端发送一个释放连接的报文。那么客户端接收后就知道可以正式释放连接了。

      ​                 第四次挥手:客户端接收到服务器最后的释放连接报文后,要回复一个彻底断开的报文。

      ​           好处:数据安全,能给数据的传输提供一个安全的传输环境
      ​           坏处:效率低

      UDP:面向无连接协议
               好处:效率高
               坏处:传输的数据不安全,容易丢失数据包

3. 端口号:每一个应用程序的唯一标识(用于确认连接方)

   ​    用两个字节表示的整数,它的取值范围是0~65535。其中,0~1023端口号已被占用,普通的应用程序需要使用1024以上的端口号。如果端口号被另外一个服务或应用所占用,会导致当前程序启动失败

4. 客户端和服务端的交互

5. 客户端和服务端的实现

   客户端:
        1.创建Socket对象,指明要连接的服务器的IP和端口号
        2.调用Socket对象中的getOutputStream,获取OutputStream,用于往服务端发请求(写数据)
        3.调用Socket对象中的getInputStream,获取InputStream,用于读取服务端响应回来的数据(读数据)
        4.关流

   服务端:

   ​      1.创建ServerSocket对象,设置端口号
   ​      2.调用ServerSocket中的accept方法,等待和获取客户端连接,返回Socket
   ​      3.调用Socket中的getInputStream,用于读取客户端发来的请求数据
   ​      4.调用Socket中的getOutputStream,用于往客户端写响应信息
   ​      5.关流

4、文件上传的实现

1. 实现流程(文件)及图解:本地硬盘(FileInputStream)—>客户端(getOutputStream)—>服务端(getInputStream)—>服务器硬盘(FileOutputStream)

2. 具体实现步骤:

   ​    客户端:

   ​         1.实现与服务端的连接

   ​         2.通过FileInputStream读取本地硬盘中的文件,再通过Socket的getOutputStream进行边读边写发送到服务器端,并在读完后给服务器发送一个结束标志socket.shutdownOutput()。

   ​     服务端:

   ​          1.实现与服务端的连接

   ​          2.使用Socket的getInputStream读取客户端写入得文件,再通过FileOutputStream进行边写边读写入到服务器端的硬盘中

3. 线程版的网络编程:将网络编程的动作封装到run方法中即可

5、BS结构架构服务器

1. 实现流程及图解:浏览器端发送请求—>服务器端读取该请求并解析出文件路径—>读取该文件路径上的文件—>先返回指定格式—>将读到的文件响应给浏览器(写到浏览器端)

2. 具体实现步骤

   浏览器端:输入访问的路径

   服务器端:使用缓冲字符流new BufferedReader(new InputStreamReader(socket.getInputStream() ) )读取浏览器端发送的请求的第一行,通过FileInputStream读取指定路径上的文件,用socke的getOutputSteam发送到浏览器端(写入到浏览器端)

基础22

1、函数式编程思想

1. 面向对象思想:很多事情自己不想做,很多事情自己不想做,调用别人的功能帮我去做事
       为什么要创建对象,因为我们不创建对象,就调用不了这个对象的功能
       过程:new对象    目的:使用对象中的方法
2. 函数式编程思想:
   只注重目的(方法),不注重过程(new对象),谁不注重,就可以干掉谁

2、lambda表达式

1. 格式:( ) —> { }     ( ):重写方法的参数位置   —>:将参数传递到方法体中  { }:重写方法的方法体位置

2. 使用前提:函数式接口做为方法参数传递

   ​     函数式接口:有且只有一个抽象方法的接口,并可以用@FunctionalInterface注解标注 

3. 省略规则

   1.重写方法的参数类型可以省略
   2.如果重写方法只有一个参数,那么类型可以干掉,所在的小括号也可以干掉
   3.如果重写方法的方法体只有一句话,所在的方法体大括号可以干掉,方法体中的那一句分号可以干掉
   4.如果重写方法的方法体只有一句话,且还是带return的,那么return,方法体的大括号,分号都可以干掉

   ​      注意:1.观察是否是函数式接口做为方法参数传递

   ​                  2.如果是,考虑用lambda表达式
   ​                  3.调用方法,传递实参的时候,写成匿名内部类的形式
   ​                  4.从new接口开始,到重写方法的方法名直接删除
   ​                          (不要忘记将右半个大括号也干掉)
   ​                  5.在重写方法的参数后面,方法体前面加上  ->
   ​                  6.再看看能不能根据省略规则再次删一删

 3、常用函数式接口

1. Supplier接口
   java.util.function.Supplier<T>接口,它意味着"供给"->我们想要什么就给什么
   方法:T get()
   3.需求:使用Supplier接口作为方法的参数
               用Lambda表达式求出int数组中的最大值

2. Consumer

   java.util.function.Consumer<T>->消费型接口
     方法:   void accept(T t),意为消费一个指定泛型的数据
    "消费"即"操作"

3. Function

   java.util.function.Function<T,R>接口用来根据一个类型的数据得到另一个类型的数据
   方法: R apply(T t)根据类型T参数获取类型R的结果

4. Predicate

   java.util.function.Predicate<T>接口。->判断型接口

 4、Stream流

1. Stream流:相当于一条操作数组和集合中数据的流水线

2. Stream流的获取

   1.针对数组:  static <T> Stream<T> of(T... values)  
   2.针对集合:在Collection中有一个方法    Stream<E> stream() 

3. Stream中的方法

   void forEach(Consumer<? super T> action):遍历(此方法为流中的终结方法)

   ​     终结方法:调用终结方法后当前流对象就不可以再进行操作

   long count(): 统计元素个数(此方法为终结方法)

   Stream<T> filter(Predicate<? super T> predicate):根据某个条件进行元素过滤并返回一个新
         的Stream流对象

   Stream<T> limit(long maxSize):获取Stream流对象中的前n个元素,返回一个新的Stream流对象

   Stream<T> skip(long n): 跳过Stream流对象中的前n个元素,返回一个新的Stream流对象

   static <T> Stream<T> concat(Stream<? extends T> a, Stream<? extends T> b):两个流合成一个流

   collect():转换成集合对象(可转为Collection、Set、List)

 5、方法引用

1. 概述:在lambda表达式简化格式的基础上再次简化
   前提:条件更苛刻
     a.被引用的方法,必须写在重写的方法中
     b.被引用的方法,从参数上,返回值上,参数个数上,参数类型上都要和所在的重写的方法保持一致
   怎么引用:
     在lambda表达式最简化的基础上-> 干掉参数,干掉->,干掉被引用的方法参数将.换成::

2. 使用对象名引用成员方法
       格式:  对象::成员方法名

3. 引用静态方法

   ​       格式:   类名::静态方法名

4. 构造引用

   ​       格式: 构造方法名::new

5. 数组创建:    int[] arr = new int[3]
   可以变相的将:   int看成方法名    [3]看成方法参数    int[]看成返回值类型    
   数组引用:
     数组类型[]::new
     int[]::new  创建一个int型的数组

基础23

 1、Junit单元测试

1. 概述: Junit是一个Java语言的单元测试框架,简单理解为在一定程度上用于取代main方法, Junit属于第三方工具,需要导入jar包后再使用

2. 作用:可以单独去运行一个我们想要测试的功能,不用提供main方法了

3. Junit的基本使用

   1.注意:需要在方法上写,不要在类上写
          @Test
   2.怎么执行单元测试的方法:
     a.选中要执行的方法名,右键->run
     b.选择方法左边的绿色小箭头->run
     c.如果想要执行当前类中所有带@Test的单元测试方法,点类名左边绿色小箭头->run

4. Junit的注意事项

   ​     1.@Test修饰的方法,不能有参数和返回值
   ​     2.@Test修饰的方法,不能是静态的
   ​            一般情况下,我们都会单独定义一个方法,在此方法中使用单元测试,在方法体中调用要测试的方法

5. Junit相关注解

   @Before:在@Test之前执行,有多少个@Test一起执行,@Before就执行多少次-> 可以用来初始化一下参数
   @After:在@Test之后执行,有多少个@Test一起执行,@After就执行多少次->可以用来关闭资源

6. @Test以后怎么使用

   1.直接执行一个要被测试的方法,可以直接在该方法上加@Test
   2.单独创建一个测试类,专门测试某一个模块的功能
     在测试类中定义测试方法,加上@Test.在方法中调用要测试的模块功能

2、类的加载时机

1. new对象的时候
   new子类对象(new子类对象,先初始化父类对象)
   执行main方法
   调用该类中的静态成员
   利用反射,获取此类的class对象

2. 类的加载时机

3. 类加载器(不同的类加载器负责加载不同的类)

   1.概述:在jvm中,负责将本地上的class文件加载到内存的对象_ClassLoader(父类)

   2.分类:

   ​        BootStrapClassLoader:根类加载器->C语言写的,我们是获取不到的
   ​                 也称之为引导类加载器,负责Java的核心类加载的
   ​                  比如:System,String等
   ​                  jre/lib/rt.jar下的类都是核心类

   ​         ExtClassLoader:扩展类加载器
   ​                  负责jre的扩展目录中的jar包的加载
   ​                  在jdk中jre的lib目录下的ext目录
   ​          AppClassLoader:系统类加载器
   ​                  负责在jvm启动时加载来自java命令的class文件(自定义类),以及classPath环境变量所指 定的jar包(第三方jar包)

   ​          三者的关系:AppClassLoader的父类加载器是ExtClassLoader
   ​                              ExtClassLoader的父类加载器是BootStrapClassLoader

   ​          但是:他们从代码级别上来看,没有子父类继承关系->他们都有一个共同的父类->ClassLoader

4. 加载过程

   1.获取类加载器对象
     类名.class.getClassLoader()

   2.获取类加载器对象对应的父类加载器
     ClassLoader类中的方法:ClassLoader      
     getParent()->没啥用

   3.双亲委派(全盘负责委托机制)

      a.Person类中有一个String
        Person本身是AppClassLoader加载
        String是BootStrapClassLoader加载
      b.加载顺序:
        Person本身是App加载,按道理来说String也是App加载
        但是App加载String的时候,先问一问Ext,说:Ext你加载这个String吗?
        Ext说:我不加载,我负责加载的是扩展类,但是app你别着急,我问问我爹去->boot
        Ext说:boot,你加载String吗?
        boot说:正好我加载核心类,行吧,我加载吧!

   ​     比如:
   ​         class Test{
   ​             new Person()
   ​         }
   ​         a.Test是app加载,person按理来说也是app加载,但是app先问ext要不要加载
   ​            ext说不负责加载自定义类,我找boot去,boot一看,我不负责加载自定义类->perosn
   ​            app一看,两个爹都不加载,我自己加载
   ​         b.结论:两个双亲都不加载,app才自己加载
   ​             比如:如果来了一个DNSNameService,我就想直接加载DNSNameService(扩展类),
   ​     本身ext要加载,但是先问boot,如果boot不加载,ext再加载

   ​    4.类加载器的cache(缓存)机制(扩展):一个类加载到内存之后,缓存中也会保存一份儿,后面如果再使用此类,如果缓存中保存了这个类,就直接返回他,如果没有才加载这个类.下一次如果有其他类在使用的时候就不会重新加载了,直接去缓存中拿,所以这就是为什么每个类只加载一次,内存中只有一份儿的原因
   ​    5.所以:类加载器的双亲委派和缓存机制共同造就了加载类的特点:每个类只在内存中加载一次

3、反射

1. Class类和Class对象

   小结:  1.class对象:jvm为加载到内存的class文件创建出来的对象

   ​           2.class类:描述class对象的类就叫做class类

   ​           3.反射:  解剖class对象

   ​           4.解剖出点啥呀?

   ​               a.成员变量(Field)  -> 赋值

   ​               b.构造方法(Constructor) -> new对象

   ​               c.成员方法(Method)->调用

2. 获取Class对象

   1. 1.方式1:调用Object类中的方法:   getClass()
      2.方式2:java为每一个类型(基本,引用),都提供了一个静态成员  :   class
      3.方式3:使用Class类中的一个方法:static Class<?> forName(String className) 
                                                                              className:类的全限定名 -> 包名.类名  

      ​           三种获取Class对象的方式最通用的一种

      ​           1.static Class<?> forName(String className)
      ​                       className:类的全限定名 -> 包名.类名  
      ​           2.为啥:因为参数为字符串类型,可以配合properties文件使用
      ​           3.如何创建properties配置文件:右键->选择new -> file -> xxx.properties
      ​           4.properties配置文件内容写法:
      ​               a.必须是key=value形式
      ​               b.key和value都是String类型,但是不要加双引号
      ​               c.每一个key=value写完要换行写下一对key=value
      ​               d.不要有空格和中文

   2. 获取Class对象中的构造方法

      1. 获取所有public的构造方法

         Class类中的方法: Constructor<?>[] getConstructors() -> 获取所有的public的构造方法

      2. 获取空参构造_public

         Class类中的方法:
           Constructor<T> getConstructor(Class<?>... parameterTypes) ->获取指定构造 
                                          parameterTypes:可变参数,可以传递0个或者多个参数
                                          如果获取空参构造:parameterTypes不写了
                                          如果获取有参构造:parameterTypes写的是构造参数类型的class对象                        Constructor类中的方法:
           T newInstance(Object... initargs)  -> 根据获取出来的Constructor创建对应的对象
           参数说明:initargs->可变参数 -> 可以传递0个或者多个参数,传递的是实参

      3. 利用空参构造创建对象的快捷方式_public

         Class类中的方法:
          T newInstance()-> 根据空参构造创建对象
         前提:被反射的类中须有空参构造

      4. 利用反射获取有参构造并创建对象_public

         Class类中的方法:
           Constructor<T> getConstructor(Class<?>... parameterTypes) ->获取指定构造 
                                          parameterTypes:可变参数,可以传递0个或者多个参数
                                          如果获取空参构造:parameterTypes不写了
                                          如果获取有参构造:parameterTypes写的是构造参数类型的class对象                              Constructor类中的方法:
           T newInstance(Object... initargs)  -> 根据获取出来的Constructor创建对应的对象
           参数说明:initargs->可变参数 -> 可以传递0个或者多个参数, 传递的是实参

      5. 利用反射获取私有构造(暴力反射)

         获取所有的构造->包含public的,也包含private的
         Class类中的方法:
           Constructor<?>[] getDeclaredConstructors()  ->  获取所有构造,包含private

         获取指定的构造->包含private
         1.class类中的方法:
           Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes)  
                                          parameterTypes:可变参数,可以传递0个或者多个参数
                                          如果获取空参构造:parameterTypes不写了
                                          如果获取有参构造:parameterTypes写的是构造参数类型的class对象                                 2.Constructor类中的方法:
           T newInstance(Object... initargs)   -> 根据获取出来的Constructor创建对应的对象
           参数说明:initargs->可变参数 -> 可以传递0个或者多个参数
                  传递的是实参
               
         3.获取出私有成员,不能直接使用,但是我们是反射技术,这个技术太吊了,既然能获取,就一定能使用
           Constructor有一个父类->AccessibleObject
         4.AccessibleObject类中有一个方法:
           void setAccessible(boolean flag)  -> flag如果设置为true -> 解除私有权限(暴力反射)

   3. 获取Class对象中的方法

      1. 利用反射获取所有public成员方法

         Class类中的方法:->都是public的->连父类中的public方法都能拿到
           Method[] getMethods()

      2. 反射之获取public方法(有参,无参)

         1.Class类中的方法:
            Method getMethod(String name, Class<?>... parameterTypes)  
                             name:要获取方法名
                             parameterTypes:指定方法具体的参数类型,是一个Class对象  
                                            如果获取的方法没有参数,此处空着                   
         2.Method类中的方法:
           Object invoke(Object obj, Object... args)  ->执行被反射出来的方法

         ​              如果是实例方法,obj为方法所在类的对象,静态方法obj为方法所在类的类名.class

         ​                a.参数说明:
         ​                 obj:根据构造创建出来的对象
         ​                 args:传递的是实参 如果调用的方法没有参数,args就不写了
         ​               b.返回值说明:Object
         ​                 接收的是被调用方法的返回值
         ​                 如果调用的方法没有返回值,那么就不用Object接收了
         ​                 如果调用的方法有返回值,那么就用Object接收一下吧

   4. 反射之获取所有(包括private)方法

      getDeclaredMethords()

   5. 反射之获取单个(包括private)方法

      getDeclaredMethod(String name, Class<?>... parameterTypes)

3. 获取Class对象中的成员变量

   1. 获取单个public成员变量

      getField(String name) 
             返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。

   2. 获取多个public成员变量

      getFields() 
             返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。

   3. 获取单个成员变量(包括私有)

      getDeclaredField(String name) 
             返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。

   4. 获取多个成员变量(包括私有)

      getDeclaredFields() 
                返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。

4、反射练习

1. 利用反射,解析配置文件中的信息:properties文件
   类的全限定名:  className=包名.类名
   方法名:       methodName=方法名
   需求:利用反射解析properties文件,获取配置信息
       根据配置信息,执行配置文件中的方法
   步骤:
     1.创建Properties配置文件,写配置信息
       a.问题1:配置文件将来要放到哪里?
         我们将来给用户的都是out路径下的class文件,如果我们将配置文件直接放到模块下,out路径下是没有配置文件生成的,那么将class文件给用户,用户一执行,发现找不到配置文件中的数据,肯定执行不了   
       b.解决问题1:我们应该将配置文件放到src下   
       c.问题2:如果将配置文件放到src下,你怎么写读取路径
         FileInputStream in = new FileInputStream("day23_reflect\\src\\bean.properties");
       d.解决问题2:类加载器
         ClassLoader classLoader = 当前类.class.getClassLoader()
         classLoader.getResourceAsStream("配置文件名称.后缀名") -> 自动扫描src下的配置文件
       e.问题3:将来我们可能有很多很多配置文件,难道我们都要放到src下吗?这样不乱吗?
       f.解决问题3:在当前模块下创建一个文件夹,取名为:resources -> 将其变成源目录->将配置文件放到此路径下
     2.利用Properties集合配合IO流解析配置文件,将配置文件中的value获取出来
     3.根据配置文件中的类的全限定名获取Class对象
     4.根据配置文件中的方法名反射对应的方法
     5.调用invoke执行该方法

5、注解

1. 注解简介

   1.jdk1.5版本的新特性->一个引用数据类型和类,接口,枚举是同一个层次的
         引用数据类型:类 数组  接口 枚举 注解
   2.作用:
          说明:对代码进行说明,生成doc文档(API文档)(不会用)
          检查:检查代码是否符合条件   @Override(会用) @FunctionalInterface
          分析:对代码进行分析,起到了代替配置文件的作用(会用)        
   3.JDK中的注解:
          @Override  ->  检测此方法是否为重写方法
             jdk1.5版本,支持父类的方法重写
             jdk1.6版本,支持接口的方法重写
          @Deprecated -> 方法已经过时,不推荐使用
                         调用方法的时候,方法上会有横线,但是能用
          @SuppressWarnings->消除警告  @SuppressWarnings("all")

2. 注解的定义以及属性的定义格式

   1.定义格式:
     public @interface 注解名{  }
   2.定义属性(增强注解作用)
     数据类型 属性名()   -> 不带默认值,需要在使用注解的时候给此属性赋值
     数据类型 属性名() default 值 -> 带默认值的,在使用注解的时候无需单独为其赋值,要是想赋新的值,也可以赋
   3.注解中能定义什么类型的属性呢?
     a.8种基本类型(byte short int long  float double char boolean)
     b.String类型 class类型 枚举类型 注解类型
     c.以上类型的一维数组

3. 注解的使用(重点)

   1.使用注解(实质上就是为注解中的属性赋值)
   2.使用位置:
     类上,方法上,参数上,属性上,构造上 等
   3.怎么使用:
     @注解名(属性名 = 值,属性名 = 值)
     @注解名(属性名={元素1,元素2})  

   注解注意事项:
         1.空注解可以直接使用->空注解就是注解中没有任何的属性
         2.不同的位置可以使用一样的注解,但是同样的位置不能使用一样的注解
         3.使用注解时,如果此注解中有属性,注解中的属性一定要赋值,如果有多个属性,用,隔开
           如果注解中的属性有数组,使用{}
         4.如果注解中的属性值有默认值,那么我们不必要写,也不用重新赋值,反之必须写上
         5.如果注解中只有一个属性,并且属性名叫value,那么使用注解的时候,属性名不用写,直接写值
           (包括单个类型,还包括数组)

4. 注解解析的方法->AnnotatedElement接口

   解析思想:
      1.获取Class对象,或者Method对象
      2.判断类上或者方法上有没有注解
      3.如果有注解,获取注解
      4.获取到注解就可以获取注解中的属性值

   1.什么叫解析注解:将注解中的属性值获取出来
   2.使用:  AnnotatedElement接口
           实现类:Method,Field,Constructor,class等      
   3.解析方法:
     boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)->判断对应的位置上有没有注解
              annotationClass:写的是注解的class对象        
     a.比如:判断BookShelf类上有没有Book注解:
           Class class = BookShelf.class
           class.isAnnotationPresent(Book.class)
     getAnnotation(Class<T> annotationClass)->获取指定的注解
              annotationClass:写的是注解的class对象
     a.比如:获取BookShelf类上的Book注解:
       Class class = BookShelf.class
       class.isAnnotationPresent(Book.class)
       class.getAnnotation(Book.class)

 6、元注解

1. 概述

   1.概述:管理注解的注解
   2.元注解都是从哪些方面管理注解
     a.使用位置上:控制注解是否能在类上使用,是否能在方法上使用,是否能在参数上使用等
     b.生命周期上:控制注解只存在在源码中,控制注解是否能存在在class文件中,控制注解是否能存在在内存中  

2. 常见的元注解:
   a.Target:控制注解能放到哪个位置上
     ElementType[] value()-> ElementType是一个枚举类->枚举类中的成员可以类名直接调用
     TYPE:控制注解能使用在类上
     FIELD:控制注解能使用在成员变量上
     METHOD:控制注解能使用在方法上
     PARAMETER:控制注解能使用在参数上
     CONSTRUCTOR:控制注解能使用在构造上
     LOCAL_VARIABLE:控制注解能使用在局部变量上  
   b.Retention:控制注解的生命周期
     RetentionPolicy value();->RetentionPolicy是一个枚举类->枚举类中的成员可以类名直接调用
     SOURCE:控制注解只能在源码中出现 -> 默认
     CLASS:控制注解可以在class文件中
     RUNTIME:控制注解可以在内存中

  • 32
    点赞
  • 229
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值