java基础

javaSE总结

开发环境搭建

常用dos命名及系统快捷指令

  1. dos 命令

    • 键盘

      image-20220305105405264
    • 打开运行窗口

    • 常见命令

      • win + r //打开cmd

        image-20220305105503765
      • ipconfig //查看ip

        image-20220305105716692
      • cls //清屏

        image-20220305105828427
      • ping //查看ip 通否

        image-20220305110059518
      • p盘符:去对应的盘符

        image-20220305110211828
      • cd javase 去 javase 目录

        image-20220305110412379
    • 系统常见快捷键

      • win + e 打开我的电脑
      • win + d 快速回到桌面
      • win + L 锁屏
      • alt + tab 切换窗口

jdk安装

  1. jdk 安装

    image-20220305113934479 image-20220305114058161 image-20220305114117047 image-20220305114141432

环境变量

  1. 环境变量的配置

    • 此电脑-右键属性-高级系统设置-环境变量-配置 JAVA_HOME-配置path-%JAVA_HOME%\bin

    • 测试 java -version javac -version

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NWkOEFtU-1664677606209)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220305114633055.png)]

jdk 与 jre 关系

  1. jdk: 它是java的开发运行环境,开发人员需要安装jdk
  2. jre: java runtime environment(java 运行环境),如果只需要运行程序,不需要开发,可以只安装jre
  3. jdk 包含了 jre

java 加载和执行的过程

  1. 图解

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rRjcpIud-1664677606211)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220305115710659.png)]

  2. java 源文件:程序员编写的,扩展名是以.java 结尾的

  3. 编译:通过 javac 把java源文件编译成字节码文件(.class结尾)

  4. 运行:通过解释器(java)运行字节码文件

  5. 需要用到 dos 命令

基础语法

Java注释,关键字,标识符

java 注释
  1. 通常我们需要在源代码中添加文字去描述我们代码的作用,做一个解释说明,直接写就会报错,所以我们就可以用java 的注释来解决这一问题
  2. java 提供了三种注释方式:
    • 单行注释 //注释内容
    • 多行注释 /* 注释内容 */
    • 文档注释 /** 注释内容 */
关键字

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vHgeN57h-1664677606211)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220305140547701.png)]

  1. 关键字是我们 JAVA语言一些特殊的字母,具有特殊含义,java 中关键字是小写字母开头
标识符
  1. 标识符就是名称的意思,定义类,包,方法,变量名,目的是有一个号的命名。

  2. 标识符的组成:

    • 英文的大小写字母 a-z A-Z
    • 数字 0-9
    • 符号 _ 与 $
  3. 标识符规则

    • 数字不能打头

    • 不可以使用关键字

    • 严格区分大小写,做到见名知意

    • 驼峰命名法(类名第一个单词的首字母大小,其它单词的首字母也大小)

      public class StudentTest{
        //驼峰命名法  
      }
      

数据类型

基本数据类型
四类八种字节数数据范围
整型byte1-128-127
short2-32768~32767
int4-2147483648~2147483648
long8-263~263-1
浮点型float(f,F)4-3.403E–3.403E
double(d,D)8
字符型char2‘a’,‘A’,‘1’
布尔型boolean1true,false
引用数据类型
  • String (字符串)
  • 其它的引用数据类型(数组,类)
基本数据强制类型转换
  1. 需求:定义一个byte 类型的数,并且给一个值为300;

  2. 问题

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-HFlyADNa-1664677606212)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220305164005821.png)]

  3. 解决:强制类型转换前面加上(数据类型)

    byte b = (byte)300;
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EcUr4UGX-1664677606213)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220305164131467.png)]

变量

定义格式:

数据类型 变量名 赋值符号 数值
   int   num    =     10;

常量

定义:永远不会变的量,10,10.3,1000L

public class ConstantDemo{
    public static void main(String[] args){
        
        System.out.println(10);
        //之前定义的变量,前面加 final 关键字以后就变成常量
        final int num = 10;
    }
    
}

注意:使用 final 修饰的变量也是常量,并且不能重新赋值

运算符

算术运算符
  1. 运算符用来计算数据的,数据可以是常量,也可以是变量,被我们运算符操作的数,我们称之为操作数

  2. 算术运算符+、-、*、/、%、++、–

    运算符运算规则例子结果
    +正号+1010
    +加法10+1222
    +连接符“名字:”+“上云”名字:上云
    -负号-10-10
    -减法20 - 1010
    *乘法10*220
    /6/3(5/2)2
    %取模5%21
    ++自增int a = 1;a++/++a;2
    自减int b = 2; b–/–b;1

    注意:

    • 前置++ 先+1 后运算(后做操作),后置++ 先操作后+1;
    • 前置-- 变量先-1,后操作,后置-- 先操作,变量后-1;
赋值运算符
  1. 赋值运算符,用来为变量赋值的。=、+=、-=、*=、/=、%=

    运算符运算规则例子结果
    =赋值符号int a = 10;10
    +=加后赋值int a = 10; a+=2;(a = a+2)12
    -=减后赋值int a = 10; a-=2;8
    *=乘后赋值int a = 10;a*=2;20
    /=除后赋值int a = 10;a/=5;2
    %=取模后赋值int a = 10;a%=3;1
关系运算符
  1. 关系运算符又叫比较运算符,用来判断两个操作数大小关系,以及是否相等,结果是我们boolean 类型,true false

    运算符运算规则例子结果
    >大于5 > 3true
    >=大于或者等于5>=5true
    <小于5<3false
    <=小于等于3<=4true
    ==等于3==3true
    !=不等于3!=4true
  2. 注意:赋值运算的 = 和关系运算符的 == 是有区别的,= 是做赋值, == 是做判断比较。

    int a = 5;
    int b = 10;
    System.out.println( a == b);
    System.out.println(a = b);
    
逻辑运算符
  1. 逻辑运算符,用与 boolean 类型的值进行运算比较的。最终结果 true 或者是 false(按住 shift + 对应符号)

    运算符运算规则例子结果
    &与(两者为真)true & falsefalse
    |或(有一个真即为真)true | falsetrue
    非(取反)!truefalse
    ^异或(两者不同即为真)true ^ falsetrue
    &&短路与false && truefalse
    ||短路或true || falsetrue
    ^异或做二进制运算二进制无进位相加
条件运算符

boolean ? 值1:值2;

true?"你好""不好";
image-20220327005941105
位运算符

当你使用数字操作位运算符时,是使用二进制操作的。

位运算符(1=true,0=false):

  • &(与) 1&1=1,1&0=0

  • |(或)1|1=1,1|0=1,0|0=0

  • ^(异或) 11=0,10=1,0^0=0

  • 〜(取反) 1=0,0=1(二进制元素位)

    0000 0001
    1111 1110
    
  • << (左移)左移一位相当于乘以2,右移一位相当于除以2

    0000 0001
        <<2
    0000 0100
        
        >>1 右移
    0000 0010
        >>1
    0000 0001
    无符号右移 >>>
    
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DUgdJARq-1664677606214)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220327012537641.png)]

条件与循环语句

选择结构 if
  1. if 的定义

    if(boolean){
        //如果条件是 true执行代码块
    }
    //需求 如果考试得了一百分,奖励手机
    
    image-20220306150555087
  2. if…else 语句

    //定义
    if(boolean){
        //语句块1
    }else{
        //语句块2
    }
    //如果条件满足,执行语句块1,否则执行语句块2
    
    //需求:如果考试得100奖励一个手机,否则,家庭作业翻倍
    
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-kjnnU31O-1664677606215)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220306153110197.png)]

  3. if … else if… else if …else(只选其中一条路走)

    //语法定义
    if(boolean){
        //语句块1
    }else if(boolean){
        //语句块2
    }else if(boolean){
        //语句块3
    }else{
        //语句块4
    }
    
    //需求:考90分以上 等级A,[80-90) B  [70-80) c [0-70)d
    
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nYaYDYRh-1664677606216)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220306153125865.png)]

注意:最多只有一个分支执行,如果有 else 那一定分支执行

选择结构 Switch
  1. 定义

    switch(表达式){
     case 目标值:
         执行语句
         break;
     case 目标值:
         执行语句
         break;
     case 目标值:
         执行语句
         break;
        default:
            执行语句
    }
    
    //需求:int week = 1;1 打印星期1,2打印星期2 7打印星期天
    
循环结构
while 循环
  1. 循环:重复相同的步骤

    //定义
    while(boolean){
        代码块
    }
    
    //需求1:播放音乐10次
    //需求2:定义一个变量,从0开始,当变量小于5的时候,计算变量之间的和
    
image-20220306160643992
do…while
  1. 先做一次,再判断

    do{
        语句块
    }while(boolean);
    
    //需求:不管你之前听音乐听多了多次,当我判断的时候都要一次 播放音乐<10;
    
image-20220306160717113
for 循环
  1. for 循环的定义

    for(表达式1;表达式2;表达式3){
        语句
    }
    
    for(①;②;③){}
    ⑤
        
    执行流程
        第一步:先执行①
        第二步:其次②
        第三步:执行④
        第四步:执行③
        第五步:回到②
        最后:  执行5
    //需求:求1-5的和
    
嵌套循环

特点:最外层的循环执行一次,里面全部执行完,再继续去执行最外层的代码。

for(表达式1;表达式2;表达式3){
    for(表达式1;表达式2;表达式3){
    	语句
	}
}

//用 * 打印一个直角三角形

break

  1. 在switch条件语句和循环语句中都可以使用break语句。当它出现在switch条件语句中时,作用是终止某个case并跳出switch结构。

    • 需求:定义一个变量num = 1,当num 大于10的时候,循环停止
  2. 标记语法

    可以指定break 跳转到某一层循环
    

continue

  1. 终止本次循环,继续往下执行
    • 需求:对1~100之内的奇数求和

注意:continue 是停止本次循环,继续执行下一次循环,而break 是整体把循环结束

数组

  1. 在生活中,会遇到如下场景,需求:统计班级学生数量,计算学生的平均年龄,找出学生最老的,找出学生最小的。
    • 假如我们班有35个人,需要35个变量来表示我们学生的年龄,这样做很麻烦而且很臃肿。
  2. 数组的概念:一堆数的组合。20,21,23,20
  3. 数组中 length 属性,就是数组的长度
  4. 数组的索引是从 0 开始的,也就是数组的下标,最大值是数组长度 -1,也就是 length -1
  5. 数组长度一但固定,就不可变
数组的定义
  1. 动态定义:数组初始化时,数组元素是空的,需要我们重新赋值才有数据。

    数据类型[] 数组名称 = new 数据类型[元素个数];
    //样例
    int[] ages = new int[35];
    
    //赋值
    数组名称[对应的索引]
    

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zZQcW1zB-1664677606216)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220307101151566.png)]

  1. 静态定义:数组初始化的时候,就已经确定各索引元素的值

    //方式1
    数据类型[] 数组名称 = new 数据类型[]{数据1,数据2,数据3};
    
    //方式2
    数据类型[] 数组名称 = {数据1,数据2,数据3};
    
  2. 获取值,或者赋值

    //给数组元素赋值
    数组名称[索引] = 值;
    //获取值
    数组类型 变量名 = 数组名称[索引];
    
    • length:数组的长度
    • 索引:从0开始,比length 少1
数组的遍历
  1. 再操作数组时,经常需要去拿元素取元素,这种操作就是数组的遍历。

  2. 遍历的语法

    //for 循环 快捷键 fori
    for(int i =0;i<arr.length; i++){
        
    }
    //foreach 遍历
    数组变量名.iter
    for(数据类型 变量名:数组名称){
        
    }
    
    
  3. foreach 底层其实还是使用我们的for 循环

数组的特点
  1. 常见问题

    • 索引越界异常(没有再索引范围内)

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rfh6lN67-1664677606217)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220307110620888.png)]

    • 数组未初始化

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ynTnaK9b-1664677606217)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220307110718437.png)]

    • 空指针异常

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7kQUz5DQ-1664677606218)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220307110801634.png)]

  2. 数组元素存储的特点

    • 数组的元素数据类型必须一致(char 有 ASII码表对应)

    • 数组元素连续,空间大小一致,并且内存地址连续,呈现线性结构

    • 数组长度固定之后,不可改变

    • 数组不仅可以存储基本数据类型,还可以存储引用数据类型,数组本身就是引用数据类型

      String[] strs = {"1","2","3"};
      
  3. 优缺点

    • 优点
      • 根据索引去获取访问元素(快)
      • 能存储较多的数据
    • 缺点
      • 数组的长度固定,不可改变(超过容量增加数组元素时,只能用新数组代替)
      • 只能存储一种数据类型
      • 删除很慢,根据内容找索引很慢
数组的拷贝及其扩容
  1. 需求:原数组不够放,新增加了元素,只能考虑扩容和拷贝

     //原来5个同学的年龄
    int[] ages = {12,13,21,19,23};
    
    //新加入一个同学 18;
    int[] newAges = new int[ages.length + 1];
    for (int i = 0; i < ages.length; i++) {
        newAges[i] = ages[i];
    }
    newAges[newAges.length - 1] = 18;
    for (int newAge : newAges) {
        System.out.println(newAge);
    }
    
  2. 需求2:从源数组某一个位置开始拷贝,拷贝某一个长度到目标数组里面去

    //从源数组的第2个元素,拷贝3个元素到新数组里面去
     //需求2的实现13,21,19
    int[] ages2 = {12,13,21,19,23};
    int[] newAges2 = new int[3];
    //第二个元素
    int srcPos = 1;
    //拷贝多长
    int index = 3;
    //目标数组的起始位置
    int destPos = 0;
    for (int i = srcPos; i < srcPos + index; i++) {
        //新数组从 destPos 开始拷贝,每次递增
        newAges2[destPos++] = ages2[i];
    }
    System.out.println("-----");
    for (int newAge : newAges2) {
        System.out.println(newAge);
    }
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ksW5C9oi-1664677606219)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220307113933106.png)]

数组的工具类 Arrays 简单了解
  1. 需求:int[] ages = {1,3,4,5,6}; 打印输出的时候,[1,3,4,5,6];

    int[] ages = {1, 3, 4, 5, 6};
    //最后字符串结果
    String ret = "[";
    for (int i = 0; i < ages.length; i++) {
        //如果当前元素是最后一个元素,就不添加,
        if (i == ages.length - 1) {
            ret += ages[i] +"]";
        } else {
            ret += ages[i] + ",";
        }
    
    //            ret += i == ages.length - 1?ages[i] +"]":ages[i] + ",";
    }
    System.out.println(ret);
    
  2. Arrays工具类

    int iMax = ages.length - 1;
    String str = "[";
    for (int i = 0; ; i++) {
        str += ages[i];
        if(i == iMax){
            str+="]";
            break;
        }
        str+=", ";
    }
    

方法

  1. 生活中的方法:处理某件事或者解决某个问题的办法。

  2. java中的方法:用来解决某件事情或者实现某个功能的办法。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eFKK2MOb-1664677606220)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220308105158097.png)]

  3. 方法的定义

    修饰符 返回值类型 方法名(形式参数){
        方法体
    }
    //实现从老代码迭代成新代码
    //修饰符      方法无返回   方法名   参数列表
    public static void      print(String str) {
            
    }
    
  4. 带返回类型的方法定义

    修饰符 返回值类型 方法名(形式参数){
        方法体
            
        return 返回值类型;
    }
    
  5. return 的作用:结束当前的方法,可以单独用,还可以带返回类型用

  6. 返回类型

    • 八大基本数据类型
    • 引用数据类型
    • void(没有返回)
  7. 需求:定义加法计算器,带两个参数的,方法返回类型为 int

    public static int add(int num1,int num2){
            int ret = num1 + num2;
            return ret;
    }
    
  8. 需求:求5个数的和,返回类型 int

     public static int addSum(int... nums) {
            int sum = 0;
            for (int num : nums) {
                sum += num;
            }
            return sum;
        }
    
  9. 注意:方法的可变参数底层实际上就是数组

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZkI8zsCU-1664677606221)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220308105125455.png)]

方法的重载
  1. 需求1.0:

    • 定义一个求浮点型 double 的计算器
    • 定义方法分别去求 float 计算器
    • 定义方法分别去求 short 计算器
    • 定义方法区求 String 字符串的拼接
  2. 需求2.0

    • 定义打印 String 类型的字符串方法
    • 定义打印 int 类型的方法
  3. 方法的重载:

    • 定义:同一个类里面,方法允许存在一个以上的同名方法,要求参数列表不同
    • 参数列表不同:
      • 1.参数类型不同
      • 2.参数顺序不同
      • 3.参数个数不同
    • 和返回值类型无关

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-FBwASDZJ-1664677606221)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220308111100303.png)]

方法的递归
  1. 定义:方法自己调用自己

  2. 需求:

    • 不使用递归计算 5 的阶乘

      int num = 5;
      int ret = 1;
      for (int i = 0; i < 5; i++) {
          ret *= num--;
      }
      System.out.println(ret);
      
    • 使用递归计算5的阶乘

      public static int recursion(int num) {
          if (num == 1) {
              return 1;
          }
          int recursion = recursion(num - 1);
          int ret = num * recursion;
          return ret;
      }
      
      image-20220308135725792

类的定义

  1. 成员变量(字段)

  2. 方法

  3. 定义格式

    public class 类名{
    	0-N个字段(成员变量)
        
           
        0-N个方法;
        
    }
    
对象的创建和使用
  1. 创建方式 类名 类变量名 = new 类名();

    Student stu = new Student();
    
  2. 给对象成员变量设置值 类变量名.字段名=值

    student.name="上云";
    
  3. 获取成员变量的值,数据类型 变量名 = 类变量名.字段名

    String name = student.name;
    
  4. 实例方法的调用,类对象名.方法名

    student.showInfo();
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5cLUsZkM-1664677606222)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220308160331376.png)]

构造方法
  1. 也叫构造器(构造方法),是用来创建对象的,当你创建对象时,一定执行

  2. 构造方法:

    • 也有修饰符
    • 不具备方法的返回值类型
    • 可以带参数
    • 默认的构造方法,里面没有任何内容
    • 构造方法可以重载
  3. 构造方法,创建对象时,可以传参

    Book book = new Book("E3层");
    
  4. 注意:不提供构造方法时,默认提供一个不带参数的构造器

实例方法
  1. 定义方式:

    • 具有修饰类型
    • 有返回值类型
    • 有方法名和参数列表
  2. 定义:

    修饰符 返回值类型 方法名(参数列表){
    
    }
    
  3. 调用方式,使用对象调用。

    对象变量名.方法名
    
  4. 空指针异常(没有去创建对象,就是调用对象的属性或者是方法)

导包
  1. 如果存在重名的情况,需要去选择自己的包 alt + enter

static 关键字

  1. static:是一个修饰符,表示静态的,可以用来修饰,方法、字段、代码块、内部类,最优先加载进内存的。

  2. 注意:

    • static 关键字,表示该资源属于类(而不是属于类对象)。只要使用 static 修饰的,直接使用类名.来调用,

      不用创建对象

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GuaCq5IF-1664677606223)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220309103935720.png)]

    • 在非 static 方法中,可以去访问 static 方法,但是最好用类名.来调用。

    • 在 static 方法中,不能直接访问普通方法

    • 静态代码块优先于一切先执行

      static {
          System.out.println("static 修饰的代码块");
      }
      
  3. 什么时候使用 static 修饰的字段以及方法和代码块

    • 在开发中,写工具类的时候。
    • 资源加载,加载配置文件(mysql jdbc)

深入变量

变量的定义语法:

数据类型 变量名 = 值;

根据位置不同,分为两大类:

  1. 成员变量
    • 类成员变量(类名.字段名调用)
      • 生命周期:从类加载到程序结束
      • 使用 static 修饰的,直接定义到类里面的
    • 实例成员变量
      • 生命周期:从创建对象开始到GC垃圾回收器回收垃圾结束
      • 直接定义到类里面的
  2. 局部变量
    • 生命周期:从变量定义开始,到最近的花括号结束}
    • 方法内部的变量
    • 参数列表
    • 代码块里面的变量
  3. 什么时候使用成员变量,什么时候使用局部变量?
    • 考虑变量的生存时间(影响内存的开销)
    • 能减少作用域都去减少(减少内存开销)
    • 定义工具类时(static 用起来比较方便)成员变量封装好,利于我们方法使用

package

  1. 类的全限定类名(反射使用)

    • sy.coder.VariableDemo.VariableDemo
      
  2. 有的需要导包,有的不需要导这是为啥?

    • java.lang java 语言核心包,里面的类直接使用,不需要手动导包
    • java.util java工具包,需要手动导包(Arrays)

封装

  1. 没有封装会有什么问题

    image-20220309131651721
  2. 是用封装,做到了信息隐藏。

    image-20220309132146210
  3. 什么是封装?

    • 把对象的状态和行为看成了一个统一的整体,放到一个独立的模块中(类)
    • 做到信息隐藏,把不需要外界看到的信息隐藏起来(private进行私有化),向外提供方法,保证外界的安全访问。
  4. 封装的好处和意义:

    • 提供了代码的复用性(可以减少重复代码)
    • 使用者可以正确操作,方便使用系统功能
    • 把实现细节隐藏起来,提供了安全性
访问控制权限修饰符
  1. 封装的目的,有些类让另一些类看不到里面再做什么事情,所以提供了访问控制权限修饰符来解决。

  2. 访问权限修饰符

    修饰符类内部同一个包子类任何地方
    public
    protected
    缺省
    private
封装的实现
  1. 规范

    • 遵循 javabean 规范

      • set 后面的单词采用驼峰命名法,并且使用原单词 setAge(…)

      • get getAge();

        private int age;
        
        public void setAge(int a){
            age = a;
        }
        
        public int getAge(){
            return age;
        }
        
    • 变量:就近原则

    • this 关键字:代表当前对象的引用

    • 需求:建一个学生类,name ,age,address 提供set get 方法。

      public class Student {
      
          private String name;
      
          private int age;
      
          private String address;
      
          public Student(){
      
          }
      
          public Student(String name){
              this.name = name;
          }
      
          public void setName(String name){
              this.name = name;
          }
      
          public String getName(){
              return name;
          }
      
          public void setAge(int age){
              this.age = age;
          }
      
          public int getAge(){
              return age;
          }
      
          public void setAddress(String address){
              System.out.println(this);
              this.address = address;
          }
      
          public String getAddress(){
              return address;
          }
      }
      
  2. 对于私有属性传参

    • 使用 set get
    • 使用构造器
  3. 注意:

    • static 静态的不能使用this 关键字,默认get 如果你不写 this,底层也会给我们加上 this
    • this 关键字也可以再构造器里面使用

引出继承

父类:存储共性(状态,行为)

子类:存放自己的特性

继承的作用:代码复用

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2EMf8es7-1664677606223)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220309153230595.png)]

继承思想

定义:基于某个父类对其进行拓展,定义新的子类,子类可以继承父类原来的属性和行为,并且可以增加父类没有的特性,或者覆盖父类中的某些特性

继承关系:is a 用是造句

继承的基础语法:

使用 extends 关键字
    
public class 子类类名 extends 父类类名{
    写自己的特征
}

注意:

  • java 只支持单继承,允许多重继承(一个类只能有一个直接父类,但是可以有多个间接父类)
  • 任何类都是 Object 的子类

创建对象时,构造方法如何执行

  • 先执行父类构造器(先执行父类静态代码块,再执行子类静态代码块)
  • 子类构造器
  • set get 方法
  • 创建对象时,创建的是谁,打印 this 对象就是谁(多态)
重写
  1. 重写:当父类特征不能满足子类特征的时候,可以对父类的方法进行重写
  2. 要求:
    • 子类的访问修饰符 >= 父类本身
    • 父类不能使用 private 修饰
    • 方法返回类型,子类 <= 父类
重写和重载的区别
  1. 没有任何关系,只不过因为名字看起来相同,所以就拿来对比

  2. 重载:发生在同一个类中,方法名相同,参数列表不同,和方法的返回类型无关

  3. 重写:override

  4. 重载:overload

    • 重载:解决了一个类中,相同功能方法名不同的问题
    • 重写:解决子类继承父类,父类方法满足不了子类要求时,需要在子类里面重写

抽象类

  1. 需求:求圆(Circle),矩形(Rectangle)的面积
  2. 使用 abstract 关键字修饰,并且没有方法体
    • 必须使用 abstract 关键字修饰,方法没有方法体,留给子类去实现/重写
    • 不能使用 private 以及 static 和 final
    • 抽象方法必须定义到抽象类中或者接口
  3. 使用 abstract 修饰的类特点:
    • 不能实例化
    • 抽象类可以有普通的方法
    • 抽象类构造器不能够私有化
    • [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7hTb4XlE-1664677606224)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220309180504490.png)]

接口

  1. 什么是接口

    • 硬件接口:两个设备之间的连接方式,包含数据传输协议
      • type-c,usb,耳机接口
    • 软件接口:程序代码,是一种规范

    统一接口后的意义:根据规范设计产品,可以做到适配性。

    • 买鼠标不会去关心是哪家厂商的,是什么接口
JAVA 接口
  1. 定义:使用 interface 关键字

    //使用 interface 代替传统的 class
    public interface 类名{
        //都是抽象方法
        void usb();
        //定义常量
        public static final int EANBLE = 1;
    }
    
  2. 注意:

    • 接口里面只能去定义抽象方法

    • 抽象方法默认提供了 public abstract 修饰符

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ATmH0D1-1664677606224)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220309181348651.png)]

    • 接口不能实例化(和抽象类一样)

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-E7hyMjie-1664677606225)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220309181430891.png)]

  3. 接口怎么去实现

    • 使用 implements 关键字

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VNSdZ5qj-1664677606225)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220309181846592.png)]

  4. 接口支持多实现,分别把每个接口的抽象方法都去实现了。

    image-20220309182138344
  5. 接口的多继承

    image-20220309182317549
抽象类和接口怎么选择
  1. 都可以使用
    • 如果你不需要具体的实现时,就用接口。
    • 如果说你除了定义规范还有一定的功能,你就用抽象类

模板方法设计模式

  1. 需求:统计不同操作的时间用时。
    • 使用 String 拼接一万次
    • 使用 int 累加 一万次

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MwDVg2VK-1664677606226)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\day09\模板方法设计模式.png)]

Object 类

Object 是所有类的超类。

可以通过Ctrl + H 查看类继承结构观察

Object 类的常用方法:

  • toString() 打印当前对象(直接打印对象就是打印对象的 toString 方法)

     public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
    
  • getClass() 获取类的字节码对象

    public final native Class<?> getClass();
    aClass.getName()//获取类的权限定类名
    
  • hashCode(); 获取对象的 哈希值,存到HashTables

    public native int hashCode();
    
  • finalize() 当对象不被引用时,要被 gc 不定时回收,gc 去调用这个方法(程序员是不用自己调用,自动调用)

    protected void finalize() throws Throwable { }
    
  • equals() 方法,比较是否是同一个对象

    public boolean equals(Object obj) {
        return (this == obj);//== 比较的是地址值
    }
    
  • equals 方法 和 == 区别面试题

    • == 比较地址值
    • equals 没有重写之前,比较的也是地址值
    • 一般我们都会重写,只关心内容而不关心地址值
  • 注意:

    • 如果 equals 方法没有重写时,== 和equals 方法没有区别
    • 如果 equals 方法重写,我们只关心内容而不关心地址值

多态

  1. 什么是多态?为啥产生多态:学生是学生,学生也是人 is a

  2. 语法:

    public class Student extends Person{
        
    }
    
    public class Person{
        
    }
    
    Student stu = new Student();
    //多态
    父类 变量名 = new 子类();
    Person p = new Student();
    
  3. 通过实现接口或者继承类,都可以产生多态

  4. 在实际开发中,要求面向(多态)接口编程

  5. 多态调用,如果父类(接口)没有子类的字段或者方法,也不能去调用

  6. 多态类型转换

    Person p = new Student();
    真实类型  变量名   真实类型 变量名
    Student stu =   (Student) p;
    
  7. 面向多态(接口)编程的意义:

    • 不需要面向具体
    • 多态的作用是降低程序耦合度,提高程序扩展力
super 关键字
  1. 需求:子类对象重写父类方法时,调用的还是父类对象的方法

  2. 使用 super 关键字解决

    @Override
    public void study() {
        super.study();
        System.out.println("学生在学习");
    }
    

内部类

  1. 成员内部类(类里面存在新的类)

    public class 外部类名{
     	public class 内部类名{
            
        }
    }
    
    • 访问方式
      • 外部对象 变量名 = new 外部对象();
      • 外部类名.内部类名 内部类变量名 = 变量名.new 内部对象();
  2. 匿名内部类(底层自动去帮我们生成了一个实现类)

    public interface 接口名{
     	void user();   
    }
    
    接口名 变量名 = new 接口名(){
        public void user(){
            //具体逻辑
        }
    }
    
  3. 局部内部类(不要去使用)局部代码块里面的类

匿名对象

  1. 匿名对象:不给对象一个变量名

    Student stu = new Student();
    
    //不需要变量名
    new Student();
    
  2. 作用和意义:少开辟空间,可以有效节约空间(GC可以不定期的回收)

代码块

  1. 静态代码块

    //类中直接存在
    static{
       
    }
    
  2. 构造代码块

    {
        //构造代码块
    }
    
  3. 局部代码块

    public static void main(String[] args) {
            Test test = new Test();
            {
                
            }
    }
    
    • fori 典型的局部代码块

执行顺序

  1. 需求:写一个类继承另一个类,每一个类提供静态代码块,构造代码块,构造方法,普通方法,静态方法。
  2. 执行顺序:
    • 父类静态代码块 -> 子类静态代码块 ->父类的构造代码块 ->父类的构造器 ->子类的构造代码块 -> 子类的构造器 ->子类的普通方法
  3. 注意:
    • 构造代码块使用并不是很多,可以用构造器代替
    • 子类不能够重写父类的 static 方法(static 修饰的是数据类,而不是对象)
    • 静态方法和普通方法没有必然的先后顺序,根据我们的调用顺序决定

javaSE基础提高

常用类

System 系统类
  1. 说明:其它老师讲的时候,会给一个 api 文档,但是我不会给(在职的人不去看)跟着源码学习,不看 api

  2. 常用方法:

    //学习数组的时候,自己写过数组拷贝的代码
     public static native void arraycopy(Object src,  int  srcPos,Object dest, int destPos, int length);
    
    //查询当前系统时间
    System.currentTimeMillis();
    public static native long currentTimeMillis();
    
    //垃圾回收器
    public static void gc() {
        Runtime.getRuntime().gc();
    }
    
字符串类(String)
  1. 构造器 -> 字段 -> 方法

    • 构造器

      //无参构造器
      public String() {
          //做了数组初始化
          this.value = new char[0];
      }
      //带一个参数
      public String(String original) {
          //给char 数组赋值
          this.value = original.value;
          //缓存String 的 hash 值
          this.hash = original.hash;
      }
      //传递 char 类型数组
      public String(char value[]) {
          this.value = Arrays.copyOf(value, value.length);
      }
      
    • 字段

      /** The value is used for character storage. */
      //存储字符的数组
      private final char value[];
      
      /** Cache the hash code for the string */
      //缓存 hash code
      private int hash; // Default to 0
      
    • 方法

      //查看字符串长度
      public int length() {
          return value.length;
      }
      //判断是否为空
      public boolean isEmpty() {
          return value.length == 0;
      }
      //返回一个索引对应字符值
      public char charAt(int index) {
          return value[index];
      }
      //判断是否包含一个字符
      public boolean contains(CharSequence s) {
          return indexOf(s.toString()) > -1;
      }
      //获取byte[]
      public byte[] getBytes() {
          return StringCoding.encode(value, 0, value.length);
      }
      //以什么开头
      public boolean startsWith(String prefix) {
          return startsWith(prefix, 0);
      }
      //以什么结尾
      public boolean endsWith(String suffix) {
          return startsWith(suffix, value.length - suffix.value.length);
      }
      //equals 方法
      equals(Object obj)
      //以什么什么断开
      public String[] split(String regex) {
          return split(regex, 0);
      }
      //去掉空字符串 “   abc   ”
      public String trim() {}
      
需求练习
  1. 创建一个字符串 String str = " 我爱学习-java"

    • 判断是否为空字符串

    • 通过 “-” 分割字符串

    • 去除字符串两端的空格

    • 判断字符串是否包含 java

      String str = "   我爱学习-java";
      boolean empty = str.isEmpty();
      System.out.println("当前字符串是否为空:"+empty);
      
      String[] split = str.split("-");
      System.out.println(Arrays.toString(split));
      
      String trim = str.trim();
      System.out.println(trim);
      
      boolean isContains = str.contains("java");
      System.out.println("当前字符串是否包含java:"+isContains);
      
  2. 创建两个字符串

    • String str = “sy”;
    • String strNew = new String(“sy”);
    • 比较内容时怎么比较?
    • 怎么判断这两块空间不是同一块?(javap -verbose xx.class)
    • 画出String 创建的一个流程图?
  3. 字符串类可以被继承吗?

StringBuilder(字符缓冲区)
  1. StringBuilder 也是final 修饰的不可以不继承

  2. 里面的 char[] 数组不是使用 final 修饰的,可以替换

  3. 构造器

    //默认的数组长度为16
    public StringBuilder() {
        super(16);
    }
    //指定容量
    public StringBuilder(int capacity) {
        super(capacity);
    }
    
  4. 方法

    //做char[] 的拷贝或者拼接
    @Override
    public StringBuilder append(String str) {
        super.append(str);
        return this;//放回当前对象
    }
    
    //将 StringBuilder 对象转换成字符串对象
    @Override
    public String toString() {
        // Create a copy, don't share the array
        return new String(value, 0, count);
    }
    
  5. 字段

    /**
    * The value is used for character storage.
    */
    char[] value;
    
    /**
    * The count is the number of characters used.
    */
    int count;
    
StringBuffer
  1. 使用synchronized修饰,是线程安全
面试题 String StringBuilder StringBuffer 区别
  1. 拼接 10万次字符串,去比较各自的耗时
  2. 注意:
    • StringBuilder 性能最好 > StringBuffer > String
    • StringBuffer 是线程安全的

JAVA 编码规范

  1. 编码对于我们程序员来说,特点重要,原因如下:
    1. 一个软件的生命周期,90%时间都是在维护系统
    2. 良好的编码习惯可以改善代码的可读性
  2. 编码规范:
    • 起名:做到见名知意,遵循标识符规范
      • 不能使用拼音,采用驼峰命名法(StudentInfo)
    • 边写代码边测试,打印中间变量进行观察,确保程序正确性
    • 基本规范:
      • 包名:域名倒写,工具类 utils , 控制层 controller
      • 类名:一般使用名词,并且首字母大写,不要使用jdk 内置名字
      • 接口名:单词前面习惯加字母 i (IUser)
      • 方法名:(动词),eat(),saveUser();
      • 变量名:首字母小写,多个单词用驼峰,studentName
      • 常量名:final 修饰的,多个单词全部大写,用_隔开,MAX_VALUE,MIN_VALUE

基本类型的包装类型

  1. 问题:
    • 一切皆对象?int age = 18;
    • 给你一个数,8888,转换成二进制,算法非常难
    • double 类型,默认值 0.0,缺考怎么去表示?考试0分的时候怎么去表示?
  2. 基本数据类型,缺少对象,jdk 提供了包装类型来解决如上问题。
Number 抽象类的学习
//获取 int 类型的值
public abstract int intValue();

//获取 long 类型的值
public abstract long longValue();

public abstract float floatValue();

public abstract double doubleValue();

public byte byteValue() {
    return (byte)intValue();
}

public short shortValue() {
    return (short)intValue();
}
Integer (int)
  1. integer 继承结构

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TJSr7MLD-1664677606227)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220311100603306.png)]

  2. 构造器学习

    public Integer(String s) throws NumberFormatException {
        this.value = parseInt(s, 10);
    }
    //将字符串解析成 int 类型
    public static int parseInt(String s) throws NumberFormatException {
        return parseInt(s,10);
    }
    
    //将字符串解析成 Integer 类型的数
    public static Integer valueOf(String s) throws NumberFormatException {
        return Integer.valueOf(parseInt(s, 10));
    }
    
    //将Integer 对象转换成 int 数
    public int intValue() {
        return value;
    }
    
  3. 自动装箱和拆箱(语法糖)

    //自动装箱
    Integer integer3 = 10;
    Integer integer3 = Integer.valueOf(10);
    //自动拆箱
    int intValue = integer3;
    int intValue = integer3.intValue();
    
  4. 整数类型做了一个缓存处理

    private static class IntegerCache {
        //缓存了 [-128,127]
    }
    
String Integer int 相互转换
  1. String 转 Integer

    Integer.valueOf()
    
    new Integer();
    
  2. String 转 int

    Integer.valueOf();
    
  3. Integer 转 int

    integer 对象.intValue();
    
拓展内容(面试内容,面试前再回头来听)
  1. 缓存设计的优点

    • 节约空间开销
    • 超过缓存范围才重新分配空间
  2. Integer 类型和 int 类型不是同一个类型

    • 通过方法的重载证明
  3. 两个方法分别定义 int a = 100000;当int 类型的值,超过 short 的最大值时,存储到常量池里面

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M8Me7Unb-1664677606227)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220311110521367.png)]

包装类型对应
基本类型默认值包装类型包装类型默认值
int0Integernull
long0Longnull
booleanfalseBooleannull
byte0Bytenull
short0Shortnull
float0.0Floatnull
double0.0Doublenull
char‘’Characternull
  1. 注意:开发过程中,建议使用包装类型

大数据运算

  1. BigInteger : java 开发中,我们的数超过了 long 类型,使用它

    public BigInteger(String val) {
        this(val, 10);
    }
    
    • 四则运算:
    public BigInteger add(BigInteger val) {}
    
    public BigInteger subtract(BigInteger val) {}
    
    public BigInteger multiply(BigInteger val) {}
    
    public BigInteger divide(BigInteger val) {}
    
  2. BigDecimal:具有精度运算的

    • 需求:
      • 打印 0.09 + 0.01
      • 打印 1 - 0.34
      • 打印 1.403 / 100
    • 注意:做金钱运算使用 BigDecimal
    • 里面有加减乘除的方法

随机数 Random

  1. 需求:随机生成 1- 100 之间的数,生成10次

    Random random = new Random();
    
    for (int i = 0; i < 10; i++) {
        int j = random.nextInt(100);
        System.out.println(j);
    }
    
  2. 需求:随机生成 100-200 之间的随机数,生成10次

    //多思考
    Random random = new Random();
    
    for (int i = 0; i < 10; i++) {
        int j = random.nextInt(100) + 100;
        System.out.println(j);
    }
    

Math 类()数学类

  1. Math 类包含了数学的常用方法:
    • 平方
    • 三角函数
    • 平方根
    • 指数
    • 绝对值

Arrays 工具类

  1. 自己写过二分查找法

正则表达式

  1. 正则表达式:使用字符串来定义匹配规则(regex)

  2. 正则表达式的匹配练习:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2POPG8NH-1664677606230)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220311135413745.png)]

  3. 注意:正则不用手动去写,也不用去记,了解一下就行了。

  4. 去网站生成正则表达式就行

日期处理

Date
//创建当前日期对象
public Date() {
    this(System.currentTimeMillis());
}

//打印符合我们本地人观看的时间日期
@Deprecated
public String toLocaleString() {
    DateFormat formatter = DateFormat.getDateTimeInstance();
    return formatter.format(this);
}
SimpleDateFormat -->DateFormat

把日期变成字符串

 public final String format(Date date)

把字符串变成日期

 public Date parse(String source) 

最常用的日期格式

  • yyyy-MM-dd
  • yyyy-MM-dd HH:mm:ss
字母含义示例
y年份。一般用 yy 表示两位年份,yyyy 表示 4 位年份使用 yy 表示的年扮,如 11; 使用 yyyy 表示的年份,如 2011
M月份。一般用 MM 表示月份,如果使用 MMM,则会 根据语言环境显示不同语言的月份使用 MM 表示的月份,如 05; 使用 MMM 表示月份,在 Locale.CHINA 语言环境下,如“十月”;在 Locale.US 语言环境下,如 Oct
d月份中的天数。一般用 dd 表示天数使用 dd 表示的天数,如 10
D年份中的天数。表示当天是当年的第几天, 用 D 表示使用 D 表示的年份中的天数,如 295
E星期几。用 E 表示,会根据语言环境的不同, 显示不 同语言的星期几使用 E 表示星期几,在 Locale.CHINA 语 言环境下,如“星期四”;在 Locale.US 语 言环境下,如 Thu
H一天中的小时数(0~23)。一般用 HH 表示小时数使用 HH 表示的小时数,如 18
h一天中的小时数(1~12)。一般使用 hh 表示小时数使用 hh 表示的小时数,如 10 (注意 10 有 可能是 10 点,也可能是 22 点)
m分钟数。一般使用 mm 表示分钟数使用 mm 表示的分钟数,如 29
s秒数。一般使用 ss 表示秒数使用 ss 表示的秒数,如 38
S毫秒数。一般使用 SSS 表示毫秒数使用 SSS 表示的毫秒数,如 156
Calendar 日历类
  1. 获取日历对象

    public static Calendar getInstance()
    
  2. 获取当前时间

    public final Date getTime() {
        return new Date(getTimeInMillis());
    }
    

工具类的设计

  1. 日期工具类的设计
    • 需求:建立一个员工类, Employee, entry 入职时间,birthday 生日,创建员工管理类 EmployeeManager input 录入数据
    • 发现如果不使用工具类,代码太臃肿了。所以需要抽工具类
  2. 数组工具类自行设计

枚举

  1. 需求:定义一个学生类,定义一个成员变量 restDay(表示学习哪天休息)

  2. 问题如下

    • 非法数据设置、

      image-20220311151701851
    • 解决办法1:使用指定的单独管日期的类 WeekDay,并且不能够修改内容,使用7个常量来表示,能保证选择数据安全性,但是还是吧不能保证数据安全

image-20220311152243701

​ 解决办法2:私有化构造器,使用对象来代替常量

image-20220311152756121
  1. 枚举:

    [public] enum 枚举名称{
        常量1,常量2}
    
  2. 特点

    • 构造器私有化

    • 里面是一个个常量

    • 枚举里面可以提供带参数构造器

    • 可以提供 set get方法

    • 可以定义普通方法

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BOPs3GsD-1664677606231)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220311153608588.png)]

单例设计模式

  1. 单例模式:只能创建出一个对象,不能创建多个,提供方法去获取需要的对象。

没有异常处理时如何处理异常

  1. 什么是异常:非正常的,不正常的。

  2. 程序中:代码出现错误,程序会终止运行。异常指的不是语法错误,语法错误,编译不通过,不能产生字节码文件,根本不能运行

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MSVIm0nV-1664677606233)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220312104131854.png)]

  3. 异常是衡量语言成熟的标准之一,java C++都支持异常处理机制。

  4. 上学迟到的异常:

    public class Sleep {
        public static final int OK = 1;//准时起床
        public static final int NO_OK = 0;//没起来
        public int asleep(int num) {
            if(num == Sleep.OK){
                System.out.println("准时起床");
                return OK;
            }else{
                System.out.println("起晚了翘课");
                return NO_OK;
            }
        }
    }
    
    public class Student {
        public static final int LATE = 0;//代表迟到或者翘课
        public static final int IN_TIME = 1;//准时上课
        public Sleep sleep;
        public Student(Sleep sleep){
            this.sleep = sleep;
        }
        public int gotoStudy(int num){
            if (sleep.asleep(num) == Sleep.OK) {
                System.out.println("准时上课");
                return Student.IN_TIME;
            }else{
                System.out.println("翘课");
                return Student.LATE;
            }
        }
    }
    
    Sleep sleep = new Sleep();
    Student student = new Student(sleep);
    
    int i = student.gotoStudy(0);
    if(i == Student.IN_TIME){
        System.out.println("准时上学");
    }else{
        System.out.println("翘课");
    }
    
  5. 没有异常机制存在问题:

    • 使用方法的返回值来表示异常,无法穷尽所有情况来表示
    • 异常代码和正常流程混在一起了。代码更加臃肿,增加了程序的复杂性,可读性也变低了。
    • 随着系统规模扩大,维护性变低了。
异常机制
  1. 解决上述问题,把不同的异常类型描述成不同的类(异常类),变得更加的灵活,自己不想处理的可以交给调用者处理

  2. 异常继承结构图

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-tR4ZIwtv-1664677606234)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220312110040864.png)]

    • Error 错误:指JVM 相关的不可修复的错误,如:内存溢出,JVM错误等。常见的Error
      • StackOverflowError 栈异常,使用递归没有出口的时候
      • OutOfMemoryError 内存不够
    • Exception: 常见异常
      • NullportException 空指针异常
      • ArrayIndexOutofBundsException 数组索引越界异常
  3. 查看异常信息(可以定义异常的行数的,大胆的去解决不要害怕)

异常处理

如果出现异常,程序是不能继续往下执行的,这个时候需要我们程序员手动处理异常。

  • 如果该方法不处理:通过方法声明抛出,由调用该方法的调用者来处理(throws)
  • 在方法中使用 try{}catch(){} 的语句进行处理

语法格式:

  1. throws 关键字

    • 声明:把问题标识出来,报告给调用者,由调用者处理(有甩锅的感觉)

    • 在参数列表上 throws + 具体的异常类型

    • 用在方法上

    • 格式

      public static Date getDateByString(String str) throws ParseException {
          DateFormat format = new SimpleDateFormat("yyyy-MM-dd");
          Date parse = format.parse(str);
          return parse;
      }
      
  2. throw 关键字

    • 用来抛出一个指定类型的异常

    • 创建一个异常对象 throws 异常对象;

    • 用在方法内部

    • 格式

      public static int divide(int a, int b) {
          if (b == 0) {
              throw new ArithmeticException("除数不能为0");
          }
          return a / b;
      }
      
  3. try…catch

    • 用来处理异常

    • 定义格式

      try{
          可能出现异常的代码
      }catch(异常的类型 变量){
          异常执行代码
      }
      
      try{
          int divide = divide(1, 0);
      }catch(ArithmeticException e){
      //            e.printStackTrace();
          System.out.println("我们的除法计算器出现异常了");
      }
      System.out.println("欢迎下次光临");
      
  4. try…catch…finally

    try{
        可能出现异常的代码
    }catch(异常的类型 变量){
        异常执行代码
    }finally{
        无论程序怎么执行,都会执行到这里
    }
    
    finally 代码块永远会执行
    
  5. 什么时候使用 throws?throw?try…catch

    • throws:当前方法不需要去处理,只需要提供异常信息,给调用者处理即可
    • throw:方法会出现异常时,需要提醒调用者
    • try…catch:具体需要处理的时候
  6. Exception 和 RuntimeException 的区别

    • Exception 是受检查异常,必须处理或者throws 出去
    • RuntimeException 运行时异常,运行的时候才去检查
  7. 异常对象常用方法:

    • getMessage() 获取具体的异常原因
    • printStackTrace()//打印具体的错误
final、finalize、finally有什么区别(面试题)
  1. final:表示最终的,不可修改的。
    • final int MAX = 10; 常量
    • final class Student 不可以继承
    • final 去修饰方法,不可以被重写
  2. finalize:Object 的一个方法,提供给GC垃圾回收器使用的。
  3. finally:异常处理的代码块,最终都要执行
重写复习
  • 发生到子类和父类之间
  • 方法签名必须相同(方法名和形式参数)
  • 子类返回类型必须和父类一致或者比它小
  • 子类的修饰符大于等于父类
  • 建议:子类抛出的异常小于等于父类
自定义异常
  1. 现有的异常不能满足我的要求,需要自己去定义:

    • IndexOutofBundsException 索引越界异常

      public class IndexOutOfBoundsException extends RuntimeException {
          public IndexOutOfBoundsException() {
              super();
          }
          public IndexOutOfBoundsException(String s) {
              super(s);
          }
      }
      
      
    • NullpointerException 空指针异常

      public class NullPointerException extends RuntimeException {
        
          public NullPointerException() {
              super();
          }
      
          public NullPointerException(String s) {
              super(s);
          }
      }
      
  2. 自定义异常

    • 语法

      public class 自定义异常类 extends 异常类{
          //定义无参数构造器
          public 自定义异常类() {
          	super();
          }
      	//带一个String类型参数的构造器
          public 自定义异常类(String s) {
              super(s);
          }
      }
      
    • 例子

      public class MyNullPointerException extends Exception {
      
          public MyNullPointerException(){
              super();
          }
      
          public MyNullPointerException(String s){
              super(s);
          }
      }
      

异常在开发中的使用:

  • 项目中会做统一异常处理,状态码返回 200 400 404 500
  • 普通的正常异常的处理

数据结构

  1. 什么是数据结构:是用来做计算存储,组织数据(插入数据,更新数据,删除数据,查询数据)的一种方式,是相互之间,存在一种或者多种特定关系的数据结合。数据结构需要高效的算法和索引技术。

  2. 常见的数据结构:

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-uBOzBztA-1664677606235)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220312131213376.png)]

  • 意义:带来更高效的存储和运行效率
  • 要求:高效的检索算法和索引技术
  • 作用(模拟:存储学生的信息)
    • 保存学生信息
    • 修改学生信息
    • 删除学生信息
    • 查询学生信息
    • 查询多个学生信息
  • ArrayList LinkedList HashMap (高度封装,别人给我们提供好的)
引出ArrayList
  1. 需求:加入你是大学生程序竞赛的导师(5个参赛名额,1-2个替补)

    • 准备一个数组(5)
    • 安排5个学生去比赛
    • 查询某一个同学是几号比赛位
    • 替补替换2号同学
    • 3号同学作弊,禁止3号同学参赛(不能安排替补上场)
    • 打印最后比赛参赛选手的名称
  2. 新需求

    • 带队3个人参加数学比赛
    • 带队10个人参加 ctf 比赛
    image-20220312140801808
分析 ArrayList 性能
  1. 大O表示法(BigO):用来描述时间的复杂度,专门用来衡量计算机性能
  2. 分析 ArrayList 性能
    • 新增操作:
      • 把数据添加到最后一个元素,至少操作一次
      • 如果把数据放到数组的第一个位置,现在有N个元素,此时需要操作N次(整体后移)
      • 平均:O((N+1)/2 ) O(N)
    • 删除操作:
      • 如果是最后一个元素,操作一次
      • 如果删除第一个元素,操作N次
      • 平均 O((N+1)/2) O(N)
    • 修改操作:
      • 操作一次
    • 查询操作:
      • 根据索引去查,也是操作1次
      • 根据元素来查,1-N次之间 O((N+1)/2 ) O(N)
  3. 基于数组结够,做查询和修改非常快,但是做删除和新增会慢一点
链表 LinkedList
  1. 链表分为:

    • 单向链表

      增加和删除

    • 双向链表

      • 往前添加
      • 往后添加
      • 删除

    分析 LinkedList 性能

    • 增加:
      • 直接从头尾增加,操作1次
    • 删除
      • 如果删除头尾元素,操作1次
      • 删除中间元素,(1+N)/2
    • 查询
      • 查询头尾 1次
      • 查询中间 (1+N)/2
    • 修改
      • 头尾1次
      • 中间 (1+N)/2

    基于数组和链表的对比:

    • ArrayList:查询更改较快,新增和删除较慢
    • LinkedList:查询,更改较慢,新增和删除较快
队列

队列是一种特殊的线性表,特殊之处在于只允许在表的前端或者后端操作

单向队列(Queue):先进先出(FIFO),只能从队尾插入数据,从头部删除

双向队列(Deque):可以从头尾什么都可以操作。

  1. 栈(stack):受限制的线性表,先进后出(FILO)
  2. 被限制只允许从表的一段进行插入和删除运算,这一端称为栈顶,另一端就称为栈底
哈希表:Hash
  1. 一般数组中,通过索引操作的,索引和我们元素之间是不存在确定关系。查找值直接查索引就行
  2. hashtable:元素值和我们的hashtable 是存在对应关系的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zXQCUjSh-1664677606235)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220312164448665.png)]

  1. 需求:不适用任何的集合,也不使用数据库,添加学生信息(id name),做到快速查询
    • 插入查询特别快
    • 元素位置—>哈希码—>链表
集合概述
  1. 集合框架(java.util)的由来:容器类(集合类)可以存储多个数据,数组明明可以存储多个数据,为啥还要定义容器类?

    • 数组弊端:
      • 长度一但固定就不可变
      • 很多地方需要操作数组的(增删改查)都需要去编写对应的方法(代码重复了—>封装)
      • 每个人定义各自的方法,可能存在别人找不到 这种情况,实现也容易存在bug
  2. 什么是集合框架:容器类确实很好用,集合框架框架是为了提供一些规范和标准,任何实现类都需要包含对外的接口,接口的实现,对集合内部的算法(底层都是一种数据结构)

  3. 定义集合框架的目的:提供代码复用(封装的思想),让使用者专注于业务开发,而不是数据结构和算法。

  4. 常见集合类:

    • List(列表):集合中对象按照索引位置排序,允许元素重复。
    • Set(集):集合中的元素不按特定方式排序,不允许元素重复。
    • Map(映射):集合中的元素(key-value),不允许key 重复,值可以重复。

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YJHBjhLf-1664677606236)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220313110647116.png)]

image-20220313110804405
Collection 常用方法
  1. 接口定义的常用方法规范

    //集合容量大小 
    int size();
    //判断集合是否为空
    boolean isEmpty();
    //包含是否有某一个元素
    boolean contains(Object o);
    //迭代器
    Iterator<E> iterator();
    //转换成数组
    Object[] toArray();
    //添加元素的
    boolean add(E e);
    //删除元素
    boolean remove(Object o);
    //判断集合是否包含另一个集合
    boolean containsAll(Collection<?> c);
    //添加一个集合
    boolean addAll(Collection<? extends E> c);
    //清空
    void clear();
    //获取hashcode
    int hashCode();
    
  2. 通用迭代

    Iterator it = 集合对象.iterator();
    while(it.hasNext()){
        Object ele = it.next();
    }
    
    //迭代器接口
    //判断是否有下一个元素
    boolean hasNext();
    //获取下一个元素
    E next();
    
List 接口
  1. List 接口规范:

    //根据索引获取元素值 
    E get(int index);
    //设置某一个索引位置元素值
    E set(int index, E element);
    //删除某一个索引位置的值
     E remove(int index);
    //截取
    List<E> subList(int fromIndex, int toIndex);
    
Vector 实现类
  1. 看源码学习

    public class Vector<E> extends AbstractList<E> implements List<E>{
           //元素数组
          protected Object[] elementData;
          //元素个数
          protected int elementCount;
          //扩容容量
          protected int capacityIncrement;
        
        public Vector(int initialCapacity, int capacityIncrement) {
            this.elementData = new Object[initialCapacity];
            this.capacityIncrement = capacityIncrement;
        }
        
         public Vector(int initialCapacity) {
            this(initialCapacity, 0);
         }
        
        public Vector() {
            this(10);
        }
        
         public synchronized void addElement(E obj) {
            modCount++;
            ensureCapacityHelper(elementCount + 1);
            elementData[elementCount++] = obj;
        }
        //扩容逻辑
         private void grow(int minCapacity) {
            // overflow-conscious code
            int oldCapacity = elementData.length;
             //如果你传进来扩容容量,新容量=老容量+传进来的扩容容量否则2倍老容量
            int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                             capacityIncrement : oldCapacity);
            if (newCapacity - minCapacity < 0)
                newCapacity = minCapacity;
            if (newCapacity - MAX_ARRAY_SIZE > 0)
                //给int类型的最大值
                newCapacity = hugeCapacity(minCapacity);
             //数组的拷贝
            elementData = Arrays.copyOf(elementData, newCapacity);
        }
        
        
    }
    
  2. Vector 总结

    • 底层使用 Object[] 数组(调用不带参数构造器时,默认长度为10,若不传扩容参数,扩容2倍)
    • toString 方法已经重写并且可以直接打印出数组的样子
    • 增查删改
    • 常用方法
      • add(E obj)
      • addElement(E obj)
    • 查询
      • size() 查长度
      • get(int index) 查具体索引位置的元素值
      • isEmpty() 判断集合为空
    • 删除
      • remove(int index)删除具体索引位置的元素
      • remove(“A”) 删除指定元素
      • removeLast() 循环,设置 null ,等待gc 回收
    • 修改
      • set(int index,E obj);修改某一个索引位置元素值
image-20220313115544959
Stack 栈

栈:是数据结构,First In Last Out

栈结构生活中的体现:

  • QQ消息:AB两个人先后发送消息,最后发送的是最新的。

栈:底层可以用数组,或者链表

//添加元素
public E push(E item) {
        addElement(item);
        return item;
}
//取元素并且删除
 public synchronized E pop() {
    E       obj;
    int     len = size();
    obj = peek();
    removeElementAt(len - 1);
    return obj;
}

//查看栈顶元素
public synchronized E peek() {
    int     len = size();
    if (len == 0)
        throw new EmptyStackException();
    return elementAt(len - 1);
}
  • 建议:建议使用ArrayDeque(方法会更加友好)
ArrayList

ArrayList 是用来取代 Vector.两者底层原理和算法,一模一样。

区别:

  • Vector:所有的方法都是用 synchronized 修饰符,表示线程安全的,性能低,适用于多线程环境
  • ArrayList:线程不安全,性能高,即使在多线程环境下也是用它(Collections.synchronizedList(list))
  • ArrayList 底层扩容是1.5倍,Vector 是两倍
  • 底层构造器ArrayList 优化了,默认创建对象的时候是给一个空数组,第一次调用add 方法时,采取重新初始化数组(创建对象时,如果不存任何值,也浪费了堆空间)
LinkedList
  1. LinkedList:是一个双向链表,双向队列(单向队列)list 的实现类。

    Queue 方法DQueue 方法LinkedList
    boolean add(E e);void addFirst(E e);public E getFirst()
    E remove();void addLast(E e);public E getLast()
    E poll();E removeFirst();public void addFirst(E e)
    E element();E removeLast();public void addLast(E e)
    E peek();E pollFirst();
    E pollLast();
    E getFirst();
    boolean add(E e);
    void push(E e);
    E pop();
  2. 面试题:请编写一个双向链表

  3. 注意:

    • LinkedList 是非线程安全的,保证线程安全,使用Collections 线程安全方法
    • 擅长操作头和尾,大多数你以后要用的方法, addFirst addLast removeFirst
    • 链表不存在索引,但是调用get(index) 是因为底层提供了 ListItr 这个内部类 提供了一个int 的索引
    • 擅长保存和删除操作
List 的总结
  1. 根据 Vector ArrayList LinkedList 类的所有特点进行一个抽象,定义一个规范
  2. 特点:
    • 允许元素重复
    • 会记录添加顺序
    • 具有很多共同方法
实现类的选用
  1. ArrayList 取代 Vector 直接使用
  2. LinkedList:
    • 数组结构的算法:插入和删除速度慢,查询和更改较快
    • 链表结构的算法:插入和删除速度快,查询和更改较慢
泛型
  1. 为啥使用泛型?

    • 存在一定问题:
      • 取集合元素时,取出来的是Object 类型,需要强制类型转换才能使用
      • 添加元素时候,缺乏规范,导致可能需要使用时,会出现类型转换异常
    • 设计原则,不要写重复的代码,能抽就抽
  2. 泛型:是一种数据规范和约束,提供编译时期的安全检查机制,底层给我们做强制类型转换

  3. 如何使用泛型?

    • 常见的字母

      • T type(类型,使用到类上面)
      • K V (key value)
      • E element(元素)
    • 使用

      • 使用到类或者接口上

        public class User<T> {
            T obj;
        }
        
        //多个的方法
        public class User<T,E,k> {
            T obj;
            E ele;
            k value;
        }
        
      • 接口

        public interface Usb<T> {
            void user(T t);
        }
        
      • 方法

        public static <T> T print(T t){
            return t;
        }
        
      • 泛型的继承

        public class Mouth<T,T1> implements Usb<T,T1>{
            @Override
            public void user(T t, T1 t1) {
            }
        }
        
        public class Keyword<T> implements Usb<T,String>{
            @Override
            public void user(T t, String s) {
            }
        }
        
Map 接口
  1. map 概述:key—>value 的映射关系,是以键值对的方式存储

  2. Map:是一种两个集合之间的一个映射关系,Map 并没有继承 Collection 接口

    • key 是不可以重复
    • value 是可以重复的
  3. Map 最常用的实现类:

    • HashTable
    • HashMap
    • LinkedHashMap
    • Properties
    • ConcurrentHashMap
  4. map 常用的方法

    int size();
    //判断某一个key 是否存在
    boolean containsKey(Object key);
    //获取元素值
    V get(Object key);
    //设置值
    V put(K key, V value);
    //删除某一个key 的值
    V remove(Object key);
    //获取所有的key
     Set<K> keySet();
    //获取所有的value
    Collection<V> values();
    //获取键值对对象
    Set<Map.Entry<K, V>> entrySet();
    
HashMap

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EX4oREPL-1664677606237)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220313163441465.png)]

  1. put 方法的实现原理

    public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);
    }
    
    hash(key);
    
    Node<K,V> 单向的
        
    TreeNode<K,V>
    
  2. get 方法原理

    hash(key)//先找hash表中的位置
    //判断是treeNode,如果是使用红黑树算法寻找value,不是使用链表遍历
    treeNode 算法,使用hash 往左节点或者右节点直接找。
        
    遍历链表,判断hash 的同时,去判断 key 值
    
    

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-dNKVwIt4-1664677606238)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220313165003690.png)]

  3. 面试题:java7 个 hava8 hashMap 的区别

  4. 使用

    • key — String

    • value 无所谓

    • 注意,存String 类型无所谓,存对象类型,需要重写equals 方法和 hashCode();

      Map<Student,String> mapStu = new HashMap<>();
      mapStu.put(new Student(10),"sy");
      mapStu.put(new Student(12),"zs");
      mapStu.put(new Student(13),"ls");
      mapStu.put(new Student(10),"zz");
      
      Set<Map.Entry<Student, String>> entries = mapStu.entrySet();
      System.out.println(entries);
      for (Map.Entry<Student, String> entry : entries) {
          System.out.println(entry.getKey());
          System.out.println("-----");
          System.out.println(entry.getValue());
      }
      
    • 嵌套使用

LinkedHashMap

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-x2EwIPsG-1664677606238)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220313181350172.png)]

  1. 记录添加顺序,key 不允许重复,判断 key 是否重复和 HashMap 标准一致
HashTable
  1. HashTable:和HashMap 几乎一致,它是线程安全的,被HashMap 所替代了。采用hash表算法,所有的方法synchronized修饰符修饰,性能低一点。
Properties

用来加载资源文件

public synchronized void load(InputStream inStream) throws IOException {
    load0(new LineReader(inStream));
}
TreeMap
  1. 采用红黑树算法,里面的key 会按照自然顺序(不自己指定排序规则)自动排序,或者定制排序,可以不能重复,key 判断重复的标准,Comparator compare 的返回值判断

    • 返回值 = 0
    • 返回值 > 0 升序 ASC
    • 返回值 < 0 降序 DESC
  2. 需求:计算一个字符串中字符出现的次数 “fwihfiwehfihewifhiaufiuhailfawigfuauekgfweufuiwegfieuw”,并按照 a b c 的方式排序;

    String str = "fwihfiwehfihewifhiaufiuhailfawigfuauekgfweufuiwegfieuw";
    char[] chars = str.toCharArray();
    Map<Character,Integer> map = new TreeMap<>();
    for (char aChar : chars) {
        //如果从map 里面找不到,说明没值
        if(map.get(aChar) == null ){
            map.put(aChar,1);
        }else{
            Integer integer = map.get(aChar);
            map.put(aChar,++integer);
        }
    }
    
    System.out.println(map);
    
  3. 排序源码

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iVF9oltj-1664677606239)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220313185353668.png)]

Set 接口
  1. Set 接口是 Collection 的子接口,相当于数学上的集合

  2. Set 存储元素的特点:

    • 不允许元素重复,尝试添加相同元素,会返回false
    • 不会记录元素的先后添加顺序
    • 判断两个元素对象是否相等用的是equals 方法
  3. hash 表与 数组对比

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zlPECyDi-1664677606240)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220314102329611.png)]

HashSet
  1. HashSet 是 Set 最常用的接口,底层使用 Hash(散列) 算法,查询速度和插入速度较快。

  2. HashSet 判断两个对象是否相等,equasl 比较。返回 true 表示相等。

  3. 对象的 HashCode 值决定了在hash 表中的位置。

    • 判断添加对象和集合元素对象HashCode值。
      • 不等:直接将新添加对象存储导对应位置
      • 相等:再继续判断新对象和集合中对象的具体值,equals 方法判断
        • HashCode 相同,equals true ,则是同一个对象,则不保存hashtable 中
        • HashCode 相同,equasl false,存储到同槽的链表上。
  4. HashSet 基于 HashMap 实现的

    //直接使用HashMap写好的代码,体现了封装的原则,减少重复代码
    private transient HashMap<E,Object> map;
    //map.put value 永远设置同一块空间 new Object 的静态常量
    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }
    //得到 HashMap 的 key
    public Iterator<E> iterator() {
        return map.keySet().iterator();
    }
    
  5. 注意:记得重写 equals 和 hashCode 方法

LinkedHashSet
  1. 底层使用哈希表算法,和链表算法,

    • 哈希表用来保证唯一性,HashSet 里面是不记录添加先后顺序的。
    • 链表,来记录元素的添加顺序
  2. 底层基于LinkedHashMap 实现

    public LinkedHashSet() {
        super(16, .75f, true);
    }
    
    HashSet(int initialCapacity, float loadFactor, boolean dummy) {
        map = new LinkedHashMap<>(initialCapacity, loadFactor);
    }
    
TreeSet
  1. TreeSet:底层使用红黑树算法,会对存储的元素做自然排序(小-大)

  2. 注意:使用TreeSet 时,必须使用同一种数据类型。因为需要比较,否则就会报类型转换异常

    • 底层肯定实现了Comparable 接口
    • 比较结果
      • 大于0
      • 等于0 则说明是同一个对象
      • 小于0
  3. 底层都是基于 TreeMap 实现的

    //底层使用 treeMap 
    public TreeSet() {
        this(new TreeMap<E,Object>());
    }
    //可以传一个自定义比较器
    public TreeSet(Comparator<? super E> comparator) {
        this(new TreeMap<>(comparator));
    }
    
image-20220314113745752
Collections集合工具类
  1. 常用方法

    //获取线程安全的集合
     Collections.synchronizedList(new ArrayList());
    //获取线程安全的集合
    Collections.synchronizedCollection(Collection);
    //排序,好挺常用
    public static <T extends Comparable<? super T>> void sort(List<T> list) {
        list.sort(null);
    }
    
  2. 其它常用

    public static final List EMPTY_LIST = new EmptyList<>();
    public static final Map EMPTY_MAP = new EmptyMap<>();
    public static final Set EMPTY_SET = new EmptySet<>();
    
集合类整体总结

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2iDj94CK-1664677606240)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220314121314501.png)]

是否记录添加顺序的总结如下:

数据类型是否记录添加顺序是否添加就排序底层算法
arrayListtruefalse数组
linkedListtruefalse链表
hashSetfalsefalse哈希算法,红黑树
linkedHashSettruefasle哈希算法,链表,红黑树
treeSetfalsetrue红黑树
hashMapfalsefalse哈希算法,红黑树
linkedHashMaptruefalse哈希算法,链表,红黑树
treeMapfalsetrue红黑树

IO概述

  1. 问题:数据是存储到内存中的,当我们程序运行结束时,数据就没了,此时就需要把数据持久化存储起来。
  2. I:input 输入(读)
  3. O:output 输出(写)
  4. java.io 包
File 类
  1. File 类:文件、目录的一个抽象封装

  2. 文件路径分隔符:

    • windows:使用 \ 分割,java 中要使用\\ ,分割属性;(不区分大小写)
    • Unix 系统:/ 分割(区分大小写)
  3. 获取当前系统的分割符:

    //获取分割属性
    File.pathSeparator;
    File.pathSeparatorChar;
    //分割符
    File.separator;
    File.separatorChar;
    
  4. 获取路径和名称

    • 相对路径:参考一个坐标,与这个坐标的路径

      . 代表当前目录
      ..返回上一层
      ../test 上一层目录下面的 test 目录
      注意,现在拷贝的时候,尽量使用绝对路径来做,以后到框架阶段,用相对路径来做
      
    • 绝对路径:从磁盘的跟目录一直到你的文件

      //获取绝对路径
      public String getAbsolutePath()
      //获取文件路径
      public File getAbsoluteFile()
      //获取文件路径
      public String getPath()
      //获取上级目录文件
      public File getParentFile()
      //获取上级目录路径
      public String getParent()
      
  5. 构造方法

    //直接使用路径创建文件 pathname 可以是文件也可以是目录
    public File(String pathname)
    //从目录对象下创建文件对象
    public File(File parent, String child)
    //目录路径和文件路径分开传
    public File(String parent, String child)
    
  6. 方法

    //创建新文件
    public boolean createNewFile()
    //判断是否为目录
    public boolean isDirectory() 
    //判断是否为文件
    public boolean isFile()
    //删除文件
    public boolean delete()
    //判断文件是否存在
    public boolean exists()
    //创建文件目录
    public boolean mkdir()
    //创建多个目录
    public boolean mkdirs() 
    //获取当前层级的文件名
    public String[] list() 
    //重命名(可以做拷贝)
    public boolean renameTo(File dest) 
    
递归操作文件
  1. 需求:列出指定目录中的所有文件,包括子文件夹中的所有文件及其子文件。(Recursion) 递归

    • 递归回顾:

      public static int recursion(int num){
              if(num == 1){
                  return 1;
              }
              return num * recursion(--num);
          }
      
    • 需求实现

      public static void allFiles(File file, String path) {
              //寻找第一层的所有儿子
              File[] files = file.listFiles();
              System.out.println(path + file.getAbsolutePath());
              for (File f : files) {
                  if (f.isDirectory()) {
                      //如果是目录就需要递归
                      allFiles(f, path + path + "   -");
                  } else {
                      System.out.println(path + path + f.getName());
                  }
              }
          }
      
  2. 需求:批量修改文件名

    public static void rename(String deleteName,String newName,File file){
            File[] files = file.listFiles();
            for (File f : files) {
                if(f.isFile()){
                    if(f.getName().contains(deleteName)){
                        //替换名字字符串
                        String replace = f.getName().replace(deleteName, newName);
                        //创建替换文件对象
                        File file1 = new File(f.getParent(), replace);
                        f.renameTo(file1);
                    }
                }else{
                    //递归
                    rename(deleteName,newName,f);
                }
            }
        }
    
文件过滤器(FilenameFilter)
  1. 需求:打印指定目录下以.avi 结尾的资源

    public static void filterFiles(List<File> list, File file, String filterName){
            File[] files1 = file.listFiles();
            int count = 0;
            for (File file1 : files1) {
                if(file1.isFile()){
                    File[] files = file.listFiles(new FilenameFilter() {
                        @Override
                        public boolean accept(File dir, String name) {
                            return new File(dir, name).isFile() && name.endsWith(filterName);
                        }
                    });
                    if(count > 0){
                        continue;
                    }
                    for (File file2 : files) {
                        list.add(file2);
                    }
                    count++;
                }else{
                    filterFiles(list,file1,filterName);
                }
            }
        }
    
  2. 文件过滤器(FilenameFilter)规范,需要自己实现逻辑。

    FilenameFilter filter = new FilenameFilter() {
        @Override
        public boolean accept(File dir, String name) {
            return false;
        }
    };
    
IO概述
  1. io:输入和输出
    • 输入设备:
      • 键盘,鼠标,麦克风
    • 输出设备
      • 显示器,打印机,音响
  2. 为什么程序需要io
    • 做数据存储持久化。
  3. io流的分类(java.io 包下面的)
    • 按流向(输入和输出流)
    • 按数据单位(字节流字符流)
    • 四大基本流
      • 字节输入流
      • 字节输出流
      • 字符输入流
      • 字符输出流
    • 不管你是什么流,都需要关闭资源如果不关闭资源,磁盘文件会被占用,不能删除也不能修改

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0u6GA7fF-1664677606241)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220315111454242.png)]

注意:操作IO流

  • 输入输出的目标搞明白,程序写出去,输出,程序读进来,输入
    • 输入
      • read()
    • 输出
      • write()
文件流
字节流
  1. 字节流:

    • FileInputStream 文件输入流

      • 需求:读 my.txt 的文件内容出来

        常用方法
        public FileInputStream(String name) throws FileNotFoundException {
            this(name != null ? new File(name) : null);
        }
        //通过文件获取输入流对象
        public FileInputStream(File file)
        //通过 byte[] 数组读
        public int read(byte b[]) throws IOException {
            return readBytes(b, 0, b.length);
        }
        //关闭资源的方式
        public void close()
          //获取文件对象
                File file = new File("D:\\javase\\homework\\practice\\day20\\my.txt");
                //获取文件输入流对象
                FileInputStream in = null;
                try {
                    in = new FileInputStream(file);
                    int length = -1;
        //        while ((length = in.read()) != -1){
        //            System.out.println(length);
        //        }
                    byte[] bytes = new byte[1024];
                    while ((length = in.read(bytes)) != -1){
                        String s = new String(bytes);
                        System.out.println(s);
                    }
        
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    try {
                        in.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
        
    • FileOutputStream 文件输出流

      • 需求:把 sy666 写进刚才读的文件里面

        //append 表示是否追加
        public FileOutputStream(String name, boolean append)
        //关闭资源
        public void close()
        //写
         public void write(byte b[])
        
        //获取文件对象
                File file = new File("D:\\javase\\homework\\practice\\day20\\my.txt");
                FileOutputStream out = null;
                try {
                     out = new FileOutputStream(file,true);
                    String sy = "sy666";
                    byte[] bytes = sy.getBytes();
                    out.write(bytes);
                } catch (Exception e) {
                    e.printStackTrace();
                }finally {
                    if(out != null){
                        try {
                            out.close();
                        } catch (IOException e) {
                            e.printStackTrace();
                        }
                    }
                }
        
    • 需求:将 sy.txt 文件中的内容,拷贝成一个新文件 new.txt

      FileInputStream in = null;
              FileOutputStream out = null;
              try {
                  in = new FileInputStream("D:\\javase\\homework\\practice\\day20\\my.txt");
                  out = new FileOutputStream("D:\\javase\\homework\\practice\\day20\\new.txt");
                  byte[] buffer = new byte[10];
                  int length = -1;
                  // in.read 读数据到 buffer
                  while ((length = in.read(buffer)) != -1){
                      out.write(buffer);//把 buffer 中的数据写出去
                  }
      
      
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  try {
                      if (in != null) {
                          in.close();
                      }
                      if (out != null) {
                          out.close();
                      }
                  } catch (IOException e) {
                      e.printStackTrace();
                  }
      
              }
      
字符流
  1. FileReader 输入

    FileReader reader = null;
    try {
        reader = new FileReader("D:\\javase\\homework\\practice\\day20\\my.txt");
        char[] buffer = new char[1024];
        int length = -1;
        while ((length = reader.read(buffer) ) != -1){
            String s = String.valueOf(buffer);
            System.out.println(s);
        }
    } catch (Exception e) {
        e.printStackTrace();
    }finally {
        reader.close();
    }
    
  2. FileWriter 输出

    FileWriter fileWriter = new FileWriter("D:\\javase\\homework\\practice\\day20\\my.txt", true);
    fileWriter.write("你好");
    fileWriter.write("上云");
    //关闭资源
    fileWriter.close();
    
  • 字节流与字符流的选择

    • 二进制文件,图片,音频,视频必须使用字节流
    • 文本文件(txt)使用字符流
    • 不清楚类型,用字节流
  • flush(刷新操作)

    • 计算机直接访问磁盘文件的时候,比操作内存慢,设置一个缓冲区,写的时候直接先写到内存,达到特定值再写到磁盘
    • 使用缓冲区意义:
      • 提高cpu的使用率
      • 回滚写入的数据
    • 操作系统使用 -1 代表磁盘文件结尾的标志
    • IO 是最影响程序性能的,缓冲区设置容量的整数倍,可以去有效的提高 io 性能 1024.

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gZwP1xGu-1664677606241)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220315134846949.png)]

try catch 资源自动释放

  • 语法

    try(需要关闭资源的文件写到这里){
        
    }catch(){
        
    }
    
    public static void copyFile1(String srcFilePath, String destFilePath) {
    
            try (FileInputStream in = new FileInputStream(srcFilePath);
                 FileOutputStream out = new FileOutputStream(destFilePath);
                 
                 ) {
                byte[] buffer = new byte[10];
                int length = -1;
                // in.read 读数据到 buffer
                while ((length = in.read(buffer)) != -1) {
                    out.write(buffer);//把 buffer 中的数据写出去
                }
    
            } catch (Exception e) {
                e.printStackTrace();
            }
    
    
        }
    
缓冲流
  1. 缓冲流:其实就是个包装流,目的是起缓冲的作用,提升io 性能
  2. 字节缓冲流
    • BufferedInputStream 字节缓冲输入流
    • BufferedOutputStream 字节缓冲输出流
  3. 字符缓冲流
    • BufferedReader 字符缓冲输入流
    • BufferedWriter 字符缓冲输出流
使用缓冲流与不使用缓冲流性能的对比
  1. 使用单字节拷贝方式

    • 使用传统字节流

      public static void copy(String srcPath, String destPath) throws IOException {
              long begin = System.currentTimeMillis();
              FileInputStream in = new FileInputStream(srcPath);
              FileOutputStream out = new FileOutputStream(destPath);
              int length = -1;
              while ((length = in.read()) != -1) {
                  out.write(length);
              }
              in.close();
              out.close();
              long end = System.currentTimeMillis();
              System.out.println("拷贝耗时:" + (end - begin));
          }
      
    • 使用 Buffered 缓冲流

       public static void copyBuffer(String srcPath, String destPath) throws IOException {
              long begin = System.currentTimeMillis();
              FileInputStream in = new FileInputStream(srcPath);
              FileOutputStream out = new FileOutputStream(destPath);
              BufferedInputStream bufferedIn = new BufferedInputStream(in);
              BufferedOutputStream bufferedOut = new BufferedOutputStream(out);
      
              int length = -1;
              while ((length = bufferedIn.read()) != -1){
                  bufferedOut.write(length);
              }
              bufferedIn.close();
              bufferedOut.close();
              in.close();
              out.close();
              long end = System.currentTimeMillis();
              System.out.println("buffered 拷贝耗时:" + (end - begin));
          }
      
  2. 读和写外面再加buffer

    • 使用传统字节流

      long begin = System.currentTimeMillis();
      FileInputStream in = new FileInputStream(srcPath);
      FileOutputStream out = new FileOutputStream(destPath);
      int length = -1;
      byte[] buffered = new byte[10];
      while ((length = in.read(buffered)) != -1) {
          out.write(buffered,0,length);
      }
      in.close();
      out.close();
      long end = System.currentTimeMillis();
      System.out.println("copyBufferedBuffered拷贝耗时:" + (end - begin));
      
    • 使用缓冲流

      public static void copyBufferBuffered(String srcPath, String destPath) throws IOException {
              long begin = System.currentTimeMillis();
              FileInputStream in = new FileInputStream(srcPath);
              FileOutputStream out = new FileOutputStream(destPath);
              BufferedInputStream bufferedIn = new BufferedInputStream(in);
              BufferedOutputStream bufferedOut = new BufferedOutputStream(out);
              byte[] buffer = new byte[10];
              int length = -1;
              while ((length = bufferedIn.read(buffer)) != -1){
                  bufferedOut.write(buffer,0,length);
              }
              bufferedIn.close();
              bufferedOut.close();
              in.close();
              out.close();
              long end = System.currentTimeMillis();
              System.out.println("buffered buffer 拷贝耗时:" + (end - begin));
          }
      
    • 总结:使用缓冲流真的快

字符编码

  1. 字符编码的发展流程:

    • 一开始的时候只能存储一个字节,只能认识数字还可以去识别(a-z A-z)ASCII 美国标准信息交换码
    • 随着计算机的普及,很多国家都把自己的字符引入了计算机(汉字)一个字节存储范围太小,用两个字节来存储汉字,使用GB2312 编码 —GBK(2字节)
    • 中国人肯定使用汉字,但是把汉字给其它国家的使用,其它国家不认识,显示?乱码需要统一的编码来管理,Unicode 编码(2字节)
  2. 常见的字符集:

    • ASCII:占一个字节,只能够包含128符号,不能表示汉字
    • ISO-8859-1(lanin-1) : 占一个字节,收录西欧语言,不能表示汉字
    • ANSI:占两个字节,可以表达汉字(GB2312,GBK)
    • UTF-8:是一种针对 Unicode 的可变长度的字符编码,又称万国码。互联网工程小组,要求所有的互联网协议都必须支持UTF-8
  3. 字符的编码以及解码(保证必须使用相同的编码)

    • 编码:把字符串转换成byte 数组
    • 解码:把byte 数组转换成字符串
  4. 实操:

    String str = "上云";
    //将字符串变成一个byte 数组,编码
    byte[] bytes = str.getBytes("utf-8");
    System.out.println(Arrays.toString(bytes));
    //        String csn = Charset.defaultCharset().name();
    //        System.out.println(csn);
    
    //解码操作
    String s = new String(bytes,"ISO-8859-1");
    System.out.println(s);
    
    //编码
    byte[] bytes1 = s.getBytes("ISO-8859-1");
    System.out.println(Arrays.toString(bytes1));
    String s1 = new String(bytes1, "UTF-8");
    System.out.println(s1);
    
    
image-20220315143846663

转换流

  1. 转换流:把字节流转换成字符流
    • InputStreamReader
    • OutputStreamWriter

合并流

  1. 合并流(SequenceInputStream):把多个输入流合并成一个流对象

    image-20220315145258833

对象流

  1. 序列化以及反序列化

    • 序列化(写):把内存中的java对象数据,存储到磁盘中去,或者给其它的网络节点使用
    • 反序列化(读):把磁盘文件的数据恢复成java对象过程
  2. 为什么要使用序列化

    • 在分布式系统中,数据的共享都需要实现序列化(redis)
    • 服务的钝化,把我们不常用的对象存储到磁盘中,节约内存开销
    • 使用 json 传输的时候
  3. 要求:必须实现序列化接口 public interface Serializable

  4. 对象流:

    • ObjectInputStream 做反序列化的,从文件转换成 java 对象

      public static Object readerObject(String path) throws IOException, ClassNotFoundException {
              ObjectInputStream stream = new ObjectInputStream(new FileInputStream(path));
              Object o = stream.readObject();
              stream.close();
              return o;
          }
      
    • ObjectOutputStream 序列化的,把 java 对象转换成文件

       public static void writeObject(String path, Object o) throws IOException {
              ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(path));
              stream.writeObject(o);
              stream.close();
          }
      
  5. 常见问题

    • class invalid for deserialization(没有实现序列化接口)
    • 序列号版本对不上(引入版本号,避免因为属性该表导致不兼容问题)public static final long serialVersionUID = 1;

打印流

  1. 打印流:打印数据的,打印流就只能是输出流

    • PrintStream:字节打印流
    • PrintWriter:字符打印流
  2. 拓展点:

    System.out.println();
    ==
    PrintStream out = System.out;
    out.println();
    
  3. 打印流中的格式化输出(printf(String fomart,Object…arr));

     System.out.printf("姓名:%s,年龄:%d", "上云", 18);
    

扫描器类(Scanner)没啥用

  1. java.util.Scanner :扫描器类,做输入操作的。

    hashNextXXX();//判断有没有这种数据类型的数据
    Xxx nextXX();
    
  2. 基本使用

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        boolean b = scanner.hasNext();
        boolean b1 = scanner.hasNextInt();
        if(b) {
            String next = scanner.next();
            System.out.println(next);
        }
    }
    

数据流

  1. 数据流:提供了可以读/写任何数据类型的方法

    • DataInputStream 提供了 readXXX()方法
    • DataOutputStream 提供了 writeXX(obj)
  2. 操作:

    public static void read(String path) throws IOException {
        DataInputStream in = new DataInputStream(new FileInputStream(path));
        System.out.println(in.readInt());
        System.out.println(in.readUTF());
        in.close();
    }
    
    public static void write(String path) throws IOException {
        DataOutputStream out = new DataOutputStream(new FileOutputStream(path));
        out.writeInt(123123);
        out.writeUTF("你好,这里是上云教学课");
        out.close();
    }
    

Properties

  1. 配置文件,资源文件以 .properties 作为拓展名

    • username=root
    • password=123456
  2. db.properties 文件来做配置文件

    #key=value
    username=root
    password=123456
    
  3. 具体操作

    Properties properties = new Properties();
    
    FileInputStream in = new FileInputStream("D:\\javase\\homework\\practice\\day21\\src\\cn\\sycoder\\PropertiesDemo\\db.properties");
    properties.load(in);
    
    System.out.println(properties);
    System.out.println(properties.get("username"));
    System.out.println(properties.get("password"));
    
  4. ClassLoader类加载器去读(反射的时候补充)

NIO

  1. jdk1.4之后提供的,可以把一块磁盘文件映射到内存中去,java.nio

  2. 应用领域(云服务器)

  3. jdk1.7 提供了一个工具类,Files

     Files.copy(Paths.get("D:\\javase\\homework\\practice\\day21\\my.txt"),
                    new FileOutputStream("D:\\javase\\homework\\practice\\day21\\AAA.txt"));
    
  4. 与 io 有啥不同

    • Channels Buffers(通道和缓冲区):使用通道和缓冲区进行操作,性能更快
    • 异步的:线程从通道读数据到缓冲区的时候,线程还可以做其他的事。
    • Selectors(选择器):选择器可以监听多个通道的事件

反射

类加载机制
  1. jvm 和类的关系

    • 运行带有main方法的类(主方法),启动 jvm 进程,并加载字节码,同一个jvm 所有线程已经变量都处于同一个进程中
    • jvm 何时退出?
      • 程序正常运行结束
      • 出现异常,没有捕获异常时
      • System.exit() 方法
      • 强制杀进程的时候
    • 重点:jvm 进程一旦结束,进程中的内存中的数据会丢失
  2. 类加载机制

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3ZH2aRXO-1664677606242)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220316102102812.png)]

  3. 类加载初始化具体步骤(加载,连接,初始化)

    • 类的加载
      • 类加载器(ClassLoader),将字节码文件(class 文件)加载进内存中,并且创建一个字节码对象(java.lang.Class),类加载器由JVM提供,或者自定义
    • 类的连接(类加载进内存之后,生成 Class 对象,把类的二进制数据合并到 JRE 中)
      • 验证:检测被加载的类是否有正确的内部结构
      • 准备:负责为类的 static 变量分配内存,设置默认值(并不是初始化操作)
      • 解析:把类的二进制数据中的符号引用替换为直接引用(深入分析 jvm)
    • 类的初始化(jvm 负责对类进行初始化,主要是对 static 变量进行初始化)
      • 如果该类未被加载和连接,则程序先加载并连接该类(类还可以动态加载)groovy
      • 如果该类的父类未被初始化,则优先初始化父类
      • 如果该类有初始化语句(静态代码块),系统依次执行这些初始化语句
反射的概述
  1. 问题:Object obj = new String(“abc”);
    • 需求:如何调用 String 中的length 方法
      • 使用强制类型转换
    • 如果不知道真实的类型怎么办?
  2. 问题:一切皆对象,**类这种事物是啥对象?**使用什么类来表示这种对象?
    • Class :表示所有的类
    • Constructor:表示所有的构造器
    • Method :表示所有的方法
    • Field:表示所有的字段
    • 通过反射:得到类的元数据信息(构造器,方法,字段,内部类)
  3. 类加载进内存,变成 Class 对象,也叫字节码对象
Class 类和 Class 实例
  1. Class 表示所有的类

  2. Class 实例表示:一份份的字节码(类,接口,注解)

  3. 各种类如何表示?

    • String Class<java.lang.String>
    • HashMap Class<java.util.HashMap>
  4. 如何获取Class 的实例

    //1:使用类名.class
    Class<String> stringClass = String.class;
    //2:通过对象调用 getClass();
    String str = "abc";
    Class<? extends String> aClass = str.getClass();
    //3:使用类的全限定类名 java.lang.String
    Class<?> aClass1 = Class.forName("java.lang.String");
    Class<?> stuClass = Class.forName("cn.sycoder.ClassObjectDemo.Student");
    System.out.println(stuClass);
    
    • 注意:同一个JVM中,只存在一个类的一份字节码和一份字节码对象
    • 使用最多的 Class.forName(类的全限定类名);
  5. 基本数据类型的字节码如何表示:

    • jvm 已经提前内置好基本数据类型字节码实例

      Class<Integer> aClass2 = int.class;
      
    • 包装类型提供了一个 TYPE 常量,也是可以去获取基本类型的类实例

      Class<Integer> type = Integer.TYPE;
      
    • 如何证明 Integer 和 int 不是同一种数据类型

      Integer.class == int.class
      
类加载
  1. 直接使用类.class

    Class<String> stringClass = String.class;
    
  2. 使用对象调用getClass()

    String str = "abc";
    Class<? extends String> aClass = str.getClass();
    
  3. 使用类全限定类名

    Class<?> aClass1 = Class.forName("java.lang.String");
    Class<?> stuClass = Class.forName("cn.sycoder.ClassObjectDemo.Student");
    
反射操作构造器
  1. Class 去操作 Constructor 类

  2. 常用的方法

    //获取构造器对象
    public Constructor<T> getConstructor(Class<?>... parameterTypes)
    //获取全部构造器对象
    public Constructor<?>[] getConstructors()
    //获取全部构造器包括私有
    public Constructor<?>[] getDeclaredConstructors()
    
  3. 常见错误

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zgxgD35P-1664677606242)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220316111632146.png)]

  4. 常用获取构造器方法

    //获取单个
    Class<?> aClass = Class.forName("cn.sycoder.ConstructorDemo.User");
    Constructor<?> constructor = aClass.getConstructor();
    //获取非私有全部
    Constructor<?>[] constructors = aClass.getConstructors();
    //获取私有的单个
    Constructor<?> declaredConstructor = aClass.getDeclaredConstructor();
    //获取带私有的全部
    Constructor<?>[] declaredConstructors = aClass.getDeclaredConstructors();
    //带参数的
    Constructor<?> constructor1 = aClass.getConstructor(String.class);
    
反射创建对象
  1. 问题:为啥使用反射创建对象,不直接使用 new 创建对象

    • 框架中,多半使用反射创建对象,使用类全限定类名操作
  2. 如何使用反射创建对象

    • 获取类字节码对象

    • 获取构造器对象

    • 通过反射获取的构造器创建对象

      Class<?> aClass = Class.forName("cn.sycoder.ConstructorNewObject.Person");
      Constructor<?> constructor = aClass.getConstructor();
      //通过构造器创建对象
      Object o = constructor.newInstance();
      
    • 如果构造器是私有的,还需要去设置可以访问

      constructor.setAccessible(true);
      

      [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DPNulnui-1664677606243)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220316112823727.png)]

  3. 常见错误:

    • cn.sycoder.ConstructorNewObject.Person with modifiers “private”

      constructor.setAccessible(true);
      
    • Exception in thread “main” java.lang.IllegalArgumentException: wrong number of arguments

       Constructor<?> constructor1 = aClass.getConstructor(String.class, int.class);
      Object o1 = constructor1.newInstance("上云",18);
      
反射操作方法
  1. 实例方法

    • 获取字节码对象

    • 使用构造器获取对象

    • 获取方法对象

    • 反射调用方法

      • 调用方法

        • Object invoke(Object obj,Object…args)
        Class<?> aClass = Class.forName("cn.sycoder.MethedDemo.MethodDemo");
        Constructor<?> constructor = aClass.getConstructor();
        Object o = constructor.newInstance();
        
        
        Method eat = aClass.getMethod("eat");
        Object invoke = eat.invoke(o);
        
        Method eat1 = aClass.getMethod("eat", String.class);
        Object obj = eat1.invoke(o, "鱼");
        
  2. 静态方法

    • 静态方法不属于对象,属于类本身

    • 如何执行:

      • 获取类字节码对象

      • 获取方法对象

      • 执行(invoke)不需要传对象

        Method getName = aClass.getMethod("getName", String.class);
        Object object = getName.invoke(null, "上云");
        System.out.println(object);
        
反射操作字段
  1. 获取类字节码对象

  2. 获取对象

  3. 操作字段

    Class<?> aClass = Class.forName("cn.sycoder.FiledDemo.FiledDemo");
    Constructor<?> constructor = aClass.getConstructor();
    Object o = constructor.newInstance();
    Field age = aClass.getDeclaredField("age");
    age.setAccessible(true);
    
    age.set(o,19);
    
    Object o1 = age.get(o);
    System.out.println(o1);
    
类加载器加载 Properties
  1. 使用绝对路径

    //使用绝对路径
    Properties properties = new Properties();
    FileInputStream in = new FileInputStream(path);
    properties.load(in);
    System.out.println(properties);
    
  2. 使用相对路径从根目录开始找

    Properties properties = new Properties();
    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    InputStream resourceAsStream = classLoader.getResourceAsStream(path);
    properties.load(resourceAsStream);
    System.out.println(properties);
    
  3. 使用相对路径(相对于我们使用的类的文件夹开始)

    Properties properties = new Properties();
    InputStream inputStream = Test.class.getResourceAsStream(path);
    properties.load(inputStream);
    System.out.println(properties);
    

多线程

并行和并发
  1. 需求:边打英雄联盟和边听音乐

  2. 问题:只能先后关系,并不能同时发生

    • 多进程或者多线程来解决
  3. 并行和并发:

    • 并行:多件事情在同一时刻发生

    • 并发:多件事情在同一时间段发生,同一时间段多个程序同时运行

      image-20220316134737264
  4. 单个CPU:一个时间点只能执行一个程序,多个程序可以交替执行。

  5. 线程调度:多个线程以某个顺序执行

进程与线程
  1. 进程:内存中的应用程序,每个进程有一块独立的内存空间,一个应用程序可以同时启用多个进程,有独立内存空间,至少有一个线程
  2. 线程:进程中的执行任务单元,一个进程里面可以拥有多个线程,栈空间独立,堆内存共享
  3. 多线程的优势:因为堆内存是共享的,所以内存的开销是不是较少。
  4. 多线程具体运行那个线程,取决于 CPU调度
  5. java 程序中最少有几个线程:
    • 主线程
    • GC垃圾回收线程
  6. 线程的调度:JVM 采用抢占式的调度方式,没有采用分时概念,谁抢到谁执行。
  7. 多线程的应用:
    • 抢票
    • 游戏
    • 多线程下载
  8. 宽带带宽:以位(bit)计算的,下载速度以字节(byte),1字节=8位
    • 1024KB/s 代表 1M,下载速度,1024/8 128KB/s
多线程实现方式
  1. 继承 Thread 类

    • 重写 run 方法

      public class MusicDemo extends Thread{
          @Override
          public void run() {
              for (int i = 0; i < 10; i++) {
                  System.out.println("听音乐:"+i);
              }
          }
      
      }
      
    • 启动线程,调用 start 方法

      MusicDemo musicDemo = new MusicDemo();
      musicDemo.start();
      
    • 注意:不要去调用 run() 方法

  2. 实现 Runnable 接口

    • 实现Runnable 接口,实现 Run 方法

      public class PlayGame implements Runnable {
          @Override
          public void run() {
              for (int i = 0; i < 10; i++) {
                  System.out.println("打游戏:" + i);
              }
          }
      }
      
    • 启动(先创建对象,再创建 Thread 对象通过构造器获得线程对象)

      PlayGame playGame = new PlayGame();
      Thread thread = new Thread(playGame);
      thread.start();
      
  3. 使用匿名内部类来创建线程(只适用于只使用一次的方式)

    new Thread(new Runnable() {
                @Override
                public void run() {
                    for (int i = 0; i < 10; i++) {
                        System.out.println("统计人头数:" + i);
                    }
                }
            }).start();
    
线程的调度
  1. 线程控制操作:Thread.sleep(1000L);

  2. 线程合并(联合线程):

    • join方法(操作线程先执行完之后,等待线程才执行)
    image-20220316144139526
  3. 守护线程:GC 使用

    • 目的:为其它线程服务的—GC—
    • 特点:主线程结束,守护线程就结束
    • 创建线程:默认是前台线程
    • 获取守护线程thread.setDaemon(true),必须再 start() 方法之前
  4. 获取当前线程及其名称

    • Thread t = Thread.currentThread();
    • t.getName();
  5. 线程设置优先级

    • 注意:优先级高,只不过是获取执行机会更大(取决于CPU调度)

      /**
       * The minimum priority that a thread can have.
       */
      public final static int MIN_PRIORITY = 1;
      
      /**
       * The default priority that is assigned to a thread.
       */
      public final static int NORM_PRIORITY = 5;
      
      /**
       * The maximum priority that a thread can have.
       */
      public final static int MAX_PRIORITY = 10;
      
  6. 线程的让位:

    • yield 方法:当前线程对象去提示CPU调度器自己愿意让出CPU资源(但是调度器可以忽略你的请求)
    • sleep 和 yield 方法的区别
      • 都能使当前处于运行状态的线程暂时放弃 cpu 把机会给其它线程
      • sleep 方法给其它线程运行机会,但是不考虑其它线程的优先级,yield 只会给相同优先级,或者更高优先级的线程运行机会
      • 调用 sleep 方法之后,线程进入计时等待状态,yield 进入就绪状态
线程同步
  1. 需求:猴子(3个 A B C)吃香蕉30个,使用多线程的方式实现

    • 继承 Thread 类的方式

      • 同一个编号的香蕉被多个猴子吃

        public class MonkeyDemo extends Thread {
            private int num = 30;//香蕉总数
            @Override
            public void run() {
                for (int i = 0; i < 30; i++) {
                    if (num > 0) {
                        System.out.println(super.getName() + "吃了编号为:" + num-- + "的香蕉");
                    }
                }
            }
        }
        
        
        MonkeyDemo monkeyA = new MonkeyDemo();
        monkeyA.setName("A");
        
        MonkeyDemo monkeyB = new MonkeyDemo();
        monkeyB.setName("B");
        
        MonkeyDemo monkeyC = new MonkeyDemo();
        monkeyC.setName("C");
        
        monkeyA.start();
        monkeyB.start();
        monkeyC.start();}}
        
    • 实现 Runnable 接口

      • 是否可以共享同一个资源的原因,实现方式可以做到(当有网络延迟的时候,也不可以做到)
      public class MonkeyRunnable implements Runnable{
      
          private int num = 30;
          @Override
          public void run() {
              for (int i = 0; i < 30; i++) {
                  if (num > 0) {
                      System.out.println(Thread.currentThread().getName() + "吃了编号为:" + num-- + "的香蕉");
                  }
              }
          }
      }
      
      MonkeyRunnable runnable = new MonkeyRunnable();
      
      new Thread(runnable,"A").start();
      new Thread(runnable,"B").start();
      new Thread(runnable,"C").start();
      
  2. 解决多个猴子不能同时吃到同一个香蕉的案例

    • 同步代码块

      • 语法

      • 非静态

      • 同步锁是谁?

        • 非静态的来说,同步锁就是 this
        • 静态的来说,类的字节对象(MonkeyRunnable.class)
        synchronized(同步锁){
        }
        
      • 为了保证每个线程都能够正常执行,原子操作,一般的,把当前并发访问的共同资源作为同步监听对象

      • 任何时候,只能运行一个线程拥有同步锁,谁拿到谁执行,其它的等待

      • 不要使用同步锁去修饰 run 方法,修饰之后,某一个线程执行完了其它的才可以执行

    • 同步方法

      synchronized public void eat() {
          //业务逻辑
      }
      
    • 锁机制(Lock):

      Lock lock = new ReentrantLock();
      //上锁
      lock.lock();
              if (num > 0) {
                  System.out.println(Thread.currentThread().getName() + "吃了编号为:" + num-- + "的香蕉");
              }
      //解锁
      lock.unlock();
      
  3. 同步代码块,同步方法,同步锁如何选用?

    • 尽量减少锁的作用域(Synchronized)
    • 建议使用锁机制(很好的去控制锁的作用范围,性能更高)

生产者与消费者模式

  1. 线程通信:不同线程执行不同任务,如果这些任务存在关系,线程之间必须能够通信,协调完成工作

  2. 需求:实现生产者与消费者模式

    • 通过生产者与消费者操作共同资源
    • 使用多个线程来做生产者(Producer)
    • 使用多个线程来做消费者(Consumer)
  3. 生产者以及消费者示意图:(体现面向对象设计原则:低耦合)

    image-20220317105254974
    • 主板与集成显卡(高耦合)

      //主板
      public class Producer{
          private Consumer cu;
      }
      
      //集成显卡
      public class Consumer{
          private Producer p;
      }
      
    • 主板和内存条(方便升级)(低耦合)

      //主板
      public class Producer{
          //资源
          private ShareResource resource;
      }
      
      //内存
      public class Consumer{
          //资源
           private ShareResource resource;
      }
      
      //内存卡槽
      public class ShareResource{
          
      }
      
实现生产者与消费者
public class Producer implements Runnable {

    private ShareResource resource;

    public Producer(ShareResource resource){
        this.resource = resource;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            if(i % 2 == 0){
                resource.push("女士服装","s");
            }else{
                resource.push("男士服装","XXXL");
            }
        }
    }
}
public class Consumer implements Runnable{
    private ShareResource resource;

    public Consumer(ShareResource resource){
        this.resource = resource;
    }

    @Override
    public void run() {
        for (int i = 0; i < 20; i++) {
            resource.pop();
        }
    }
}
public class ShareResource {

    private String name;

    private String size;

    /**
     * 给生产者推送数据的
     *
     * @param name
     * @param size
     */
    public void push(String name, String size) {
        this.name = name;
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        this.size = size;
    }

    public void pop() {
        try {
            Thread.sleep(1000L);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("服装名称:" + this.name + " 尺码: " + this.size);
    }
}
生产者与消费者出现数据紊乱的问题

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qYO4vRSb-1664677606244)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220317111644139.png)]

  1. 问题1:出现数据紊乱问题
    • 解决方案:只要保证生产名字和尺码的过程中保持同步,中间不被消费者消费
      • 同步方法/同步代码块/锁来保持同步性
  2. 问题2:应该生产一个数据消费一个数据
    • 应该交替出现,男士–XXL 女士–s 男士–xxl 女士–s
      • 使用等待唤醒机制
线程通信
  1. ​ 线程通信(wait)和(notify) 方法介绍

    • wait():执行该方法的线程对象要释放同步锁,JVM 会把该线程放到等待池里面,等待其它的线程唤醒它
    • notify():执行该方法的线程唤醒在等待池中的线程,把线程转到锁池中去等待。
    • notifyAll():执行该方法的线程,唤醒在等待池中的所有线程,把这些线程转移到锁池中去等待。
    • 注意点:这些方法,只能被同步监听锁对象锁(同步锁)调用
  2. 同步监听锁对象(同步锁):多个线程有共同对象使用时,多个线程之间才会出现互斥现象,共同的这个对象就叫同步监听锁对象

  3. 同步锁池:同步锁必须选择多个线程共同的资源对象,当生产者生产数据时(先获取锁),生产者没生产出来的时候,消费者只能等待(锁池等待),等生产者生产完,释放同步锁时,消费者此时就可以抢锁来进行消费。

  4. P线程和C线程S对象(同步锁),P,C线程如何通信(wait notify)

    • P线程执行S对象的同步方法,P线程持有S对象的锁,C线程是不是在S对象的锁池中等待。
    • P线程生产完,执行 wait() ,释放S对象的锁,进入S对象的等待池中去等待生产。
    • S对象锁池中等待的C线程获取S对象的锁,执行S对象的消费同步方法。
    • C线程消费结束,执行完S对象的同步消费方法时,执行notify()唤醒P线程,JVM把P从S对象等待池中移到S对象的锁池中,等待获取锁,C 线程释放锁,P获取锁,继续循环。
    public class ShareResource {
    
        private String name;
    
        private String size;
    
        private boolean isEmpty = true;//判断资源对象是否为空
    
        /**
         * 给生产者推送数据的
         *
         * @param name
         * @param size
         */
        synchronized public void push(String name, String size) {
    
            try {
                //判断资源对象是否为空,空的时候等待
                while (!isEmpty){
                    this.wait();
                }
                this.name = name;
                Thread.sleep(1000L);
                this.size = size;
                isEmpty = false;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                this.notify();//唤醒一个消费者
            }
    
        }
    
        synchronized public void pop() {
            try {
                //如果资源为空,消费者等待
                while (isEmpty){
                    this.wait();
                }
                Thread.sleep(1000L);
                System.out.println("服装名称:" + this.name + " 尺码: " + this.size);
                isEmpty = true;
                this.notify();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
        }
    }
    
  5. Lock 和 Condition 接口:

    • wait 和 notify 只能被同步监听锁对象调用,否则报错,但是Lock 机制根本没有同步锁,也没有获取释放锁的逻辑。
    • 使用Condition 接口对象的 await singnal signalAll 方法取代 Object 类中的 wait notify notifyAll 方法
    public class ShareResource {
    
        private String name;
    
        private String size;
    
        private boolean isEmpty = true;//判断资源对象是否为空
    
        private Lock lock = new ReentrantLock();
    
        private Condition condition = lock.newCondition();
    
        /**
         * 给生产者推送数据的
         *
         * @param name
         * @param size
         */
        public void push(String name, String size) {
            lock.lock();//获取锁
            try {
                //判断资源对象是否为空,空的时候等待
                while (!isEmpty){
                    condition.await();
                }
                this.name = name;
                Thread.sleep(1000L);
                this.size = size;
                isEmpty = false;
                condition.signalAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();//释放锁
            }
    
        }
    
        public void pop() {
            lock.lock();//上锁
            try {
                //如果资源为空,消费者等待
                while (isEmpty){
                    condition.await();
                }
                Thread.sleep(1000L);
                System.out.println("服装名称:" + this.name + " 尺码: " + this.size);
                isEmpty = true;
                condition.signalAll();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlock();//释放锁
            }
    
        }
    }
    

建议:建议使用第二种方式

死锁

  1. 多线程通信时,很容易出现死锁现象,死锁并且是不能解决的,只能避免。
    • P线程等待有C线程持有的锁,而我们C线程又去等待P线程持有的锁,发生死锁现象,JVM不检测也不是图避免这种情况
  2. 如何避免死锁:当我们多个线程去访问共享资源的时候 A,B,C,保证每一个线程都按照相同的顺序去访问。
  3. Thread 类有一些过时的方法:
    • suspend() 使正在运行的线程放弃 CPU 暂停运行。
    • resume() 是暂停线程恢复运行
    • 这两方法很容易导致死锁,不要去使用
      • P线程获取锁对象,去执行同步方法,如果C线程调用P线程的暂停方法,此时P就会放弃CPU但是不释放锁。
    • 如何避免:上锁—释放锁

线程的生命周期

  1. 生命周期:一个物品从出生—死亡

  2. 线程的生命周期(Thread.State):

    • NEW:使用new 创建线程对象的时候,只分配了空间,调用 start() 方法的时候,线程启动

    • RUNNABLE:(可运行状态)使用了 start 之后,变成了两种状态

      • ready:准备就绪,等待 cpu 的调度
      • running :获取到了 cpu 的调度
    • BLOCKED:(阻塞的状态)运行中的线程,因为某些原因,放弃了 cpu 暂停运行,此时 jvm 不会给线程分配 cpu

      • 当 P线程处于运行状态时,但是,没有获取到同步锁, JVM 就会把 P线程放到同步锁对象的锁池中去,P阻塞
      • 线程运行中发出(IO请求),此时阻塞
    • WAITING:(等待的状态)等待状态只能被其它线程唤醒,

      • 运行中的线程调用了 wait() 方法,此时 jvm 把当前的线程存放在对象等待池中
    • TIMED_WAITING:(计时等待)wait(long),sleep(long),就变成计时等待

      • 线程运行过程中,调用上面方法,此时 JVM把当前线程存在对象等待池中
    • TERMINATED:(停止)表示线程结束了

      • 正常的执行完线程
      • 出现异常
      image-20220317131530909

定时器

1.Timer 里面有一个常用的方法

Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("----");
            }
        },0,1000L);

线程组

  1. 可以对线程集中管理,ThreadGroup

  2. 用户创建线程对象时,可以通过构造器指定所属的线程组

    ThreadGroup groups = new ThreadGroup("商品上架线程组");
    ThreadGroup groups1 = new ThreadGroup("fihfiwehuif");
    GoodsThread a = new GoodsThread(groups, "A");
    a.start();
    new GoodsThread(groups,"B").start();
    new GoodsThread(groups1,"C").start();
    new GoodsThread("efwefewfewfe").start();
    
    public GoodsThread(ThreadGroup group, String name) {
       super(group,name);
    }
    
  3. A线程中创建B线程,B线程默认加入A线程线程组

  4. 默认创建的线程,都属于main 线程

注解

  1. java 注解:又称为java标记,jdk1.5开始引入的注释机制,注解可以通过反射获取标记的内容,编译器生成类字节码文件时,标记也可嵌入到字节码中。

  2. java 内置注解:

    • 使用在代码上的注解

      • @Override-检查方法是否被重写

        public class Test extends AnnotationDemo {
            @Override
            public void test() {
                super.test();
            }
        }
        
      • @Deprecated-标记过时

        @Deprecated
        public String toLocaleString() {
            DateFormat formatter = DateFormat.getDateTimeInstance();
            return formatter.format(this);
        }
        
      • @SuppressWarnings-忽略注解中声明的警告

    • 元注解(DIV):

      • @Documented:标记这个注解是否包含在用户文档中
      • @Retention:标记注解保存的时间
        • SOURCE:源代码中
        • CLASS:字节码中
        • RUNTME:运行时
      • @Target:标记注解的使用目标
        • METHOD
        • FIELD
        • TYPE
      • @Inherited-标记注解是继承哪个注解类(默认是没有继承的)
    • 自定义注解

      @Target(ElementType.METHOD)
      @Retention(RetentionPolicy.RUNTIME)
      public @interface MyAnnotation {
          String value() default "MyAnnotation";
      }
      
      @MyAnnotation("eat1")
      public void eat(){
      //s
      }
      
自定义注解
  1. 案例:自定义关系型数据库的动态sql (mybatis)

    select username,address,phone from user where username=zhangsan and password=123456
    
java8 特性
  1. Lambda表达式:允许一个函数作为方法参数传递到方法中去

    (parm)->expression;
    或
    (parm)->{expression;}
    
    • 实操

      Callable<Integer> integerCallable = () -> 5;
      
      IntFunction<Integer> integerIntFunction = (int x) -> (3 * x);
      
      IntBinaryOperator intBinaryOperator = (int a, int b) -> a + b;
      
      Consumer<String> stringConsumer = (String s) -> {
              System.out.println(s);
          };
      
  2. Stream:数据源的元素队列,支持聚合操作(想象成流)

    • 数据源:集合,数组

    • 聚合操作:filter,map,reduce,find,match,sorted

    • 实操

      • filter(过滤)

        List<String> list = new ArrayList();
                list.add("A");
                list.add("");
                list.add("B");
                System.out.println(list);
                List<String> collect = list.stream().filter(x -> !x.isEmpty()).collect(Collectors.toList());
        
      • forEach(循环)

        list.stream().forEach(x-> System.out.println(x));
        
      • map(做映射)

         List<Integer> collect1 = list1.stream().map(x -> x * x).collect(Collectors.toList());
        
      • limit(截取指定数量)

        List<Integer> collect2 = list1.stream().limit(2).collect(Collectors.toList());
        
      • sorted(排序)

        List<Integer> collect3 = list1.stream().sorted((a, b) -> b.compareTo(a)).collect(Collectors.toList());
        
      • Collectors(工具类)

        Collectors.toList()
        Collectors.toSet()
        Collectors.toMap()
        
      • mapToInt(统计操作,max,min,avg,sum)

        IntSummaryStatistics intSummaryStatistics = list1.stream().mapToInt(a -> a).summaryStatistics();
                System.out.println(intSummaryStatistics.getMin());
        
  3. 接口中提供默认方法和静态方法

    • 默认方法

      public interface DefaultInterfaceDemo {
          
          default void eat(String name){
              System.out.println(name);
          }
      }
      
    • 静态方法

      static void eat(String name,int count){
              System.out.println(name);
          }
      
  4. 新的 date api

    • 旧版存在问题:

      • 设计较差(java.util,java.sql 都有date)
      • 非线程安全的
      • 处理时区比较麻烦
    • 新版提供:

      • Local(本地):简化了日期处理,没有时区的问题
      • Zoned(时区):指定时区处理时间
      //获取当前时间
      LocalDateTime now = LocalDateTime.now();
      System.out.println(now);
      
      //获取时间的年月日
      System.out.println(now.getYear() +""+ now.getMonthValue() + now.getDayOfMonth());
      
      //解析
      DateTimeFormatter pattern = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
      LocalDateTime parse = LocalDateTime.parse("2025-10-11 11:11:12", pattern);
      System.out.println(parse);
      
      ZoneId zoneId = ZoneId.systemDefault();
      System.out.println(zoneId);
      
      ZoneId of = ZoneId.of("Asia/Shanghai");
      System.out.println(of);
      

网络编程

网络概述
  1. 什么是计算机网络:指将地理位置不同的具有独立功能的多台计算机及其设备,通过通信线路连接起来,在网络操作系统,网络管理软件及其网络通信协议的管理和协调下,实现信息共享和资源传递

  2. 划分:

    • 网络划分:

      • 局域网
      • 广域网
      • 互联网
    • 网络分层:减少网络设计的复杂性,提供一个规范。不同机器上同等功能层必须采用相同的协议

      image-20220318110234533
    • 网络模型:使用OSI七层架构TCP和IP体系

    • TCP/IP :是网络互联的通信协议

      • 应用层:TELNET,FTP,SMTP等
      • 运输层:
        • TCP:是可靠的,通过三次握手来连接数据传输服务
        • UDP:不可靠的,是无连接的数据传输服务
      • 网络层:主要解决主机到主机之间的通信问题(网络协议,IP可靠的协议,无连接的数据传递服务)
      • 网络接口层:负责监视数据在主机和网络之间的交换
  3. 套接字:源IP和目的IP以及端口号和目的端口号的组合,用来标识客户端请求的服务器和服务

  4. 网络编程:使用套接字来达到进程间通信目的的编程就是网络编程

  5. 进程间通信:同一电脑不同进程之间通信,(网络连接)A电脑中的进程和B电脑进程通信

  6. java.net 包

IP
  1. ip:网络之间互联的协议

  2. ip版本:

    • ipv4:192.168.2.12
    • ipv6:fe80::495a:afb0:a010:1442%7
    • ip 地址编址方案:
      • A(10.0.0.0)10.255.255.255
      • B(172.16.0.0)172.16.255.255
      • C(192.168.0.0)192.168.255.255
  3. 本机地址

    • localhost
    • 127.0.0.1
    • 本机ip(cmd - ipconfig)
  4. 实操

    InetAddress ip = InetAddress.getByName("LAPTOP-IQLK33VN");
    System.out.println(ip.getHostName());
    System.out.println(ip.getHostAddress());
    
PORT
  1. 端口:设备和外界设备通信交流的出口
    • 常用端口:80,8080,3306,6379
  2. 注意:同一台电脑中,不能同时出现同一个端口,端口冲突
协议
  1. 协议:网络协议的简称,是计算机双方必须遵守的规则
  2. http:超文本传输协议(不收费)
  3. https:使用安全的套接字传输的超文本协议(收费)
  4. ftp:文件传输协议
  5. file:文件,本机电脑或者网上分享的文件
URI 与 URL
  1. URI:统一资源标识符,是用来标识某一个互联网资源名称的字符串
    • 包含:主机名,端口,标识符,相对uri
    • http://www.baidu.com/hello.html
  2. URL:统一资源定位符,是互联网的标准资源地址
    • 包含:主机名,端口,标识符,具体路径
    • http://ip:80/home/index.png
传输层协议
  1. TCP:面向连接(经历三次握手)、传输可靠(保证了数据正确性,数据顺序的正确性),用来传输数据量大,(流模式)、速度慢,建立连接开销大。服务端和客户端
  2. UDP:面向非连接、传输不可靠(丢包(数据丢失))、用于传输少量数据(数据报包模式)、速度快。发送端和接收端

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6EkgfB56-1664677606244)(G:\学习资料\十指波\上云JavaSE最新基础课程\笔记\picture-master\static\image-20220318135045397.png)]

TCP
public class Client {

    public static void main(String[] args) throws IOException {
        Socket socket = new Socket("127.0.0.1", 9999);
        InputStream in = socket.getInputStream();
        Scanner scanner = new Scanner(in);
        while (scanner.hasNext()){
            System.out.println(scanner.next());
        }

        scanner.close();
        socket.close();
    }
}
public class Server {

    public static void main(String[] args) throws IOException {
        //创建服务端,指定端口为9999
        ServerSocket socket = new ServerSocket(9999);

        System.out.println("服务端准备就绪");
        //获取客户端的连接请求,阻塞的。
        Socket accept = socket.accept();
        System.out.println("获取到客户端的连接:"+accept.getInetAddress());
        PrintStream printStream = new PrintStream(accept.getOutputStream());
        printStream.print("你好,这里是服务端,感谢你的连接");
        printStream.close();

        socket.close();
    }
}
UDP
public class Send {

    public static void main(String[] args) throws IOException {
        String data = "我是发送者";
        //创建发送端对象
        DatagramSocket datagramSocket = new DatagramSocket(10010);
        //发送数据
        DatagramPacket packet = new DatagramPacket(data.getBytes(),//发送的数据
                data.getBytes().length,//发送多长
                InetAddress.getLocalHost(),//目标发送地址
                110);//发送的端口

        datagramSocket.send(packet);
        datagramSocket.close();
    }
}

public class Receive {

    public static void main(String[] args) throws IOException {
        //创建接收对象
        DatagramSocket datagramPacket = new DatagramSocket(10010);
        byte[] buffer = new byte[1024];
        //接收数据
        DatagramPacket packet = new DatagramPacket(buffer, 1024);
        datagramPacket.receive(packet);
        String string = new String(buffer, 0, packet.getLength());
        System.out.println(string);

        datagramPacket.close();
    }
}
常见错误
Exception in thread "main" java.net.BindException: Address already in use: Cannot bind
	at java.net.DualStackPlainDatagramSocketImpl.socketBind(Native Method)
	at java.net.DualStackPlainDatagramSocketImpl.bind0(DualStackPlainDatagramSocketImpl.java:80)
	at java.net.AbstractPlainDatagramSocketImpl.bind(AbstractPlainDatagramSocketImpl.java:94)
	at java.net.DatagramSocket.bind(DatagramSocket.java:392)
	at java.net.DatagramSocket.<init>(DatagramSocket.java:242)
	at java.net.DatagramSocket.<init>(DatagramSocket.java:299)
	at java.net.DatagramSocket.<init>(DatagramSocket.java:271)
	at cn.sycoder.UdpDemo.Send.main(Send.java:14)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小郑在努力ing

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值