1. JavaSE

第一阶段模块一 JavaSE Java语言基础

Chapter1 初识计算机和Java语言

0. 计算机

  • 计算机 - 用于高级计算,使用非常广泛的设备,主要计算机硬件和计算机软件两个部分组成。
    (游戏,视频,结账,医疗)
    (硬件 - 客观存在的各种计算机相关设备,看得见摸得着)
    (软件 - 控制各硬件设备完成各种功能,看得见摸不着)

  • 硬件 - 中央处理器(CPU),内存,硬盘,输入输出设备,主板,机箱,电源
    (CPU - 解释计算机指令以及处理计算机软件中的数据,负责读取指令,对指令译码并执行)
    (内存 - 它是外存与CPU进行沟通的桥梁,计算机中所有程序的运行都在内存中进行, 暂时存放CPU中的运算数据,与硬盘等外部存储器交换的数据)
    (硬盘 - 计算机最主要的存储设备,容量是计算机最主要的参数)

  • CPU - 中央处理器(Central Processing Unit)
    (大脑的思考部分,运算核心,控制核心,解释指令,处理软件数据)

  • 内存 - 存储部件(Memory)
    (暂时存放CPU中的运算数据,硬盘等外部存储器交换的数据)
    (CPU可以直接访问内存的数据,效率高)
    (容量小16G,断电数据丢失)
    (ctrl+s进行保存,数据从内存到硬盘)

  • 硬盘 - 存储部件
    (永久存放数据内容,容量大,断电数据不丢失)
    (CPU不能直接访问硬盘数据,先加载到内存中)
    (内存 硬盘 性能互补 缺一不可)

  • 软件 - 系统软件,应用软件
    (系统软件 - 操作系统,其他软件的基础,Windows,Unix,Linux,IOS,Android)
    (应用软件 - 基于操作系统装在操作系统上的软件,QQ,微信)

1. 计算机的体系结构

  • 配置 - 硬件 Hardware
  • 装系统 -
    1.操作系统内核 内部的核心代码 OS Kernet
    2.操作系统外壳(GUI/命令)OS Shell(KDE bash csh)
  • 装软件 - 浏览器,音乐,下载

2. Java语言的概述

  • 计算机语言发展
    第一代语言 - 机器语言,二进制代码,打孔
    第二代语言 - 汇编语言,助记符表示一条机器指令 ADD SUB
    第三代语言 - 高级语言,Java,C,C++,PHP,Python,Scala

  • Java语言发展
    20世纪90年代,单片机系统,家电设备+单片机系统=智能家电,sun公司,绿色计划=抢占智能家电市场,C++缺陷,不能跨平台=硬件设备换了代码可能要改=每台设备开发代码,C++改写=Java
    1995年 Java问世
    1996年 Java 1.0
    1999年 Java 1.2 JAVA SE,JAVA EE,JAVA ME
    2004年 Java 5.0 Tiger 发布
    2011年 Java 7.0 Oracle发布 7月
    2014年 Java 8.0 Oracle发布 3月19日
    2017年 Java 9.0 Oracle发布 9月21日
    2018年 Java 11 Oracle发布 9月25日

  • Java语言版本
    Java SE(Java Platform,Standard Edition)基础版,office
    Java EE(Java Platform,Enterprise Edition)企业版,构建在基于SE之上,企业级应用,网银系统
    Java ME(Java Platform,Micro Edition)微型版,Android之后被淘汰

  • 开发工具下载安装
    www.sun.com www.oracle.com
    下载 Java SE 11(LTS) ( long time suport),JDK Download,Windows 64bit

  • 相关概念
    JDK - Java开发工具包(Java Development Kit)
    JRE - Java SE 运行时环境(Java SE Runtime Enviroment)
    (提供运行Java应用程序必须的软件环境)
    javac.exe - 编译器,高级Java源代码翻译成字节码(二进制)文件
    java,exe - 解释器,启动JVM对字节码文件进行解释并运行
    JVM+运行类库=JRE+编译器等开发工具=JDK
    JDK的目录结构
    bin - binary,存放JDK的各种工具命令
    conf - config,存放JDK的相关配置文件
    include - 存放平台的头文件
    jmods - 存放JDK的各种模块
    legal - 存放JDK的个模块的授权文档
    lib - 存放JDK的一些补充jar包和源代码

3. 开发环境的搭建和使用

  • Java开发工具
    文本 - Notepad++
    Eclipse - 免费
    MyEclipse - 收费
    IDEA - 收费,使用的人多,方便用

  • 编写Java程序的流程

  1. 新建文本文档,文件扩展名由 xxx.txt 修改为 xxx.java;
  2. 使用记事本/Notepad++的方式打开文件,编写Java代码后进行保存;
  3. 启动dos窗口,并切换到.java文件所在的路经中;
  4. 使用javac xxx.java进行编译,生成xxx.class的字节码文件;
  5. 使用java xxx.class 进行解释执行,打印最终结果;
  • Java11新特性之间的编译运行
  1. 新建文本文当,将文件扩展名由xxx.txt修改为xxx.java;
  2. 实用记事本/Notepad++的方式打开文件,编写Java代码后进行保存;
  3. 启动dos窗口,并切换到.java文件所在的路经中;
  4. 使用java xxx.class 进行解释运行,打印最终结果(慎用);

  • 注释
  1. 注释用于进行代码说明,是给程序员看的文字描述,编译器会忽略注释
  2. 基本分类
    // 单行注释,从 // 开始,到本行结束,都是注释。
    /* / 多行注释, 从/开始,到/结束,中间所有都是注释。
    /
    * */ 多行/文档注释, 从/*开始,到/结束,是一种支持提取的注释。
    注意:多行注释不允许嵌套使用(多行注释里面不能再嵌套多行注释)
  • 环境变量的配置
  1. 基本概念
    通常情况下可执行文件只能在该文件所在的路经中使用,为了使得该可执行文件在任意路经中使用,
    测需要将该文件所在的路经信息配置到环境变量Path中。
    (xxx.java 只能放在bin下面才能执行,麻烦)
  2. 配置方法1
    高级系统设置 - 环境变量 - 系统变量 - Path - 将javac.exe所在的路经信息配置到Path变量的最前面
    注意:配置完重启dos窗口
  3. 配置方法2
    (以后安装新版,Path要重新写,难找)
    C:\Program Files\Java\jdk-11.0.2\bin
    新建变量:变量名JAVA_HOME 变量值C:\Program Files\Java\jdk-11.0.2
    C:\Program Files\Java\jdk-11.0.2\bin = %JAVA_HOME%\bin
  • 跨平台原理
    Java字节码可以通过JVM翻译为具体平台能够执行的机器指令。由于Sun定义了JVM规范,而且不同的操作系统大多提供了JVM实现,才使得相同的一个字节码文件可以在不同的系统上运行,从而使Java赢了“一次编译,到处使用”的美名。

4. 重点

  • jdk,jre,javac.exe,java.exe 背概念
    JDK - Java开发工具包(Java Development Kit)
    JRE - Java SE 运行时环境(Java SE Runtime Enviroment)
    javac.exe - 编译器,高级Java源代码翻译成字节码(二进制)文件
    java,exe - 解释器,启动JVM对字节码文件进行解释并运行

  • 跨平台原理 会说

    Java字节码可以通过JVM翻译为具体平台能够执行的机器指令。由于Sun定义了JVM规范,而且不同的操作系统大多提供了JVM实现,才使得相同的一个字节码文件可以在不同的系统上运行,从而使Java赢了“一次编译,到处使用”的美名。

Chapter2 变量和数据类型

1. 变量

变量的基本概念

  • 当需要在程序中记录单个数据内容时,则声明一个变量即可,而声明变量的本质就是在内存中申请一个存储单元,由于该存储单元中的数据内容可以发生改变,因此得名为"变量"。

  • 由于存放的数据内容大小不一样,导致所需存储单元的大小不一样,在Java语言中使用数据类型加以描述,为了便于下次访问还需要给该变量指定一个名字,用于记录该变量对应的存储单元。

变量的声明方式

  • 数据类型 变量名 = 初始值;
    注意:其中=初始值可以省略,但;不可以省略

变量的注意事项

  • Java是强类型语言,变量在使用前必须声明来指明其数据类型。
  • 变量在使用之前必须初始化。
  • 变量不能重复声明

标识符的命名法则(笔试)

  • 由数字、字母、下划线以及$等组成,其中数字不能开头(后面讲到)。
  • 不能使用Java语言的关键字,所谓关键字就是Java语言用于表示特殊含义的单词。
  • 区分大小写,长度没有限制但不宜过长。
  • 尽量做到见名知意,支持中文但不推荐使用。
  • 标识符可以给类/变量/属性/方法/包 起名字。

变量输入输出

  • import java.util.Scanner;
  1. 声明两个变量 名字 年龄
    String name;
    int age;
  2. 提示用户从键盘输入名字和年龄,放入到变量中
    Scanner sc = new Scanner(System.in);
    name = sc.next();
    age = sc.nextInt();
    *输入时 enter 来区分 name 和 age 的输入
  3. 打印变量的数值

官方库的使用

  • JDK中带有大量的API(Scanner)类, 是有Java系统带来的工具库, 这些工具数以万计! 是Java官方程序员的技术积累。
  • 使用这些类可以大大简化编程, 提高开发效率。
  • 具体的API类功能, 可以参阅Java的参考手册。

2. 数据类型

数据类型的分类

  • 在Java语言中数据类型主要分为两大类:
  • 基本数据类型(记住)
    byte、short、int、long、float、double、boolean、char
  • 引用数据类型(了解)
    数组、类、接口、枚举、标注

常用的进制

  • 在日常生活中采用十进制进行数据的描述,
    逢十进一,十进制权重是:100、101、10^2、…

  • 在计算机的底层采用0和1组成的二进制序列进行数据的描述,
    逢二进一,二进制的权重是20、21、2^2、…

  • 二进制中的最高位(最左边)用于代表符号位,
    若该位是0则表示非负数,
    若该位是1则表示负数。

  • 八进制和十六进制其实都是二进制的简写。

进制之间的转换

  • 正十进制转换为二进制的方式

    1. 除2取余法,使用十进制整数不断地除以2取出余数,直到商为0时将余数逆序排序。
      十进制45转换为二进制的结果为:0B10 1101

      (转换后应该是64位二进制,不过前面都是0,所以前面的0省略了,就剩了10 1101)
      (0B:告诉系统这是二进制)
      (0 :告诉系统这是八机制)
      (0X :告诉系统这是十六机制)

    2. 拆分法,将十进制整数拆分为若干个二进制权重的和,有该权重下面写1,否则写0。

        ...  128  64  32 16       8  4  2  1
              0   0   1   0       1  1  0  1
           
        45 = 32 + 8 + 4 + 1  =>  0010 1101
      
  • 正二进制转换为十进制的方式

    a.加权法,使用二进制中的每个数字乘以当前位的权重再累加起来。(负数的需要补码:按位取反,再加1 )

     0010 1101     =>     0*2^7 + 0*2^6 + 1*2^5 + 0*2^4 + 1*2^3 + 1*2^2 + 0*2^1 + 1*2^0 = 45
    
  • 负十进制转换为二进制的方式

    a.先将十进制的绝对值转换为二进制,然后进行按位取反再加1。

     十进制-45转换为二进制的结果:1101 0011
         => 十进制绝对值45
         => 转换二进制:	0010 1101
         => 按位取反:  	1101 0010
         => 再加1:		1101 0011
         * -45 + 45 = 0 
         * -45:1101 0011
         *  45:0010 1101 +         =>  1 0000 0000
         * 应该是 64位 + 64位 ,这里只写了 8位 + 8位,65位是 1 剩下是0,9位是1剩下的是0
         * 电脑是 64bit 所以只能 显示到64位,(65位)高位溢出,丢弃
    
  • 负二进制转换为十进制的方式

    1. 先减1再按位取反,合并为十进制整数后添加负号。
      负二进制1101 0011 转换为十进制的结果是:
      => 先减 1 :1101 0010
      => 按位取反:0010 1101
      => 转十进制:1+4+8+32=45
      => 添加负号:-45

单个字节(Byte=8bit)表示的整数范围(重中之重)

  • 在计算机中单个字节表示八位二进制位,其中最高位(最左边)代表符号位,
    使用0代表非负数,使用1代表负数,具体表示的整数范围如下:

  • 非负数表示范围:0000 0000 ~ 0111 1111 => 0 ~ 127 => 0 ~ 2^7-1

  • 负数表示范围:1000 0000 ~ 1111 1111 => -128 ~ -1 => -2^7 ~ -2^0

  • 单个字节表示的整数范围是:-2^7 ~ 2^7-1,也就是-128 ~ 127.

整数类型

  • Java语言中描述整数数据的类型有:byte、short、int、long,荐int类型

  • 其中byte类型在内存空间中占1个字节,表示范围是:-2^7 ~ 2^7-1 -128~127.

  • 其中short类型在内存空间中占2个字节,表示范围是:-2^15 ~ 2^15-1 - 32 768 ~ 32 767.

  • 其中int类型在内存空间中占4个字节,表示范围是:-2^31 ~ 2^31-1. - 2147483648 ~ 2147483647

  • 其中long类型在内存空间中占8个字节,表示范围是:-2^63 ~ 2^63-1.

  • 在Java程序中直接写出的整数数据叫做直接量/字面值/常量,默认为int类型。
    若希望表达更大的直接量,则在直接量的后面加上l或者L,推荐L。

  • 声明一个long类型的变量并初始化,若描述比long类型还大的数据则使用java.math.BigInteger类型

浮点类型

  • Java语言中用于描述小数数据的类型:float 和 double,推荐double类型

  • 其中float类型在内存空间占4个字节,叫做单精度浮点数,可以表示7位有效数字,
    范围:-3.403E38~3.403E38。

  • 其中double类型在内存空间占8个字节,叫做双精度浮点数,可以表示15位有效数字,
    范围:-1.798E308~1.798E308。

  • Java程序中直接写出的小数数据叫做直接量,默认为double类型,若希望表达float类型的直接量,
    则需要在直接量的后面加上f或者F.

  • System.out.println(0.1+0.2); //0.30000000000000004 运算时可能会有误差,
    金钱不能有误差用: java.math.BigDecimal

布尔类型

  • Java语言中用于描述真假信息类型有:boolean,数值只有:true 和 false(没有1和0)。

  • 布尔类型在内存空间中所占大小没有明确的规定,可以认为是1个字节。

字符类型

  • Java语言中用于描述单个字符的数据类型:char类型。如:‘a’、'中’等。

  • 其中char类型在内存空间中占2个字节并且没有符号位,
    表示的范围是:0 ~ 65535,由于现实生活中很少有数据能够被单个字符描述,
    因此以后的开发中更多的使用由多个字符串起来组成的字符串,
    使用String类型加以描述,如:“hello”、“奇点”等。

  • 计算机的底层只识别0和1组成的二进制序列,对于字符’a’这样的图案来说不满足该规则,因此该数据无法直接在计算机中存储,但现实生活中存在这样的图案数据需要计算机存储,为了使得该数据能够存储起来就可以给该数据指定一个编号,然后将编号存储起来即可,该编号就叫做ASCII。

  • 要求掌握的ASCII有:‘0’ - 48 ‘A’ - 65 ‘a’ - 97 空格 - 32 换行符 - 10

  • Java字符类型采用Unicode字符集编码。Unicode是世界通用的定长字符集,所有的字符都是16位。

  • 要求掌握的转义字符有:

      										\" - " 
                                            \' - ' 
                                            \\ - \ 
                                            \t - 制表符 
                                            \n - 换行符
    

基本数据类型之间的转换

  • Java语言中基本数据类型之间的转换方式:自动类型转换和强制类型转换。

  • 其中自动类型转换主要指从小类型到大类型之间的转换。

  • 其中强制类型转换主要指从大类型到小类型之间的转换,
    语法格式如下:目标类型 变量名 = (目标类型)源类型变量名;

  • 强转有风险,操作需谨慎!

3. 总结

  • 变量
    变量概念,变量的声明方式,标识符(变量名)的命名法则,变量的输入输出

  • 数据类型
    基本数据类型:byte short int long float double boolean char
    常见的进制:十进制,二进制,十和二之间的转换,单个字节表示的整数范围
    数据类型之间的转换:自动类型转换,强制类型转换
    常用的ASCII和转义字符

Chapter 3 Java语言的运算符

1. 运算符

算术运算符

  • + 表示加法运算符

  • - 表示减法运算符

  • * 表示乘法运算符

  • / 表示除法运算符

  • % 表示取模/取余运算符

算术运算符案例题目

  • 提示用户输入正整数类型的秒数,拆分秒数后输出x小时x分x秒。
  • 如:输入7199,输出1小时59分59秒。

字符串连接运算符

  • + 可以实现字符串的连接。同时可以实现字符串与其他数据类型“相连”。
  • 只要+两边的操作数中有一个操作数是字符串类型,则该+就被当做字符串连接符处理

关系/比较运算符

  • > 表示是否大于运算符 >= 表示是否大于等于运算符

  • < 表示是否小于运算符 <= 表示是否小于等于运算符

  • == 表示是否等于运算符 != 表示是否不等于运算符

  • 所有以关系运算符作为最终运算的表达式结果一定是boolean类型。

案例题目

  • 提示用户输入一个整数,使用关系运算符判断该整数是否为负数,
    若是则打印true,若不是则打印false。

自增减运算符

  • ++ 表示自增运算符,用于使得当前变量自身的数值加1的效果

  • – 表示自减运算符,用于使得当前变量自身的数值减1的效果

  • 只能用于变量,常数不可以

  • 前后加加的区别,
    ia++这个整体叫表达式,其中ia是操作数、变量 => ia++和 ia 所占的内存空间不同
    后++ 表示先让ia的数值作为整个表达式的最终结果,然后再让ia变量自身的数值加1
    前++表示先让变量自身的数值加1,然后再让变量的数值作为整个表达式的结果

逻辑运算符

  • && 表示逻辑与运算符,相当于"并且",同真为真,一假为假。

  • || 表示逻辑或运算符,相当于"或者",一真为真,同假为假。

  • ! 表示逻辑非运算符,相当于"取反",真为假,假为真。

  • 逻辑运算符的操作数均为boolean表达式。

逻辑运算符的图解

在这里插入图片描述

逻辑运算符的短路特性

  • 对于逻辑与运算符来说,若第一个表达式为假则结果为假,此时跳过第二个表达式;
  • 对于逻辑或运算符来说,若第一个表达式为真则结果为真,此时跳过第二个表达式;

案例题目

  • 提示用户输入一个正整数,使用逻辑运算符判断该正整数是否为三位数,
    若是则打印true,否则打印false。

条件/三目运算符

  • 条件表达式? 表达式1: 表达式2
  • 判断条件表达式是否成立,若成立则执行表达式1,否则执行表达式2 。

案例题目

  • 提示用户输入两个整数,使用三目运算符找到最大值并打印出来。

赋值运算符

  • = 表示赋值运算符,用于将=右边的数据赋值给=左边的变量,覆盖变量原来的数值。

  • 赋值表达式本身也有值,其本身之值即为所赋之值。

  • +=、 -=、*=、 /=、 … (复合赋值)

移位运算符(了解)

  • << 左移运算符,用于将数据的二进制位向左移动,右边使用0补充
    左移1位相当于当前整数的数值2
    13 << 1 -------- 26 = 13
    2
    13 << 2 -------- 52 = 1322

  • >> 右移运算符,用于将数据的二进制位向右移动,左边使用符号位补充
    右移1位相当于当前整数的数值/2

  • >>> 表示逻辑右移运算符,用于将数据的二进制位向右移动,左边使用0补充。
    对非负数来说,逻辑右移和右移的效果一致

运算符的优先级

  • ()的优先级极高。

  • =的优先级极低。

  • 若无法确认优先级,则使用()来确保即可。

在这里插入图片描述

2. 总结

Chapter 4 流程控制语言

1. 分支结构

分支结构的概念

  • 当需要进行条件判断并做出选择时,使用分支结构。
    在这里插入图片描述

if分支结构

  • if(条件表达式) { 语句块; }
  • 判断条件表达式是否成立
    => 若成立,则执行语句块;
    => 若不成立,则跳过语句块;
    在这里插入图片描述

案例题目

  • 提示用户输入两个整数,使用if分支结构找到最大值并打印出来。
    (利用 max 变量)

if else分支结构

  • if(条件表达式) { 语句块1; } else { 语句块2; }
  • 判断条件表达式是否成立
    => 若成立,则执行语句块1;
    => 若不成立,则执行语句块2;
    在这里插入图片描述

案例题目

  • 提示用户输入一个整数,使用if else分支结构判断该整数是负数还是非负数并打印。
  • 使用if else分支结构判断该整数是正数、负数还是零。

if else if else分支结构

  • if(条件表达式1) { 语句块1; }
    else if(条件表达式2) { 语句块2; }
    else { 语句块n; }
  • 判断条件表达式1是否成立
    => 若成立,则执行语句块1;
    => 若不成立,则判断条件表达式2是否成立
    => 若成立,则执行语句块2;
    => 若不成立,则执行语句块n;
    在这里插入图片描述

案例题目 1

  • 根据用户输入的薪水计算个人所得税并打印出来,其中个税起征点为:5000元,具体规则如下:
    在这里插入图片描述

案例题目 2

  • 出租车计费方式:由里程钱数和等候时间钱数相加得出。
  • 里程数前3公里13元,超过3公里到15公里部分每公里2元,15公里以上部分每公里3元。
  • 等候时间每2分半1元,不足部分不要钱。
  • 输入公里数和等候秒数,输出车费。
  • 16公里,等候290秒,车费 = 13 +(15-3)*2 + (16-15)*3 + 1 = 41

案例题目 3

  • 提示用户输入考试的成绩,使用if-else if-else分支结构判断所在等级并打印。
    [90 ~ 100] 等级A
    [80 ~ 89] 等级B
    [70 ~ 79] 等级C
    [60 ~ 69] 等级D
    [0 ~ 59] 等级E

switch case分支结构

  • switch(变量/表达式) {
     case 字面值1: 语句块1; break;
     case 字面值2: 语句块2; break;
     …
     default:语句块n;
    }
  • case 穿透 不符合case9 但是执行代码遇见break后跳出去
  • 计算变量/表达式的数值 => 判断是否匹配字面值1
    => 若匹配,则执行语句块1 => 执行break跳出当前结构
    => 若不匹配,则判断是否匹配字面值2
    => 若匹配,则执行语句块2 => 执行break跳出当前结构
    => 若不匹配,则执行语句块n
  • switch()中支持的数据类型有:byte、short、char以及int类型,从jdk1.5开始支持枚举类型,从jdk1.7开始支持String类型。
    在这里插入图片描述

案例题目

  • 使用switch case分支结构模拟以下菜单效果。
    在这里插入图片描述

2. 循环结构

循环结构的概念

  • 在Java程序中若希望重复执行一段代码时,就需要使用循环结构。
  • 任何复杂的程序逻辑都可以通过顺序、分支、循环三种程序结构实现。
    在这里插入图片描述

for循环

  • for(初始化表达式; 条件表达式; 修改初始值表达式) { 循环体; }
  • 执行初始化表达式 => 判断条件表达式是否成立
    => 成立则执行循环体 => 修改初始值表达式 => 判断条件是否成立
    => 若不成立,则循环结束
    在这里插入图片描述

案例题目 1

  • 使用for循环打印1-100的所有奇数,使用三种方式。

案例题目 2

  • 使用for循环实现累加:1+2+…+10000=?最后打印出来。

案例题目 3

  • 使用for循环打印三位数中所有水仙花数。
  • 所谓“水仙花数”即一个整数满足其值等于各个数位的立方和。
  • 如:153是一个水仙花数,因为153=13+53+3^3。

continue关键字

  • continue语句用在循环体中,用于结束本次循环而开始下一次循环。

案例题目

  • 使用for循环打印1 ~ 20之间的所有整数,若遇到5的倍数则跳过不打印。

break关键字

  • break用于退出当前语句块,break用在循环体中用于退出循环。
  • for( ; ; ) - 这种没有循环条件的循环叫做 无限循环,俗称“死循环”。
  • cmd结束无限循环 : Ctrl+C后输入"y"后回车

案例题目

  • 不断地提示用户输入聊天内容并输出,直到用户输入”bye”结束聊天。

案例题目

  • 猜数字游戏
  • 随机生成数字n(1-100), 等待用户输入猜测数据, 根据用户的输入比较输出猜大了,猜小了,猜对了,
    如果用户猜对了就结束游戏 。

双重for循环的格式

  • for(初始化表达式1; 条件表达式2; 修改初始值表达式3) {
     for(初始化表达式4; 条件表达式5; 修改初始值表达式6) {
      循环体;
     }
    }

双重for循环的执行流程

  • 执行表达式1 => 判断表达式2是否成立
    => 若成立,则执行表达式4 => 判断表达式5是否成立
    => 若成立,则执行循环体 => 执行表达式6 => 表达式5是否成立
    => 若不成立,则内层循环结束 => 表达式3 => 表达式2是否成立
    => 若不成立,则外层循环结束

双重for循环的特点

  • 外层循环用于控制打印的行数,内层循环用于控制打印的列数,
    外层循环改一下,内层循环从头到尾跑一圈。
  • 在以后的开发中若需要打印多行多列时,需要使用双重循环。
  • 多重循环不宜嵌套太多层,否则效率很低。一般到三重循环即可,最常见的就是双重循环。

案例题目

  • 使用双重for循环分别打印以下图案
    在这里插入图片描述
  • 使用双重for循环打印九九乘法表。
    在这里插入图片描述

break关键字跳出多层循环

  • 在嵌套的循环结构中,break用于退出所在循环体。
  • 如果要退出外层循环体,需要使用标号的方式。
for (...) {
    
    				outer: for (...) {
    
    
    for(...) {
    
        	   		for(...) {
    
    
        break;         			break outer;
    }              			}
}            			}

案例题目

  • 使用双重for循环打印2~100之间的所有素数。 Math.sqrt()
  • 当一个数只能被1和它本身整除时,这个数就叫做素数或质数。

while循环

  • while(条件表达式) { 循环体; }
  • 判断条件表达式是否成立
    => 若成立,则执行循环体 => 判断条件表达式是否成立
    => 若不成立,则循环结束
    在这里插入图片描述

while循环和for循环比较

  • while循环和for循环完全可以互换,当然推荐使用for循环。
  • while循环更适合于明确循环条件但不明确循环次数的场合中。
  • for循环更适合于明确循环次数或范围的场合中。
  • while(true) 等价于 for( ; ; ) 都表示无限循环。

案例题目 1

  • 使用while循环计算调和数列的和并打印,即: 1/1 + 1/2 + … + 1/n。

案例题目 2

  • 提示用户输入一个任意位数的正整数然后反向输出。

do while循环(熟悉)

  • do { 循环体; } while(条件表达式);
  • 执行循环体 => 判断条件表达式是否成立
    => 若成立,则执行循环体 => 判断条件表达式是否成立
    => 若不成立,则循环结束
    在这里插入图片描述

do while循环

  • do-while循环主要用于至少执行一次循环体的场合中。

案例题目

  • 使用do while循环来模拟学习任务是否合格的检查, 如果合格则停止,否则就重新完成学习任务。

3. 总结

  1. 分支结构
    if分支结构,if else分支结构,if else if else分支结构,switch case分支结构
  2. 循环结构
    for循环,break和continue关键字,双重for循环,while循环,do while循环

Chapter 5 数组以及应用

1. 一维数组

一维数组的基本概念

  • 当需要在Java程序中记录单个数据内容时,则声明一个变量即可。
  • 当需要在Java程序中记录多个类型相同的数据内容时,则声明一个一维数组即可,一维数组本质上就是在内存空间中申请一段连续的存储单元。
  • 数组是相同数据类型的多个元素的容器,元素按线性顺序排列,在Java语言中体现为一种引用数据类型。

    一维数组的声明方式
  • 数据类型[] 数组名称 = new 数据类型[数组的长度];
  • 调用数组的length属性可以获取数组的长度:
  • 可以通过下标的方式访问数组中的每一个元素。需要注意的是:数组的下标从0开始,对于长度为n的数组,下标的范围是0~n-1。

一维数组的初始化方式

  • 基本类型的数组(数据元素为基本类型)创建后,其元素的初始值:
    byte、short、char、int、long为0;float和double为0.0;boolean为false。

  • 可以在数组声明的同时进行初始化,具体如下:
    数据类型[] 数组名称 = {初始值1, 初始值2, …};

内存结构之栈区

  • 栈用于存放程序运行过程当中所有的局部变量。
    一个运行的Java程序从开始到结束会有多次变量的声明。

内存结构之堆区

  • JVM会在其内存空间中开辟一个称为“堆”的存储空间,
    这部分空间用于存储使用new关键字创建的数组和对象。

案例题目

  • 声明一个长度为5元素类型为int类型的一维数组,打印数组中所有元素值;
  • 使用元素11、22、33、44分别对数组中前四个元素赋值后再次打印;
  • 将元素55插入到下标为0的位置,原有元素向后移动,再打印所有元素值;
  • 将元素55从数组中删除,删除方式为后续元素向前移动,最后位置置为0并打印;
  • 查找数组中是否存在元素22,若存在则修改为220后再次打印所有元素;

数组的优缺点

  • 可以直接通过下标(或索引)的方式访问指定位置的元素,速度很快。
  • 数组要求所有元素的类型相同。
  • 数组要求内存空间连续,并且长度一旦确定就不能修改。
  • 增加和删除元素时可能移动大量元素,效率低。

案例题目

  • 声明一个初始值为11 22 33 44 55的一维数组并打印所有元素
  • 声明一个长度为3元素类型为int类型的一维数组并打印所有元素
  • 实现将第一个数组中间3个元素赋值到第二个数组中
  • 再次打印第二个数组中的所有元素
  • System.arraycopy(-,-,-,-,-)

案例题目

  • 编程统计用户输入任意一个正整数中每个数字出现次数的统计并打印。
  • 如:123123 => 1出现2次,2出现2次,3出现2次

案例题目

  • 提示用户输入学生的人数以及每个学生的考试成绩并打印出来。
  • 计算该班级的总分和平均分并打印出来。

数组工具类的概念

  • java.util.Arrays类可以实现对数组中元素的遍历、查找、排序等操作。

数组工具类的常用方法

  • 常用方法如下:
    在这里插入图片描述

2. 二维数组

二维数组的概念

  • 二维数组本质上就是由多个一维数组摞在一起组成的数组,二维数组中的每个元素都是一维数组,而一维数组中的每个元素才是数据内容。

二维数组的声明和初始化方式

  • 数据类型[][] 数组名称 = new 数据类型[行数][列数];
  • 数据类型[][] 数组名称 = { {元素1, 元素2,…}, …};

案例题目

  • 根据用户输入的行数n输出对应行数的杨辉三角,具体如下:
    在这里插入图片描述

3. 总结

  1. 一维数组
    基本概念,两种声明方式,增删改查操作,优缺点,案例,数组工具类
  2. 二维数组
    基本概念,两种声明方式

第一阶段模块二 面向对象编程

Chapter6 类和对象

1. 面向对象以及引用

面向对象编程的概念

  • 万物皆对象。
  • 面向对象指以属性和行为的观点去分析现实生活中的事物。
  • 面向对象编程指先以面向对象的思想进行分析,然后使用面向对象的编程语言进行表达的过程。
     c 面向过程
     c++ 面向过程+面向对象
     java 面向对象
  • 面向对象编程是软件产业化发展的需求。
  • 理解面向对象的思想精髓(封装、继承、多态),至少掌握一种编程语言。

2. 类和对象以及引用

类和对象的概念

  • 对象主要指现实生活中客观存在的实体,在Java语言中对象体现为内存空间中的一块存储区域。
  • 类简单来就是“分类”,是对具有相同特征和行为的多个对象共性的抽象描述,在Java语言中体现为一种引用数据类型,里面包含了描述特征/属性的成员变量以及描述行为的成员方法。
  • 类是用于构建对象的模板,对象的数据结构由定义它的类来决定。

类的定义

class 类名 {
    
                        class Person {
    
    
       类体;
   }                         	}
  • 注意:通常情况下,当类名由多个单词组成时,要求每个单词首字母都要大写。

成员变量的定义

class 类名 {
    
     						calss Persion{
    
    
	数据类型 成员变量名 = 初始值; 		String name;
}                               	}
  • 注意:当成员变量由多个单词组成时,通常要求从第二个单词起每个单词的首字母大写 。

对象的创建

  • new 类名(); new Persion();
  • 注意:
    a.当一个类定义完毕后,可以使用new关键字来创建该类的对象,这个过程叫做类的实例化。
    b.创建对象的本质就是在内存空间的堆区申请一块存储区域, 用于存放该对象独有特征信息。

引用的定义

  • 基本概念
    a.使用引用数据类型定义的变量叫做引用型变量,简称为"引用"。
    b.引用变量主要用于记录对象在堆区中的内存地址信息,便于下次访问。
  • 语法格式
    类名 引用变量名; Persion p = new Persion;
    引用变量名.成员变量名; p.name = “kim”; System.out.println(p.name);

案例题目

  • 编程实现Person类的定义和使用。

成员变量的初始值

  • 对象创建后,其成员变量可以按照默认的方式初始化,具体规则如下:
成员变量的类型 默认初始值
数值类型
byte,short,int,long,float,double,char
0 0.0
boolean型 false
引用类型 null

案例题目

  • 编程实现Point类的定义,特征有:横纵坐标(整数),要求在main方法中声明Point类型的引用指向Point对象并打印特征,然后将横纵坐标修改为3和5后再次打印。

3. 成员方法

成员方法的定义

class 类名 {
    
                                                                     class Persion {
    
    
       返回值类型 成员方法名(形参列表) {
    
                           					void show(){
    
    
           成员方法体;                                                                 System.out.println("uuuuu");
       }                                                                                     }
   }                                                                                     }
  • 当成员方法名由多个单词组成时,要求从第二个单词起每个单词的首字母大写。

返回值类型的详解

  • 返回值主要指从方法体内返回到方法体外的数据内容。
  • 返回值类型主要指返回值的数据类型,可以是基本数据类型,也可以是引用数据类型。
  • 当返回的数据内容是66时,则返回值类型写 int 即可
  • 在方法体中使用return关键字可以返回具体的数据内容并结束当前方法。
  • 当返回的数据内容是66时,则方法体中写 return 66; 即可
  • 当该方法不需要返回任何数据内容时,则返回值类型写void即可。

形参列表的详解

  • 形式参数主要用于将方法体外的数据内容带入到方法体内部。
  • 形式参数列表主要指多个形式参数组成的列表,语法格式如下:
     数据类型 形参变量名1, 数据类型 形参变量名2, …
  • 当带入的数据内容是"hello"时,则形参列表写 String s 即可
  • 当带入的数据内容是66和"hello"时,则形参列表写 int i, String s 即可
  • 若该方法不需要带入任何数据内容时,则形参列表位置啥也不写即可。

方法体的详解

  • 成员方法体主要用于编写描述该方法功能的语句块。
  • 成员方法可以实现代码的重用,简化代码。

方法的调用

  • 引用变量名.成员方法名(实参列表); p.show();
  • 实际参数列表主要用于对形式参数列表进行初始化操作,因此参数的个数、类型以及顺序都要完全一致。
  • 实际参数可以传递直接量、变量、表达式、方法的调用等。

可变长参数

  • 返回值类型 方法名(参数的类型… 参数名)
  • 方法参数部分指定类型的参数个数是可以改变的,也就是0~n个 。
  • 一个方法的形参列表中最多只能声明一个可变长形参,并且需要放到参数列表的末尾。

方法的传参过程

  • int max(int ia, int ib) { … … … } int a = 5; int b=6; int res = m.max(a,b);
  1. 为main方法中的变量a、b、res分配空间并初始化。
  2. 调用max方法,为max方法的形参变量ia、ib分配空间。
  3. 将实参变量的数值赋值到形参变量的内存空间中。
  4. max方法运行完毕后返回,形参变量空间释放。
  5. main方法中的res变量得到max方法的返回值。
  6. main方法结束后释放相关变量的内存空间。
    在这里插入图片描述

参数传递的注意事项

  • 基本数据类型的变量作为方法的参数传递时,
    形参变量数值的改变通常不会影响到实参变量的数值,
    因为两个变量有各自独立的内存空间;

  • 引用数据类型的变量作为方法的参数传递时,
    形参变量指向内容的改变会影响到实参变量指向内容的数值,
    因为两个变量指向同一块内存空间

  • 当引用数据类型的变量作为方法的参数传递时,
    若形参变量改变指向后再改变指定的内容,
    则通常不会影响到实参变量指向内容的改变,因为两个变量指向不同的内存空间。

内存结构之栈区

  • 栈用于存放程序运行过程当中所有的局部变量。
    一个运行的Java程序从开始到结束会有多次方法的调用。

  • JVM会为每一个方法的调用在栈中分配一个对应的空间,这个空间称为该方法的栈帧。
    一个栈帧对应一个正在调用中的方法,栈帧中存储了该方法的参数、局部变量等数据。

  • 当某一个方法调用完成后,其对应的栈帧将被清除。

传参的相关概念

  • 参数分为形参和实参,定义方法时的参数叫形参,调用方法时传递的参数叫实参。
  • 调用方法时采用值传递把实参传递给形参,方法内部其实是在使用形参。
  • 所谓值传递就是当参数是基本类型时,传递参数的值,比如传递i=10,真实传参时,
    把10赋值给了形参。当参数是对象时,传递的是对象的值,也就是把对象的地址赋值给形参。

4. 总结

  1. 面向对象编程的概念(理解)
    对象,面向对象,面向对象编程
  2. 类和对象以及引用(重中之重)
    类和对象,类的定义,成员变量的定义,对象的创建,引用的定义
  3. 成员方法(重中之重)
    语法格式,详解,调用,传参的过程

Chapter7 方法和封装

1. 构造方法

构造方法的基本概念

class 类名 {
    
      			class Person {
    
    
	类名(形参列表) {
    
     		Person () {
    
     - Person类中的构造方法
		构造方法体;
	}      					}
}  						}
  • 构造方法名与类名完全相同并且没有返回值类型,连void都不许有。

默认构造方法

  • 当一个类中没有定义任何构造方法时,编译器会自动添加一个无参空构造构造方法,叫做默认/缺省构造方法,如:Person(){}
  • 若类中出现了构造方法,则编译器不再提供任何形式的构造方法。

构造方法的作用

  • 使用new关键字创建对象时会自动调用构造方法实现成员变量初始化工作。

案例题目

  • 编程实现Point类的定义并向Point类添加构造方法
    Point() 默认创建原点对象
    Point(int i, int j) 根据参数创建点对象

2. 方法重载

方法重载的概念

  • 若方法名称相同,参数列表不同,这样的方法之间构成重载关系 (Overload)。

重载的体现形式

  • 方法重载的主要形式体现在:参数的个数不同、参数的类型不同、参数的顺序不同,与返回值类型和形参变量名无关,但建议返回值类型最好相同。
  • 判断方法能否构成重载的核心:调用方法时能否加以区分。

练习题目

  • 编程实现为Point类添加重载的成员方法:
    up() – 实现纵坐标减1的功能。
    up(int dy) – 实现纵坐标减去参数指定数值的功能。
  • 测试重载方法的调用规则

重载的实际意义

  • 方法重载的实际意义在于调用者只需要记住一个方法名就可以调用各种不同的版本,来实现各种不同的功能。
  • 如:java.io.PrintStream类中的println方法。

3. this关键字

this的基本概念

  • 若在构造方法中出现了this关键字,则代表当前正在构造的对象。
  • 若在成员方法中出现了this关键字,则代表当前正在调用的对象。
  • this关键字本质上就是当前类类型的引用变量。

工作原理

  • 在构造方法中和成员方法中访问成员变量时,编译器会加上this.的前缀,而this.相当于汉语中"我的",当不同的对象调用同一个方法时,由于调用方法的对象不同导致this关键字不同,从而this.方式访问的结果也就随之不同。

使用方式

  • 当局部变量名与成员变量名相同时,在方法体中会优先使用局部变量(就近原则),若希望使用成员变量,则需要在成员变量的前面加上this.的前缀,明确要求该变量是成员变量(重中之重)。
  • this关键字除了可以通过this.的方式调用成员变量和成员方法外,还可以作为方法的返回值(重点)。
  • 在构造方法的第一行可以使用this()的方式来调用本类中的其它构造方法(了解)。

注意事项

  • 引用类型变量用于存放对象的地址,可以给引用类型赋值为null,表示不指向任何对象。
  • 当某个引用类型变量为null时无法对对象实施访问(因为它没有指向任何对象)。此时,如果通过引用访问成员变量或调用方法,会产生NullPointerException 异常。

4. 方法递归调用

案例题目

  • 编程实现参数n的阶乘并返回,所谓阶乘就是从1累乘到n的结果。

递归的基本概念

  • 递归本质就是指在方法体的内部直接或间接调用当前方法自身的形式。

注意事项

  • 使用递归必须有递归的规律以及退出条件。
  • 使用递归必须使得问题简单化而不是复杂化。
  • 若递归影响到程序的执行性能,则使用递推取代之。

案例题目

  • 编程实现费式数列中第n项的数值并返回。
  • 费式数列: 1 1 2 3 5 8 13 21 ……

5. 封装

封装的概念

  • 通常情况下可以在测试类给成员变量赋值一些合法但不合理的数值,无论是编译阶段还是运行阶段都不会报错或者给出提示,此时与现实生活不符。
  • 为了避免上述错误的发生,就需要对成员变量进行密封包装处理,来隐藏成员变量的细节以及保证成员变量数值的合理性,该机制就叫做封装。

封装的实现流程

  1. 私有化成员变量,使用private关键字修饰。
    private关键字修饰表示私有的含义,也就是该成员变量只能在当前类的内部使用
  2. 提供公有的get和set方法,并在方法体中进行合理值的判断。
  3. 在构造方法中调用set方法进行合理值的判断。

案例题目

  • 提示用户输入班级的学生人数以及每个学生的信息,学生的信息有:学号、姓名,最后分别打印出来。
  • 提示:Student[] arr = new Student[num];

JavaBean的概念(了解)

  • JavaBean是一种Java语言写成的可重用组件,其它Java 类可以通过反射机制发现和操作这些JavaBean的属性。
  • JavaBean本质上就是符合以下标准的Java类:
     类是公共的 public class Student{}
     有一个无参的公共的构造器 public Student(){}
     有属性,且有对应的get、set方法 public get set …

6. 总结

  1. 构造方法(重中之重)
    语法格式,默认构造方法,构造方法:实现成员变量的初始化

  2. 方法重载(重点)
    概念,体现形式,实际意义

  3. this关键字(原理)
    概念,原理,使用方式

  4. 递归(难点)
    概念,使用原则

  5. 封装(重中之重)
    概念,实现流程,JavaBean

Chapter8 static关键字和继承

1. static关键字

案例题目

  • 编程实现People类的封装,特征有:姓名、年龄、国籍,要求提供打印所有特征的方法。
  • 编程实现PeopleTest类,main方法中使用有参方式构造两个对象并打印

基本概念

  • 使用static关键字修饰成员变量表示静态的含义,此时成员变量由对象层级提升为类层级,也就是整个类只有一份并被所有对象共享,该成员变量随着类的加载准备就绪,与是否创建对象无关。
  • static关键字修饰的成员可以使用引用.的方式访问,但推荐类名.的方式。

使用方式

  • 在非静态成员方法中既能访问非静态的成员又能访问静态的成员。
    (成员:成员变量 + 成员方法, 静态成员被所有对象共享)
  • 在静态成员方法中只能访问静态成员不能访问非静态成员。
    (成员:成员变量 + 成员方法, 因为此时可能还没有创建对象)
  • 在以后的开发中只有隶属于类层级并被所有对象共享的内容才可以使用static关键字修饰。
    (不能滥用static关键字)

构造块和静态代码块(熟悉)

  • 构造块:在类体中直接使用{}括起来的代码块。
  • 每创建一个对象都会执行一次构造块。
  • 静态代码块:使用static关键字修饰的构造块。
  • 静态代码块随着类加载时执行一次。

又见main方法

  • 语法格式:
    public static void main(String[] args){}
  • 参数使用的举例。
    在这里插入图片描述

案例题目(重中之重)

  • 编程实现Singleton类的封装。
  • 编程实现SingletonTest类对Singleton类进行测试,要求main方法中能得到且只能得到该类的一个对象。
  • 작업관리자

单例设计模式的实现流程

  • 私有化构造方法,使用private关键字修饰。
  • 声明本类类型的引用指向本类类型的对象,并使用private static关键字共同修饰。
  • 提供公有的get方法负责将对象返回出去,并使用public static关键字共同修饰。

单例设计模式的实现方式

  • 单例设计模式的实现方式有两种:饿汉式 和 懒汉式,在以后的开发中推荐饿汉式。

2. 继承

在这里插入图片描述

继承的概念

  • 当多个类之间有相同的特征和行为时,可以将相同的内容提取出来组成一个公共类,让多个类吸收公共
    类中已有特征和行为而在多个类型只需要编写自己独有特征和行为的机制,叫做继承。
  • 在Java语言中使用extends(扩展)关键字来表示继承关系。
  • 如:
    public class Worker extends Person{} - 表示Worker类继承自Person类
    其中Person类叫做超类、父类、基类。
    其中Worker类叫做派生类、子类、孩子类。
  • 使用继承提高了代码的复用性,可维护性及扩展性,是多态的前提条件。

继承的特点

  • 子类不能继承父类的构造方法和私有方法,但私有成员变量可以被继承只是不能直接访问。
  • 无论使用何种方式构造子类的对象时都会自动调用父类的无参构造方法,来初始化从父类中继承的成员变量,相当于在构造方法的第一行增加代码super()的效果。
  • 使用继承必须满足逻辑关系:子类 is a 父类,也就是不能滥用继承。
  • Java语言中只支持单继承不支持多继承,也就是说一个子类只能有一个父类,但一个父类可以有多个子类。

方法重写的概念

  • 从父类中继承下来的方法不满足子类的需求时,就需要在子类中重新写一个和父类一样的方法来覆盖从父类中继承下来的版本,该方式就叫做方法的重写(Override)。

方法重写的原则

  • 要求方法名相同、参数列表相同以及返回值类型相同,从Java5开始允许返回子类类型。
  • 要求方法的访问权限不能变小,可以相同或者变大。
  • 要求方法不能抛出更大的异常(异常机制)。

Java开发的常用工具

  • 文本编辑器(TE,Text Editor)
  • 记事本、Notepad++、Edit Plus、UltraEdit、…
  • 集成开发环境(IDE,Integrated Development Environment )
  • Jbuilder、NetBeans、Eclipse、MyEclipse、IDEA、…

下载和安装方式

  • 下载地址:https://www.jetbrains.com/
  • 安装方式:一路点击下一步默认安装即可

案例题目

  • 编程实现Animal类的封装,特征有:名字和毛色,要求提供打印所有特征的方法。
  • 编程实现Dog类的封装并继承自Animal类,该类的特征有:牙齿数量,要求提供打印所有特征的方法。
  • 编程实现DogTest类,在main方法中分别使用无参和有参方式构造Dog类型对象并打印特征。

又见构造块与静态代码块(笔试)

  • 先执行父类的静态代码块,再执行子类的静态代码块。
  • 执行父类的构造块,执行父类的构造方法体。
  • 执行子类的构造块,执行子类的构造方法体。

3. 访问控制

在这里插入图片描述

注意事项

  • public修饰的成员可以在任意位置使用。
  • private修饰的成员只能在本类内部使用。
  • 通常情况下,成员方法都使用public关键字修饰,成员变量都使用private关键字修饰。

package语句的由来

  • 定义类时需要指定类的名称,但如果仅仅将类名作为类的唯一标识,则不可避免的出现命名冲突的问题。这会给组件复用以及团队间的合作造成很大的麻烦!
  • 在Java语言中,用包(package)的概念来解决命名冲突的问题。

包的定义

  • 在定义一个类时,除了定义类的名称一般还要指定一个包名,格式如下:
    package 包名;
    package 包名1.包名2.包名3…包名n;
  • 为了实现项目管理、解决命名冲突以及权限控制的效果。

定义包的规范

  • 如果各个公司或开发组织的程序员都随心所欲的命名包名的话,仍然不能从根本上解决命名冲突的问题。因此,在指定包名的时候应该按照一定的规范。
  • org.apache.commons.lang.StringUtil
     公司    项目 模块  类
  • 其中StringUtils是类名而org.apache.commons.lang是多层包名,其含义如下:org.apache表示公司或组织的信息(是这个公司(或组织)域名的反写);common 表示项目的名称信息;lang 表示模块的名称信息。

包的导入

  • 使用import关键字导入包。
  • 使用import关键字导入静态成员,从Java5.0开始支持。
    import java.lang.System.out;
    out.println(…);

4. final关键字

基本概念

  • final本意为"最终的、不可改变的",可以修饰类、成员方法以及成员变量。

使用方式

  • final关键字修饰类体现在该类不能被继承。
  • 主要用于防止滥用继承,如:java.lang.String类等。
  • final关键字修饰成员方法体现在该方法不能被重写但可以被继承。
  • 主要用于防止不经意间造成重写,如:java.text.Dateformat类中format方法等。
  • final关键字修饰成员变量体现在该变量必须初始化且不能改变。
  • 主要用于防止不经意间造成改变,如:java.lang.Thread类中MAX_PRIORITY等。

常量的概念

  • 在以后的开发中很少单独使用final关键字来修饰成员变量,通常使用 public static final关键字共同修饰成员变量来表达常量的含义,常量的命名规范要求是所有字母都要大写,不同的单词之间采用下划线连
  • public static final double PI = 3.14;

5. 总结和答疑

  1. static关键字

    概念,使用方式,构造块和静态构造块,单列设计模式,饿汉式懒汉式

  2. 继承

    概念,特点,方法的重写,重写的原则,IDEA

  3. 访问控制

    public,private,package,导入

  4. final关键字

    概念,修饰类,修饰成员方法,修饰成员变量,常量

Chapter9 多态和特殊类

1. 多态

多态的概念

  • 多态主要指同一种事物表现出来的多种形态。
  • 饮料:可乐、雪碧、红牛、脉动、…
  • 宠物:猫、狗、鸟、小强、鱼、…
  • 人:学生、教师、工人、保安、…
  • 图形:矩形、圆形、梯形、三角形、…

多态的语法格式

  • 父类类型 引用变量名 = new 子类类型();
  • 如:
    Shape sr = new Rect();
    sr.show();

案例题目

  • 编程实现Shape类的封装,特征有:横纵坐标,要求提供打印所有特征的方法。
  • 编程实现Rect类的封装并继承自Shape类,特征有:长度和宽度。
  • 编程实现ShapeRectTest类,在main方法中分别创建Shape和Rect类型对象并打印特征。

多态的特点

  • 当父类类型的引用指向子类类型的对象时,父类类型的引用可以直接调用父类独有的方法。
  • 当父类类型的引用指向子类类型的对象时,父类类型的引用不可以直接调用子类独有的方法。
    (父 = new 子 --》 父只能用自己的,可是被子override的成员方法用的是子的)
  • 对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类重写的版本
    (动态绑定)。
  • 对于父子类都有的静态方法来说,编译和运行阶段都调用父类版本。

引用数据类型之间的转换

  • 引用数据类型之间的转换方式有两种:自动类型转换 和 强制类型转换。
  • 自动类型转换主要指小类型向大类型的转换,也就是子类转为父类,也叫做向上转型。
    (越少越大,越多越小)
  • 强制类型转换主要指大类型向小类型的转换,也就是父类转为子类,也叫做向下转型或显式类型转换。
  • 引用数据类型之间的转换必须发生在父子类之间,否则编译报错。
  • 若强转的目标类型并不是该引用真正指向的数据类型时则编译通过,运行阶段发生类型转换异常。
  • 为了避免上述错误的发生,应该在强转之前进行判断,格式如下:
    if(引用变量 instanceof 数据类型)
    判断引用变量指向的对象是否为后面的数据类型

多态的实际意义

  • 多态的实际意义在于屏蔽不同子类的差异性,实现通用的编程,带来不同的效果。
    (ShapeTest.java)

2. 抽象类

抽象方法的概念

  • 抽象方法主要指不能具体实现的方法并且使用abstract关键字修饰,也就是没有方法体。
  • 具体格式如下:
    访问权限 abstract 返回值类型 方法名(形参列表);
    public abstract void cry();

抽象类的概念

  • 抽象类主要指不能具体实例化的类并且使用abstract关键字修饰,也就是不能创建对象。

抽象类和抽象方法的关系

  • 抽象类中可以有成员变量、构造方法、成员方法;
  • 抽象类中可以没有抽象方法,也可以有抽象方法;
  • 拥有抽象方法的类必须是抽象类,因此真正意义上的抽象类应该是具有抽象方法并且使用abstract关键字修饰的类。

抽象类的实际意义

  • 抽象类的实际意义不在于创建对象而在于被继承。
  • 当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,也就是抽象类对子类具有强制性和规范性,因此叫做模板设计模式。

开发经验分享

  • 在以后的开发中推荐使用多态的格式,此时父类类型引用直接调用的所有方法一定是父类中拥有的方法,若以后更换子类时,只需要将new关键字后面的子类类型修改而其它地方无需改变就可以立即生效,从而提高了代码的可维护性和可扩展型。
  • 该方式的缺点就是:父类引用不能直接调用子类独有的方法,若调用则需要强制类型转换。

抽象类的应用

  • 银行有 定期账户和活期账户。继承自 账户类。账户类中:
  public class Account{
    
    
        private double money;
        public double getLixi(){
    
    }
  }

3. 接口

接口的基本概念

  • 接口就是一种比抽象类还抽象的类,体现在所有方法都为抽象方法。
    (可以有:常量,私有方法(Java9))
    (常量和抽象方法的关键字可以省略 )
  • 定义类的关键字是class,而定义接口的关键字是interface。
  • 如: 金属接口 货币接口 黄金类
    (黄金类不能同时继承金属类和货币类,不支持多继承,接口可以实现多个)

练习题目

  • 编程实现Runner接口,提供一个描述奔跑行为的抽象方法。
  • 编程实现Hunter接口继承Runner接口,并提供一个描述捕猎行为的抽象方法。
  • 编程实现Man类实现Hunter接口并重写抽象方法,在main方法中使用多态方式测试。

类和接口之间的关系

名称 关键字 关系
类和类之间的关系 使用extends关键字表达继承关系 支持单继承
类和接口之间的关系 使用implements关键字表达实现关系 支持多实现
接口和接口之间的关系 使用extends关键字表达继承关系 支持多继承

抽象类和接口的主要区别(笔试题)

  • 定义抽象类的关键字是abstract class,而定义接口的关键字是interface。
  • 继承抽象类的关键字是extends,而实现接口的关键字是implements。
  • 继承抽象类支持单继承,而实现接口支持多实现。
  • 抽象类中可以有构造方法,而接口中不可以有构造方法。
  • 抽象类中可以有成员变量,而接口中只可以有常量。
  • 抽象类中可以有成员方法,而接口中只可以有抽象方法。
  • 抽象类中增加方法时子类可以不用重写,而接口中增加方法时实现类需要重写(Java8以前的版本)。
  • 从Java8开始增加新特性,接口中允许出现非抽象方法和静态方法,但非抽象方法需要使用default关键字修饰。
  • 从Java9开始增加新特性,接口中允许出现私有方法。

4. 总结

  1. 多态(重中之重)

    基本概念,语法格式,多态的特点,类型转换,instanceof,实际意义

  2. 抽象类(重点)

    抽象方法,abstract,抽象类,抽象类和抽象方法的关系,实际意义

  3. 接口(重点)

    基本概念,常量,抽象方法(java8),弥补不能多继承的不足,interface,implements,接口和类之间的关系,抽象类和接口主要区别

Chapter10 特殊类

1. 内部类

内部类的基本概念

  • 当一个类的定义出现在另外一个类的类体中时,
    那么这个类叫做内部类(Inner),
    而这个内部类所在的类叫做外部类(Outer)。
  • 类中的内容:成员变量、成员方法、构造方法、静态成员、构造块和静态代码块、内部类。

实际作用

  • 当一个类存在的价值仅仅是为某一个类单独服务时,那么就可以将这个类定义为所服务类中的内部类,这样可以隐藏该类的实现细节并且可以方便的访问外部类的私有成员而不再需要提供公有的get和set方法。

内部类的分类

  • 普通内部类 - 直接将一个类的定义放在另外一个类的类体中。
  • 静态内部类 - 使用static关键字修饰的内部类,隶属于类层级。
  • 局部内部类 - 直接将一个类的定义放在方法体的内部时。
  • 匿名内部类 - 就是指没有名字的内部类。 (niming)

普通(成员)内部类的格式

  • 访问修饰符 class 外部类的类名 {
     访问修饰符 class 内部类的类名 {
      内部类的类体;
     }
    }

普通内部类的使用方式

  • 普通内部类和普通类一样可以定义成员变量、成员方法以及构造方法等。
  • 普通内部类和普通类一样可以使用final或者abstract关键字修饰。
  • 普通内部类还可以使用private或protected关键字进行修饰。
  • 普通内部类需要使用外部类对象来创建对象。
  • 如果内部类访问外部类中与本类内部同名的成员变量或方法时,需要使用this关键字。、
    (NormalOuter NormalOuterTest)

静态内部类的格式

  • 访问修饰符 class 外部类的类名 {
     访问修饰符 static class 内部类的类名 {
      内部类的类体;
     }
    }

静态内部类的使用方式

  • 静态内部类不能直接访问外部类的非静态成员。
  • 静态内部类可以直接创建对象。
  • 如果静态内部类访问外部类中与本类内同名的成员变量或方法时,需要使用类名.的方式访问。
    (StaticOuter StaticOuterTest)

局部(方法)内部类的格式

  • 访问修饰符 class 外部类的类名 {
     访问修饰符 返回值类型 成员方法名(形参列表) {
      class 内部类的类名 {
       内部类的类体;
      }
     }
    }

局部内部类的使用方式

  • 局部内部类只能在该方法的内部可以使用。
  • 局部内部类可以在方法体内部直接创建对象。
  • 局部内部类不能使用访问控制符和static关键字修饰符。
    (局部变量 都不用)
  • 局部内部类可以使用外部方法的局部变量,但是必须是final的。
    由局部内部类和局部变量的声明周期不同所致。
    (AreaOuter AreaOuterTest)

回调模式的概念

  • 回调模式是指——如果一个方法的参数是接口类型,则在调用该方法时,需要创建并传递一个实现此接口类型的对象;而该方法在运行时会调用到参数对象中所实现的方法(接口中定义的)。

开发经验分享

  • 当接口/类类型的引用作为方法的形参时,实参的传递方式有两种:
  • 自定义类实现接口/继承类并重写方法,然后创建该类对象作为实参传递;
  • 使用上述匿名内部类的语法格式得到接口/类类型的引用即可;

匿名内部类的语法格式(重点)(niming)

  • 接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };

2. 枚举

枚举的基本概念

  • 一年中的所有季节:春季、夏季、秋季、冬季。
  • 所有的性别:男、女。
  • 键盘上的所有方向按键:向上、向下、向左、向右。
  • 在日常生活中这些事物的取值只有明确的几个固定值,此时描述这些事物的所有值都可以一一列举出来,而这个列举出来的类型就叫做枚举类型。
    (Direction DirectionTest)

枚举的定义

  • 使用public static final表示的常量描述较为繁琐,使用enum关键字来定义枚举类型取代常量,枚举类型是从Java5开始增加的一种引用数据类型。
  • 枚举值就是当前类的类型,也就是指向本类的对象,默认使用public static final关键字共同修饰,因此采用枚举类型.的方式调用。
  • 枚举类可以自定义构造方法,但是构造方法的修饰符必须是private,默认也是私有的。
    (DirectionEnum DirectionTest DirectionUseTest)

Enum类的概念和方法

  • 所有的枚举类都继承自java.lang.Enum类,常用方法如下:(DirectionEnumTest)
方法 方法说明
static T[] values() 返回当前枚举类中的所有对象
String toString() 返回当前枚举类对象的名称
int ordinal() 获取枚举对象在枚举类中的索引位置
static T valueOf(String str) 将参数指定的字符串名转为当前枚举类的对象
int compareTo(E o) 比较两个枚举对象在定义时的顺序

枚举类实现接口的方式

  • 枚举类实现接口后需要重写抽象方法,而重写方法的方式有两种:重写一个,或者每个对象都重写。
    (不能继承,因为已经继承了Enum)
    (DirectionInterFace DirectionEnum DirectionEnumTest)

3. 注解

注解的基本概念

  • 注解(Annotation)又叫标注,是从Java5开始增加的一种引用数据类型。(接口)
  • 注解本质上就是代码中的特殊标记,通过这些标记可以在编译、类加载、以及运行时执行指定的处理。
    (特殊说明,标签一样)

注解的语法格式

  • 访问修饰符 @interface 注解名称 {
     注解成员;
    }

  • 自定义注解自动继承java.lang.annotation.Annotation接口。

  • 通过@注解名称的方式可以修饰包、类、 成员方法、成员变量、构造方法、参数、局部变量的声明等。

注解的使用方式

  • 注解体中只有成员变量没有成员方法,而注解的成员变量以“无形参的方法”形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。
  • 如果注解只有一个参数成员,建议使用参数名为value,而类型只能是八种基本数据类型、String类型、Class类型、enum类型及Annotation类型。

元注解的概念

  • 元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。
  • 元注解主要有
    @Retention 保持(注解的有效范围/生命周期)
    @Documented 文档 (这个注解是否在我们的文档注释中体现)
    @Target 目标 (这个注解可以修饰那些内容)
    @Inherited 继承 (这个注解是否可以被继承)
    @Repeatable 重复(是否可以重复)

元注解@Retention

  • @Retention 应用到一个注解上用于说明该注解的的生命周期,取值如下:
  • RetentionPolicy.SOURCE 注解只在源码阶段保留,在编译器进行编译时它将被丢弃忽视。
  • RetentionPolicy.CLASS 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中,默认方式。
  • RetentionPolicy.RUNTIME 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们。

元注解@Documented

  • 使用javadoc工具可以从程序源代码中抽取类、方法、成员等注释形成一个和源代码配套的API帮助文档,而该工具抽取时默认不包括注解内容。
  • @Documented用于指定被该注解将被javadoc工具提取成文档。
  • 定义为@Documented的注解必须设置Retention值为RUNTIME。

元注解@Target

  • @Target用于指定被修饰的注解能用于哪些元素的修饰,取值如下:
方法 方法说明
ElementType.ANNOTATION_TYPE 可以给一个注解进行注解
ElementType.CONSTRUCTOR 可以给构造方法进行注解
ElementType.FIELD 可以给属性进行注解
ElementType.LOCAL_VARIABLE 可以给局部变量进行注解
ElementType.METHOD 可以给方法进行注解
ElementType.PACKAGE 可以给一个包进行注解
ElementType.PARAMETER 可以给一个方法内的参数进行注解
ElementType.TYPE 可以给类型进行注解,比如类、接口、枚举

元注解@Inherited

  • @Inherited并不是说注解本身可以继承,而是说如果一个超类被该注解标记过的注解进行注解时,如果子类没有被任何注解应用时,则子类就继承超类的注解。

元注解@Repeatable

  • @Repeatable表示自然可重复的含义,从Java8开始增加的新特性。
  • 从Java8开始对元注解@Target的参数类型ElementType枚举值增加了两个:
  • 其中ElementType.TYPE_PARAMETER 表示该注解能写在类型变量的声明语句中,如:泛型。
  • 其中ElementType.TYPE_USE 表示该注解能写在使用类型的任何语句中。

常见的预制注解

  • 预制注解就是Java语言自身提供的注解,具体如下:
注解 注解说明
@author 标明开发该类模块的作者,多个作者之间使用,分割
@version 标明该类模块的版本
@see 参考转向,也就是相关主题
@since 从哪个版本开始增加的
@param 对方法中某参数的说明,如果没有参数就不能写
@return 对方法返回值的说明,如果方法的返回值类型是void就不能写
@exception 对方法可能抛出的异常进行说明

常见的预制注解

  • 常用的预制注解如下:
注解 注解说明
@Override 限定重写父类方法, 该注解只能用于方法
@Deprecated 用于表示所修饰的元素(类, 方法等)已过时
@SuppressWarnings 抑制编译器警告

4. 总结

  1. 内部类

    概念,普通内部类,静态内部类,局部内部类,匿名内部类(重点),回调模式

  2. 枚举类型

    概念,自定义枚举,enum关键字,继承Enum类,实现接口

  3. 注解

    概念,自定义注解,使用,元注解,预制注解

第一阶段模块三 JavaSE Java核心类库(上)

Chapter11 常用类的概述和使用

1. 常用的包(熟悉)

包的名称和功能

  • java.lang包 - 该包是Java语言的核心包,并且该包中的所有内容由Java虚拟机自动导入。
    如:System类、String类、…

  • java.util包 - 该包是Java语言的工具包,里面提供了大量工具类以及集合类等。
    如:Scanner类、Random类、List集合、…

  • java.io包 - 该包是Java语言中的输入输出包​,里面提供了大量读写文件相关的类等。
    如:FileInputStream类、FileOutputStream类、…

  • java.net包 - 该包是Java语言中的网络包,里面提供了大量网络编程相关的类等。
    如:ServerSocket类、Socket类、…

  • java.sql 包 - 该包是Java语言中的数据包,里面提供了大量操作数据库的类和接口等。
    如:DriverManager类、Connection接口、…

  • … …

  • Java程序员在编程时可以使用大量类库,因此Java编程时需要记的很多,对编程能力本身要求不是特别的高。

2. Object类的概述(重点)

基本概念

  • java.lang.Object类是Java语言中类层次结构的根类,也就是说任何一个类都是该类的直接或者间接子类。
  • 如果定义一个Java类时没有使用extends关键字声明其父类,则其父类为 java.lang.Object 类。
  • Object类定义了“对象”的基本行为, 被子类默认继承。(Student)

常用的方法

方法声明 功能介绍
Object() 使用无参方式构造对象
boolean equals(Object obj) 用于判断调用对象是否与参数对象相等。该方法默认比较两个对象的地址是否相等,与 == 运算符的结果一致若希望比较两个对象的内容,则需要重写该方法。若该方法被重写后,则应该重写hashCode方法来保证结果的一致性。
int hashCode() 用于获取调用对象的哈希码值(内存地址的编号)。若两个对象调用equals方法相等,则各自调用该方法的结果必须相同若两个调用对象equals方法不相等,则各自调用该方法的结果应该不相同。为了使得该方法与equals方法保持一致,需要重写该方法。
String toString() 用于获取调用对象的字符串形式该方法默认返回的字符串为:包名.类名@哈希码值的十六进制为了返回更有意义的数据,需要重写该方法使用print或println打印引用或字符串拼接引用都会自动调用该方法
Class<?> getClass() 用于返回调用对象执行时的Class实例,反射机制使用

案例题目:

  • 编程实现Student类的封装,特征:学号(id)和姓名,要求提供打印所有特征的方法。
    编程实现StudentTest类,在main方法中使用有参方式构造两个Student类型的对象并打印特征。

    题目扩展:

  • 如何实现以姓名作为基准判断两个对象是否相等?以及以学号和姓名同时作为基准判断两个对象是否相等?

3. 包装类(熟悉)

包装类的概念

  • 通常情况下基本数据类型的变量不是对象,为了满足万物皆对象的理念就需要对基本数据类型的变量进行打包封装处理变成对象,而负责将这些变量声明为成员变量进行对象化处理的相关类,叫做包装类。
    如:
    Person p = new Person();
    int num = 10;

包装类的分类

包装类 对应的基本类型
java.lang.Byte byte
java.lang.Short short
java.lang.Integer int
java.lang.Long long
java.lang.Float float
java.lang.Double double
java.lang.Boolean boolean
java.lang.Character char

Integer类的概述

  • 基本概念
    java.lang.Integer类内部包装了一个int类型的变量作为成员变量,主要用于实现对int类型的包装并提供int类型到String类之间的转换等方法。

  • 常用的常量

常量类型和名称 功能介绍
public static final int MAX_VALUE 表示int类型可以描述的最大值,即2^31-1
public static final int MIN_VALUE 表示int类型可以描述的最小值,即-2^31
public static final int SIZE 表示int类型采用二进制补码形式的位数
public static final int BYTES 表示int类型所占的字节个数
public static final Class TYPE 表示int类型的Class实例
  • 常用的方法
方法声明 功能介绍
Integer(int value) 根据参数指定的整数来构造对象(已过时)
Integer(String s) 根据参数指定的字符串来构造对象 (已过时)
int intValue() 获取调用对象中的整数值并返回
static Integer valueOf(int i) 根据参数指定整数值得到Integer类型对象
boolean equals(Object obj) 比较调用对象与参数指定的对象是否相等
String toString() 返回描述调用对象数值的字符串形式
static int parseInt(String s) 将字符串类型转换为int类型并返回
static String toString(int i) 获取参数指定整数的十进制字符串形式
static String toBinaryString(int i) 获取参数指定整数的二进制字符串形式
static String toHexString(int i) 获取参数指定整数的十六进制字符串形式
static String toOctalString(int i) 获取参数指定整数的八进制字符串形式
  • 装箱和拆箱的概念
    在Java5发布之前使用包装类对象进行运算时,需要较为繁琐的“拆箱”和“装箱”操作;即运算前先将包装类对象拆分为基本类型数据,运算后再将结果封装成包装类对象。
    从Java5开始增加了自动拆箱和自动装箱的功能。
  • 自动装箱池
    在Integer类的内部提供了自动装箱池技术,将-128到127之间的整数已经装箱完毕,当程序中使用
    该范围之间的整数时,无需装箱直接取用自动装箱池中的对象即可,从而提高效率。

Double类的概述

  • 基本概念
    java.lang.Double类型内部包装了一个double类型的变量作为成员变量,主要用于实现对double类型的包装并提供double类型到String类之间的转换等方法。
  • 常用的常量
常量类型和名称 功能介绍
public static final int SIZE 表示double类型的二进制位数
public static final int BYTES 表示double类型的字节个数
public static final Class TYPE 表示double类型的Class实例
  • 常用的方法
方法声明 功能介绍
Double(double value) 根据参数指定的浮点数据来构造对象(已过时)
Double(String s) 根据参数指定的字符串来构造对象 (已过时)
double doubleValue() 获取调用对象中的浮点数据并返回
static Double valueOf(double d) 根据参数指定浮点数据得到Double类型对象
boolean equals(Object obj) 比较调用对象与参数指定的对象是否相等
String toString() 返回描述调用对象数值的字符串形式
static double parseDouble(String s) 将字符串类型转换为double类型并返回
boolean isNaN() 判断调用对象的数值是否为非数字
  • 扩展:
    java.lang.Number类是个抽象类,是上述类的父类来描述所有类共有的成员。

Boolean类的概述

  • 基本概念
    java.lang.Boolean类型内部包装了一个boolean类型的变量作为成员变量,主要用于实现对 boolean类型的包装并提供boolean类型到String类之间的转换等方法。
  • 常用的常量
常量类型和名称 功能介绍
public static final Boolean FALSE 对应基值为false的对象
public static final Boolean TRUE 对应基值为true的对象
public static final Class TYPE 表示boolean类型的Class实例
  • 常用的方法
方法声明 功能介绍
Boolean(boolean value) 根据参数指定的布尔数值来构造对象(已过时)
Boolean(String s) 根据参数指定的字符串来构造对象 (已过时)
boolean booleanValue() 获取调用对象中的布尔数值并返回
static Boolean valueOf(boolean b) 根据参数指定布尔数值得到Boolean类型对象
boolean equals(Object obj) 比较调用对象与参数指定的对象是否相等
String toString() 返回描述调用对象数值的字符串形式
static boolean parseBoolean(String s) 将字符串类型转换为boolean类型并返回

Character类的概述

  • 基本概念
    java.lang.Character类型内部包装了一个char类型的变量作为成员变量,主要用于实现对char类型的包装并提供字符类别的判断和转换等方法。
  • 常用的常量
常量类型和名称 功能介绍
public static final int SIZE 表示char类型的二进制位数
public static final int BYTES 表示char类型的字节个数
public static final Class TYPE 表示char类型的Class实例
  • 常用的方法
方法声明 功能介绍
Character(char value) 根据参数指定的字符数据来构造对象(已过时)
char charValue() 获取调用对象中的字符数据并返回
static Character valueOf(char c) 根据参数指定字符数据得到Character类型对象
boolean equals(Object obj) 比较调用对象与参数指定的对象是否相等
String toString() 返回描述调用对象数值的字符串形式
static boolean isUpperCase(char ch) 判断参数指定字符是否为大写字符
static boolean isLowerCase(char ch) 判断参数指定字符是否为小写字符
static boolean isDigit(char ch) 判断参数指定字符是否为数字字符
static char toUpperCase(char ch) 将参数指定的字符转换为大写字符
static char toLowerCase(char ch) 将参数指定的字符转换为小写字符

包装类(Wrapper)的使用总结

  • 基本数据类型转换为对应包装类的方式
    调用包装类的构造方法或静态方法即可
  • 获取包装类对象中基本数据类型变量数值的方式
    调用包装类中的xxxValue方法即可
  • 字符串转换为基本数据类型的方式
    调用包装类中的parseXxx方法即可

4. 数学处理类(熟悉)

Math类的概述

  • 基本概念
    java.lang.Math类主要用于提供执行数学运算的方法,如:对数,平方根。
  • 常用的方法
方法声明 功能介绍
static int max(int a, int b) 返回两个参数中的最大值
static int min(int a, int b) 返回两个参数中的最小值
static double pow(double a, double b) 返回第一个参数的幂
static int abs(int a) 返回参数指定数值的绝对值
static long round(double a) 返回参数四舍五入的结果
static double sqrt(double a) 返回参数的平方根
static double random() 返回0.0到1.0的随机数

BigDecimal类的概述

  • 基本概念
    由于float类型和double类型在运算时可能会有误差,若希望实现精确运算则借助 java.math.BigDecimal类型加以描述。
  • 常用的方法
方法声明 功能介绍
BigDecimal(String val) 根据参数指定的字符串来构造对象
BigDecimal add(BigDecimal augend) 用于实现加法运算
BigDecimal subtract(BigDecimal subtrahend) 用于实现减法运算
BigDecimal multiply(BigDecimal multiplicand) 用于实现乘法运算
BigDecimal divide(BigDecimal divisor) 用于实现除法运算

BigInteger类的概念

  • 基本概念
    若希望表示比long类型范围还大的整数数据,则需要借助java.math.BigInteger类型描述。
  • 常用的方法
方法声明 功能介绍
BigInteger(String val) 根据参数指定的字符串来构造对象
BigInteger add(BigInteger val) 用于实现加法运算
BigInteger subtract(BigInteger val) 用于实现减法运算
BigInteger multiply(BigInteger val) 用于实现乘法运算
BigInteger divide(BigInteger val) 用于实现除法运算
BigInteger remainder(BigInteger val) 用于实现取余运算
BigInteger[] divideAndRemainder(BigInteger val) 用于实现取商和余数的运算

Chapter12 String类的概述和使用

1. String类的概念(重点)

  • java.lang.String类用于描述字符串,Java程序中所有的字符串字面值都可以使用该类的对象加以描述,如:“abc”。
  • 该类由final关键字修饰,表示该类不能被继承。
  • 从jdk1.9开始该类的底层不使用char[]来存储数据,而是改成 byte[]加上编码标记,从而节约了一些空间。
  • 该类描述的字符串内容是个常量不可更改,因此可以被共享使用。
    如:
    String str1 = “abc”; >>> 其中"abc"这个字符串是个常量不可改变。
    str1 = “123”; >>> 将“123”字符串的地址赋值给变量str1。改变str1的指向并没有改变指向的内容

2. 常量池的概念(原理)

由于String类型描述的字符串内容是常量不可改变,因此Java虚拟机将首次出现的字符串放入常量池中,若后续代码中出现了相同字符串内容则直接使用池中已有的字符串对象而无需申请内存及创建对象,从而提高了性能。

  • intern()
    返回常量池中与当前字符串内容相同的在常量池中的对象的引用

3. 常用的构造方法(练熟、记住)

方法声明 功能介绍
String() 使用无参方式构造对象得到空字符序列
String(byte[] bytes, int offset, int length) 使用bytes数组中下标从offset位置开始的length个字节来构造对象
String(byte[] bytes) 使用bytes数组中的所有内容构造对象
String(char[] value, int offset, int count) 使用value数组中下标从offset位置开始的count个字符来构造对象
String(char[] value) 使用value数组中的所有内容构造对象
String(String original) 根据参数指定的字符串内容来构造对象,新创建对象为参数对象的副本

4. 常用的成员方法(练熟、记住)

方法声明 功能介绍
String toString() 返回字符串本身
byte[] getBytes() 将当前字符串内容转换为byte数组并返回
char[] toCharArray() 用于将当前字符串内容转换为char数组并返回
方法声明 功能介绍
char charAt(int index) 方法charAt用于返回字符串指定位置的字符。
int length() 返回字符串字符序列的长度
boolean isEmpty() 判断字符串是否为空
  • 案例题目
    判断字符串“上海自来水来自海上”是否为回文并打印,所谓回文是指一个字符序列无论从左向右读还是从右向左读都是相同的句子。
方法声明 功能介绍
int compareTo(String anotherString) 用于比较调用对象和参数对象的大小关系
int compareToIgnoreCase(String str) 不考虑大小写,也就是’a’和’A’是相等的关系
  • 案例题目
    编程实现字符串之间大小的比较并打印。
方法声明 功能介绍
String concat(String str) 用于实现字符串的拼接
boolean contains(CharSequence s) 用于判断当前字符串是否包含参数指定的内容
String toLowerCase() 返回字符串的小写形式
String toUpperCase() 返回字符串的大写形式
String trim() 返回去掉前导和后继空白的字符串
boolean startsWith(String prefix) 判断字符串是否以参数字符串开头
boolean startsWith(String prefix, int toffset) 从指定位置开始是否以参数字符串开头
boolean endsWith(String suffix) 判断字符串是否以参数字符串结尾
  • 案例题目
    编程实现上述方法的使用。
方法声明 功能介绍
boolean equals(Object anObject) 用于比较字符串内容是否相等并返回
int hashCode() 获取调用对象的哈希码值
boolean equalsIgnoreCase(String anotherString) 用于比较字符串内容是否相等并返回,不考虑大小写,如:'A’和’a’是相等
  • 案例题目
    提示用户从键盘输入用户名和密码信息,若输入”admin”和”123456”则提示“登录成功,欢迎使用”,否则提示“用户名或密码错误,您还有n次机会”,若用户输入三次后依然错误则提示“账户已冻结,请联系客服人员!”
方法声明 功能介绍
int indexOf(int ch) 用于返回当前字符串中参数ch指定的字符第一次出现的下标
int indexOf(int ch, int fromIndex) 用于从fromIndex位置开始查找ch指定的字符
int indexOf(String str) 在字符串中检索str返回其第一次出现的位置,若找不到返回-1
int indexOf(String str, int fromIndex) 表示从字符串的fromIndex位置开始检索str第一次出现的位置
int lastIndexOf(int ch) 用于返回参数ch指定的字符最后一次出现的下标
int lastIndexOf(int ch, int fromIndex) 用于从fromIndex位置开始查找ch指定字符出现的下标
int lastIndexOf(String str) 返回str指定字符串最后一次出现的下标
int lastIndexOf(String str, int fromIndex) 用于从fromIndex位置开始反向搜索的第一次出现的下标。
  • 案例题目
    编写通用的代码可以查询字符串"Good Good Study, Day Day Up!"中所有"Day"出现的索引位置并打印出来。
方法声明 功能介绍
String substring(int beginIndex, int endIndex) 返回字符串中从下标beginIndex(包括)开始到 endIndex(不包括)结束的子字符串
String substring(int beginIndex) 返回字符串中从下标beginIndex(包括)开始到字符串结尾的子字符串
  • 案例题目
    提示用户从键盘输入一个字符串和一个字符,输出该字符(不含)后面的所有子字符串。

5. 正则表达式的概念(了解)

正则表达式本质就是一个“规则字符串”,可以用于对字符串数据的格式进行验证,以及匹配、查找、替换等操作。该字符串通常使用^运算符作为开头标志,使用$运算符作为结尾标志,当然也可以省略。

6. 正则表达式的规则(了解)

正则表达式 说明
[abc] 可以出现a、b、c中任意一个字符
[^abc] 可以出现任何字符,除了a、b、c的任意字符
[a-z] 可以出现a、b、c、……、z中的任意一个字符
[a-zA-Z0-9] 可以出现az、AZ、0~9中任意一个字符
正则表达式 说明
. 任意一个字符(通常不包含换行符)
\d 任意一个数字字符,相当于[0-9]
\D 任意一个非数字字符
\s 空白字符,相当于[\t\n\x0B\f\r]
\S 非空白字符
\w 任意一个单词字符,相当于[a-zA-Z_0-9]
\W 任意一个非单词字符
正则表达式 说明
X? 表示X可以出现一次或一次也没有,也就是0 ~ 1次
X* 表示X可以出现零次或多次,也就是0 ~ n次
X+ 表示X可以出现一次或多次,也就是1 ~ n次
X{n} 表示X可以出现恰好 n 次
X{n,} 表示X可以出现至少 n 次,也就是>=n次
X{n,m} 表示X可以出现至少 n 次,但是不超过 m 次,也就是>=n并且<=m次

7. 正则表达式相关的方法(熟悉)

方法名称 方法说明
boolean matches(String regex) 判断当前正在调用的字符串是否匹配参数指定的正则表达式规则
  • 案例题目
    使用正则表达式描述一下银行卡密码的规则:要求是由6位数字组成。
    使用正则表达式描述一下QQ号码的规则:要求是由非0开头的5~15位数组成。
    使用正则表达式描述一下手机号码的规则:要求是由1开头,第二位数是3、4、5、7、8中的一位,总共11位
    描述身份证号码的规则:总共18位,6位数字代表地区,4位数字代表年,2位数字代表月,2位数字代表日期, 3位数字代表个人,最后一位可能数字也可能是X。
方法名称 方法说明
String[] split(String regex) 参数regex为正则表达式,以regex所表示的字符串为分隔符,将字符串拆分成字符串数组
String replace(char oldChar, char newChar) 使用参数newChar替换此字符串中出现的所有参数
oldChar String replaceFirst(String regex, String replacement) 替换此字符串匹配给定的正则表达式的第一个子字符串
String replaceAll(String regex, String replacement) 将字符串中匹配正则表达式regex的字符串替换成 replacement

Chapter13 可变字符串类和日期相关类

1. 可变字符串类(重点)

基本概念

  • 由于String类描述的字符串内容是个常量不可改变,当需要在Java代码中描述大量类似的字符串时,只能单独申请和存储,此时会造成内存空间的浪费。
  • 为了解决上述问题,可以使用java.lang.StringBuilder类和java.lang.StringBuffer类来描述字符序列可以改变的字符串,如:“ab”。
  • StringBuffer类是从jdk1.0开始存在,属于线程安全的类,因此效率比较低。
  • StringBuilder类是从jdk1.5开始存在,属于非线程安全的类,效率比较高。

StringBuilder类常用的构造方法

方法声明 功能介绍
StringBuilder() 使用无参方式构造对象,容量为16
StringBuilder(int capacity) 根据参数指定的容量来构造对象,容量为参数指定大小
StringBuilder(String str) 根据参数指定的字符串来构造对象,容量为:16+字符串长度

StringBuilder类常用的成员方法

方法声明 功能介绍
int capacity() 用于返回调用对象的容量
int length() 用于返回字符串的长度,也就是字符的个数
StringBuilder insert(int offset, String str) 插入字符串并返回调用对象的引用,就是自己。
StringBuilder append(String str) 追加字符串
StringBuilder deleteCharAt(int index) 将当前字符串中下标为index位置的单个字符删除
StringBuilder delete(int start,int end) 删除字符串
StringBuilder replace(int start,int end,String str) 替换字符串
StringBuilder reverse() 字符串反转
  • 注意
    作为参数传递的话,方法内部String不会改变其值,StringBuffer和StringBuilder会改变其值。

返回值的设计

  • StringBuilder的很多方法的返回值均为StringBuilder类型。这些方法的返回语句均为:return this。
  • 由此可见,这些方法在对StringBuilder所封装的字符序列进行改变后又返回了该对象的引用。基于这样设计的目的在于可以连续调用。

2. Java8之前的日期相关类(熟悉)

System类的概述

  • 基本概念
    Java.lang.System类中提供了一些有用的类字段和方法。
  • 常用的方法
方法声明 功能介绍
static long currentTimeMillis() 返回当前时间与1970年1月1日0时0分0秒之间以毫秒为单位的时间差

Date类的概述

  • 基本概念
    java.util.Date类主要用于描述特定的瞬间,也就是年月日时分秒,可以精确到毫秒。
  • 常用的方法
方法声明 功能介绍
Date() 使用无参的方式构造对象,也就是当前系统时间
Date(long date) 根据参数指定毫秒数构造对象, 参数为距离1970年1月1日0时0分0秒的毫秒数
long getTime() 获取调用对象距离1970年1月1日0时0分0秒的毫秒数
void setTime(long time) 设置调用对象为距离基准时间time毫秒的时间点

SimpleDateFormat类的概述

  • 基本概念
    java.text.SimpleDateFormat类主要用于实现日期和文本之间的转换。
  • 常用的方法
方法声明 功能介绍
SimpleDateFormat() 使用无参方式构造对象
SimpleDateFormat(String pattern) 根据参数指定的模式来构造对象,模式主要有: y-年 M-月 d-日 H-时 m-分 s-秒
final String format(Datedate) 用于将日期类型转换为文本类型
Date parse(String source) 用于将文本类型转换为日期类型

Calendar类的概述

  • 基本概念
    java.util.Calender类主要用于描述特定的瞬间,取代Date类中的过时方法实现全球化。
    该类是个抽象类,因此不能实例化对象,其具体子类针对不同国家的日历系统,其中应用最广泛的是GregorianCalendar(格里高利历),对应世界上绝大多数国家/地区使用的标准日历系统。
  • 常用的方法
方法声明 功能介绍
static Calendar getInstance() 用于获取Calendar类型的引用
void set(int year, int month, int date, int hourOfDay, int minute, int second) 用于设置年月日时分秒信息
Date getTime() 用于将Calendar类型转换为 Date类型
void set(int field, int value) 设置指定字段的数值
void add(int field, int amount) 向指定字段增加数值
  • 多态的使用场合
  1. 通过方法的参数传递形成多态;
    public static void draw(Shape s){
    s.show();
    }
    draw(new Rect(1, 2, 3, 4));
  2. 在方法体中直接使用多态的语法格式
    Account acc = new FixedAccount();
  3. 通过方法的返回值类型形成多态
    Calender getInstance(){
    return new GregorianCalendar(zone, aLocale);
    }

3. Java8中的日期相关类(熟悉)

Java8日期类的由来
JDK 1.0中包含了一个java.util.Date类,但是它的大多数方法已经在JDK 1.1引入Calendar类之后被弃用了。而Calendar并不比Date好多少。它们面临的问题是:

  • Date类中的年份是从1900开始的,而月份都从0开始。
  • 格式化只对Date类有用,对Calendar类则不能使用。
  • 非线程安全等。

Java8日期类的概述

  • Java 8通过发布新的Date-Time API来进一步加强对 日期与时间的处理。
  • java.time包:该包日期/时间API的基础包。
  • java.time.chrono包:该包提供对不同日历系统的访问。
  • java.time.format包:该包能够格式化和解析日期时间对象。
  • java.time.temporal包:该包包含底层框架和扩展特性。
  • java.time.zone包:该包支持不同时区以及相关规则的类。

LocalDate类的概述

  • 基本概念
    java.time.LocalDate类主要用于描述年-月-日格式的日期信息,该类不表示时间和时区信息。
  • 常用的方法
方法声明 功能介绍
static LocalDate now() 在默认时区中从系统时钟获取当前日期

LocalTime类的概述

  • 基本概念
    java.time.LocalTime 类主要用于描述时间信息,可以描述时分秒以及纳秒。
  • 常用的方法
方法声明 功能介绍
static LocalTime now() 从默认时区的系统时间中获取当前时间
static LocalTime now(ZoneId zone) 获取指定时区的当前时间

LocalDateTime类的概述

  • 基本概念
    java.time.LocalDateTime类主要用于描述ISO-8601日历系统中没有时区的日期时间,如2007-12-03T10:15:30。
  • 常用的方法
方法声明 功能介绍
static LocalDateTime now() 从默认时区的系统时间中获取当前日期时间
static LocalDateTime of(int year, int month, int dayOfMonth, int hour, int minute, int second) 根据参数指定的年月日时分秒信息来设置日期时间
int getYear() 获取年份字段的数值
int getMonthValue() 获取1到12之间的月份字段
int getDayOfMonth() 获取日期字段
int getHour() 获取小时数
int getMinute() 获取分钟数
int getSecond() 获取秒数
LocalDateTime withYear(int year) 设置为参数指定的年
LocalDateTime withMonth(int month) 设置为参数指定的月
LocalDateTime withDayOfMonth(int dayOfMonth) 设置为参数指定的日
LocalDateTime withHour(int hour) 设置为参数指定的时
LocalDateTime withMinute(int minute) 设置为参数指定的分
LocalDateTime withSecond(int second) 设置为参数指定的秒
LocalDateTime plusYears(long years) 加上参数指定的年
LocalDateTime plusMonths(long months) 加上参数指定的月
LocalDateTime plusDays(long days) 加上参数指定的日
LocalDateTime plusHours(long hours) 加上参数指定的时
LocalDateTime plusMinutes(long minutes) 加上参数指定的分
LocalDateTime plusSeconds(long seconds) 加上参数指定的秒
LocalDateTime minusYears(long years) 减去参数指定的年
LocalDateTime minusMonths(long months) 减去参数指定的月
LocalDateTime minusDays(long days) 减去参数指定的日
LocalDateTime minusHours(long hours) 减去参数指定的时
LocalDateTime minusMinutes(long minutes) 减去参数指定的分
LocalDateTime minusSeconds(long seconds) 减去参数指定的秒

Instant类的概述

  • 基本概念
    java.time.Instant类主要用于描述瞬间的时间点信息。
  • 常用的方法
方法声明 功能介绍
static Instant now() 从系统时钟上获取当前时间
OffsetDateTime atOffset(ZoneOffset offset) 将此瞬间与偏移量组合以创建偏移日期时间
static Instant ofEpochMilli(long epochMilli) 根据参数指定的毫秒数来构造对象,参数为距离1970年1月1日0时0分0秒的毫秒数
long toEpochMilli() 获取距离1970年1月1日0时0分0秒的毫秒数

DateTimeFormatter类的概述

  • 基本概念
    java.time.format.DateTimeFormatter类主要用于格式化和解析日期。
  • 常用的方法
方法声明 功能介绍
static DateTimeFormatter ofPattern(String pattern) 根据参数指定的模式来获取对象
String format(TemporalAccessor temporal) 将参数指定日期时间转换为字符串
TemporalAccessor parse(CharSequence text) 将参数指定字符串转换为日期时间

Chapter14 集合类库(上)

1. 集合的概述(重点)

集合的由来

  • 当需要在Java程序中记录单个数据内容时,则声明一个变量。
  • 当需要在Java程序中记录多个类型相同的数据内容时,声明一个一维数组。
  • 当需要在Java程序中记录多个类型不同的数据内容时,则创建一个对象。
  • 当需要在Java程序中记录多个类型相同的对象数据时,创建一个对象数组。
  • 当需要在Java程序中记录多个类型不同的对象数据时,则准备一个集合。

集合的框架结构

  • Java中集合框架顶层框架是:java.util.Collection集合 和 java.util.Map集合。
  • 其中Collection集合中存取元素的基本单位是:单个元素。
  • 其中Map集合中存取元素的基本单位是:单对元素。
    在这里插入图片描述

2. Collection集合(重点)

基本概念

  • java.util.Collection接口是List接口、Queue接口以及Set接口的父接口,因此该接口里定义的方法既可用于操作List集合,也可用于操作Queue集合和Set集合。
    在这里插入图片描述

常用的方法(练熟、记住)

方法声明 功能介绍
boolean add(E e); 向集合中添加对象
boolean addAll(Collection<? extends E>c) 用于将参数指定集合c中的所有元素一个一个一次添加到当前集合中
boolean contains(Object o); 判断是否包含指定对象
boolean containsAll(Collection<?> c) 判断是否包含参数指定的所有对象
boolean retainAll(Collection<?> c) 保留当前集合中存在且参数集合中存在的所有对象,保留到当前集合。true if this collection changed as a result of the call
boolean remove(Object o); 从集合中删除对象 工作原理:Objects.equals(o, e)与contain原理相同
boolean removeAll(Collection<?> c) 从集合中删除参数指定的所有对象。一个一个一次进行删除,有则删除,无则不删
void clear(); 清空集合
int size(); 返回包含对象的个数
boolean isEmpty(); 判断是否为空
boolean equals(Object o) 判断是否相等
int hashCode() 获取当前集合的哈希码值
Object[] toArray() 将集合转换为数组 数组->集合:Arrays.asList(数组);
Iterator iterator() 获取当前集合的迭代器
  • 打印集合中的所有元素时,本质上就是打印集合中的每个对象,也就是每个对象调用对应的toString类

  • cantains方法 工作原理

c1 = [Person{
    
    name='ZhangFei', age=30}]
c1.contains(new Person("ZhangFei",30));
// contains方法的工作原理就是,拿着参数指定的对象与集合中已有的元素依次进行比较,比较的方式调用Object中equals方法
// contains方法的工作原理是:Object.equals(object o, e)
// o : contains方法的形式参数
// e : 集合中的每个元素
// equals()的工作原理如下:
/*
            public static boolean equals(Object a, Object b){       a:o:形参:Person   b:e:集合元素
                return (a == b) || (a != null && a.equals(b));
                a == b:Person对象与结合中已有的对象的地址相同
                a != null && a.equals(b):Person对象不为空,则Person对象调用equals方法与集合中已有元素相等
            }
*/
// 当Person类中没有重写equals方法时,则调用Object类中继承下来的equals方法,比地址

3. Iterator接口(重点)

基本概念

  • java.util.Iterator接口主要用于描述迭代器对象,可以遍历Collection集合中的所有元素。
  • java.util.Collection接口继承Iterator接口,因此所有实现Collection接口的实现类都可以使用该迭代器对象。

常用的方法

方法声明 功能介绍
boolean hasNext() 判断集合中是否有可以迭代/访问的元素
E next() 用于取出一个元素并指向下一个元素
void remove() 用于删除访问到的最后一个元素
  • 迭代中使用集合的remove方法会出现异常,要用迭代器提供的remove方法(it is not generally permissible for one thread to modify a Collection while another thread is iterating over it)
  • 案例题目:
    如何使用迭代器实现toString方法的打印效果?

4. for each循环(重点)

基本概念

  • Java5推出了增强型for循环语句,可以应用数组和集合的遍历
  • 是经典迭代的“简化版”。
  • 只能遍历(不能修改)

语法格式

  • for(元素类型 变量名 : 数组/集合名称) {
    循环体;
    }

执行流程

  • 不断地从数组/集合中取出一个元素赋值给变量名并执行循环体,直到取完所有元素为止。
  • 由调试源码可知:该方法确实是迭代器的简化版

5. List集合(重中之重)

基本概念

  • java.util.List集合是Collection集合的子集合,该集合中允许有重复的元素并且有先后放入次序。

  • 该集合的主要实现类有:ArrayList类、LinkedList类、Stack类、Vector类

  • 其中ArrayList类的底层是采用动态数组进行数据管理的,支持下标访问,增删元素不方便。
    由源码可知:当new对象时并没有申请数组的内存空间,当调用add方法添加元素时会给数组申请长度为10的一维数组
    扩容的原理是:原来长度的1.5倍

  • 其中LinkedList类的底层是采用双向链表进行数据管理的,访问不方便,增删元素方便。
    节点:节点的元素值,前一个节点的地址,后一个节点的地址
    在这里插入图片描述

  • 可以认为ArrayList和LinkedList的方法在逻辑上完全一样,只是在性能上有一定的差别,ArrayList更适合于随机访问而LinkedList更适合于插入和删除;在性能要求不是特别苛刻的情形下可以忽略这个差别。

  • 其中Stack类的底层是采用动态数组进行数据管理的,该类主要用于描述一种具有后进先出特征的数据结构,叫做(last in first out LIFO)。
    在这里插入图片描述

  • 其中Vector类的底层是采用动态数组进行数据管理的,该类与ArrayList类相比属于线程安全的类,效率比较低,以后开发中基本不用。自动扩增2倍

常用的方法

方法声明 功能介绍
void add(int index, E element) 向集合中指定位置添加元素
boolean addAll(int index, Collection<? extends E> c) 向集合中添加所有元素
E get(int index) 从集合中获取指定位置元素
int indexOf(Object o) 查找参数指定的对象
int lastIndexOf(Object o) 反向查找参数指定的对象
E set(int index, E element) 修改指定位置的元素
E remove(int index) 删除指定位置的元素
List subList(int fromIndex, int toIndex) 用于获取子List,子集合和当前集合公用同一块内存空间,即子集合有变当前集合一起变
  • 案例题目
    准备一个Stack集合,将数据11、22、33、44、55依次入栈并打印,然后查看栈顶元素并打印,然后将栈中所有数据依次出栈并打印。
    再准备一个Stack对象,将数据从第一个栈中取出来放入第二个栈中,然后再从第二个栈中取出并打印。

6. Queue集合(重点)

基本概念

  • java.util.Queue集合是Collection集合的子集合,与List集合属于平级关系。
  • 该集合的主要用于描述具有先进先出特征的数据结构,叫做队列(first in first out FIFO)。
  • 该集合的主要实现类是LinkedList类,因为该类在增删方面比较有优势。
    在这里插入图片描述

常用的方法

方法声明 功能介绍
boolean offer(E e) 将一个对象添加至队尾,若添加成功则返回true
E poll() 从队首删除并返回一个元素
E peek() 返回队首的元素(但并不删除)
  • 案例题目
    准备一个Queue集合,将数据11、22、33、44、55依次入队并打印,然后查看队首元素并打印,然后将队列中所有数据依次出队并打印。

总结

  1. 集合的概述
    集合的由来,两张图
  2. Collection集合
    常用的方法
  3. Iterator接口
    概念,遍历集合,常用方法
  4. for each结构
    java5新增,是迭代器的简化版
  5. List集合
    概念,常用实现类,常用方法
  6. Queue集合
    概念,常用实现类,常用方法

Chapter15 集合类库(下)

1. 泛型机制(熟悉)

基本概念

  • 通常情况下集合中可以存放不同类型的对象,是因为将所有对象都看做Object类型放入的,因此从集合中取出元素时也是Object类型,为了表达该元素真实的数据类型,则需要强制类型转换,而强制类型转换可能会引发类型转换异常。
  • 为了避免上述错误的发生,从Java5开始增加泛型机制,也就是在集合名称的右侧使用<数据类型>的方式来明确要求该集合中可以存放的元素类型,若放入其它类型的元素则编译报错。
  • 泛型只在编译时期有效,在运行时期不区分是什么类型。

底层原理

  • 泛型的本质就是参数化类型,也就是让数据类型作为参数传递,其中E相当于形式参数负责占位,而使用集合时<>中的数据类型相当于实际参数,用于给形式参数E进行初始化,从而使得集合中所有的E被实际参数替换,由于实际参数可以传递各种各样广泛的数据类型,因此得名为泛型。
  • 如:
 //其中i叫做形式参数,负责占位 				其中E叫做形式参数,负责占位
 //int i = 10; 								E = String;
 //int i = 20; 								E = Integer;
 public static void show(int i) {
    
     			public interface List {
    
    
 	... 										...
 }											}
 //其中10叫做实际参数,负责给形式参数初始化 	//其中String叫做实际参数
 show(10); 									List lt1 = ...;
 show(20); 									List lt2 = ...;

自定义泛型接口

  • 泛型接口和普通接口的区别就是后面添加了类型参数列表,可以有多个类型参数,如:<E, T, … >等。

自定义泛型类

  • 泛型类和普通类的区别就是类名后面添加了类型参数列表,可以有多个类型参数,如:<E, T, … >等。
  • 实例化泛型类时应该指定具体的数据类型,并且是引用数据类型而不是基本数据类型。
  • 父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型。
  • 子类必须是“富二代”,子类除了指定或保留父类的泛型,还可以增加自己的泛型。

自定义泛型方法

  • 泛型方法就是我们输入参数的时候,输入的是类型参数,而不是具体的参数。我们在调用这个泛型方法的时需要对泛型参数进行实例化。
  • 泛型方法的格式:
    [访问权限] <泛型> 返回值类型 方法名([泛型标识 参数名称]) { 方法体; }
  • 在静态方法中使用泛型参数的时候,需要我们把静态方法定义为泛型方法。(不是泛型方法的成员方法中的泛型参数,new对象时会被指定类型就不在是泛型参数了,也就不是方形方法了。为什么静态方法中使用泛型参数一定要泛型方法呢?new对象之后才能明确泛型参数。)

泛型在继承上的体现

  • 如果B是A的一个子类或子接口,而G是具有泛型声明的类或接口,则G并不是G的子类型!
    比如:String是Object的子类,但是List并不是List的子类。
    List<Animal> lt1= new LinkedList<>();
    List<Dog> lt2 = new LinkedList<>();
    lt1 = lt2 Error : List<Dog>类型向List<Animal>类型的转换, 有父子类关系

通配符的使用

  • 有时候我们希望传入的类型在一个指定的范围内,此时就可以使用泛型通配符了。
  • 如:之前传入的类型要求为Integer类型,但是后来业务需要Integer的父类Number类也可以传入。
  • 泛型中有三种通配符形式:
    <?> 无限制通配符:表示我们可以传入任意类型的参数。
      支持获取,不支持添加
    <? extends E> 表示类型的上界是E,只能是E或者是E的子类。
      支持获取,不支持添加
    <? super E> 表示类型的下界是E,只能是E或者是E的父类。
      支持获取,支持添加E或E的子类

2. Set集合(熟悉)

基本概念

  • java.util.Set集合是Collection集合的子集合,与List集合平级。
  • 该集合中元素没有先后放入次序打印也无顺序,且不允许重复
  • 该集合的主要实现类是:HashSet类 和 TreeSet类以及LinkedHashSet类。
  • 其中HashSet类的底层是采用哈希表进行数据管理的。
  • 其中TreeSet类的底层是采用红黑树进行数据管理的。
  • 其中LinkedHashSet类与HashSet类的不同之处在于内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。
    在这里插入图片描述

在这里插入图片描述

图:简单的哈希表结构

常用的方法

  • 参考Collection集合中的方法即可!
  • 案例题目
    准备一个Set集合指向HashSet对象,向该集合中添加元素"two"并打印,再向集合中添加元素"one"并打印,再向集合中添加元素"three"并打印,再向集合中添加"one"并打印。

元素放入HashSet集合的原理

  • 使用元素调用hashCode方法获取对应的哈希码值,再由某种哈希算法计算出该元素在数组中的索引位置。
  • 若该位置没有元素,则将该元素直接放入即可。
  • 若该位置有元素,则使用新元素与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入。
  • 若新元素与已有元素的哈希值相同,则使用新元素调用equals方法与已有元素依次比较。
  • 若相等则添加元素失败,否则将元素直接放入即可。
  • 思考:为什么要求重写equals方法后要重写hashCode方法呢?
  • 解析:
     当两个元素调用equals方法相等时证明这两个元素相同,重写hashCode方法后保证这两个元素得到的哈希码值相同,由同一个哈希算法生成的索引位置相同,此时只需要与该索引位置已有元
    素比较即可,从而提高效率并避免重复元素的出现。

TreeSet集合的概念

  • 二叉树主要指每个节点最多只有两个子节点的树形结构。
  • 满足以下3个特征的二叉树叫做有序二叉树
    a. 左子树中的任意节点元素都小于根节点元素值;
    b. 右子树中的任意节点元素都大于根节点元素值;
    c. 左子树和右子树的内部也遵守上述规则;
  • 由于TreeSet集合的底层采用红黑树(有序二叉树)进行数据的管理,当有新元素插入到TreeSet集合时,需要使用新元素与集合中已有的元素依次比较来确定新元素的合理位置。
  • 比较元素大小的规则有两种方式:
     使用元素的自然排序规则进行比较并排序,让元素类型实现java.lang.Comparable接口;
     使用比较器规则进行比较并排序,构造TreeSet集合时传入java.util.Comparator接口;
  • 自然排序的规则比较单一,而比较器的规则比较多元化,而且比较器优先于自然排序 ;

3. Map集合(重点)

在这里插入图片描述

基本概念

  • java.util.Map<K,V>集合中存取元素的基本单位是:单对元素,其中类型参数如下:
    K - 此映射所维护的键(Key)的类型,相当于目录。
    V - 映射值(Value)的类型,相当于内容。
  • 该集合中key是不允许重复的,而且一个key只能对应一个value。
  • 该集合的主要实现类有:HashMap类、TreeMap类、LinkedHashMap类、Hashtable类、Properties类。
  • 其中HashMap类的底层是采用哈希表进行数据管理的。
  • 其中TreeMap类的底层是采用红黑树进行数据管理的。
  • 其中LinkedHashMap类与HashMap类的不同之处在于内部维护了一个双向链表,链表中记录了元素的迭代顺序,也就是元素插入集合中的先后顺序,因此便于迭代。
  • 其中Hashtable类是古老的Map实现类,与HashMap类相比属于线程安全的类,且不允许null作为key或者value的数值。
  • 其中Properties类是Hashtable类的子类,该对象用于处理属性文件,key和value都是String类型的。
  • Map集合是面向查询优化的数据结构, 在大数据量情况下有着优良的查询性能。
  • 经常用于根据key检索value的业务场景。
  • Set Map 关系
    在这里插入图片描述
  • 为什么在使用HashMap的时候总是使用String类作为key的类型?
    String类是不可变类,所以创建完String类对象之后,这个对象就不能改变了,此时我创建完对象后,
    就可以将对应的哈希码值储存起来,而HashMap的工作原理,就是通过key的哈希码值来得到的,
    用String类作为key之后,实际上就相当于获取String类的哈希码值,而之前已经计算好了,直接拿过来用,
    效率提高了

常用的方法

方法声明 功能介绍
V put(K key, V value) 将Key-Value对存入Map,若集合中已经包含该Key,则替换该Key所对应的Value,返回值为该Key原来所对应的Value,若没有则返回null
V get(Object key) 返回与参数Key所对应的Value对象,如果不存在则返回null
boolean containsKey(Object key); 判断集合中是否包含指定的Key
boolean containsValue (Object value); 判断集合中是否包含指定的Value
V remove(Object key) 根据参数指定的key进行删除
Set keySet() 返回此映射中包含的键的Set视图
Collection values() 返回此映射中包含的值的Set视图
Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射的Set视图

元素放入HashMap集合的原理

  • 使用元素的key调用hashCode方法获取对应的哈希码值,再由某种哈希算法计算在数组中的索引位置。
  • 若该位置没有元素,则将该键值对直接放入即可。
  • 若该位置有元素,则使用key与已有元素依次比较哈希值,若哈希值不相同,则将该元素直接放入。
  • 若key与已有元素的哈希值相同,则使用key调用equals方法与已有元素依次比较。
  • 若相等则将对应的value修改,否则将键值对直接放入即可。

相关的常量

  • DEFAULT_INITIAL_CAPACITY : HashMap的默认容量是16。

  • DEFAULT_LOAD_FACTOR:HashMap的默认加载因子是0.75。

  • threshold:扩容的临界值,该数值为:容量*填充因子,也就是12。

  • TREEIFY_THRESHOLD:若Bucket中链表长度大于该默认值则转化为红黑树存储,该数值是8。

  • MIN_TREEIFY_CAPACITY:桶中的Node被树化时最小的hash表容量,该数值是64。

  • HashMap在Java7和Java8中有哪些主要的不同之处?
    链表数组,头插/
    链表数组,红黑树,尾插/
    (初始化,哈希码值计算方法,扩容之后的计算方式)

4. Collections类

基本概念

  • java.util.Collections类主要提供了对集合操作或者返回集合的静态方法。

常用的方法

方法声明 功能介绍
static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) 根据元素的自然顺序返回给定集合的最大元素
static T max(Collection<? extends T> coll, Comparator<? super T> comp) 根据指定比较器引发的顺序返回给定集合的最大元素
static <T extends Object & Comparable<?super T>> T min(Collection<? extends T> coll) 根据元素的自然顺序返回给定集合的最小元素
static T min(Collection<? extends T> coll, Comparator<? super T> comp) 根据指定比较器引发的顺序返回给定集合的最小元素
static void copy(List<? super T> dest, List<? extends T> src) 将一个列表中的所有元素复制到另一个列表中
方法声明 功能介绍
static void reverse(List<?> list) 反转指定列表中元素的顺序
static void shuffle(List<?> list) 使用默认的随机源随机置换指定的列表,打乱顺序
static <T extends Comparable<? super T>> void sort(List list) 根据其元素的自然顺序将指定列表按升序排序
static void sort(List list, Comparator<? super T> c) 根据指定比较器指定的顺序对指定列表进行排序
static void swap(List<?> list, int i, int j) 交换指定列表中指定位置的元素

5. 总结

  1. 泛型机制(熟悉)
    概念和本质,自定义泛型接口,类,方法,继承方面的体现,通配符
  2. Set集合(熟悉)
    概念,主要实现类,常用的方法,两种方式制定排序规则
  3. Map集合(重点)
    概念,主要实现类,常用方式
  4. Collections类(熟悉)
    概念和常用的方法

第一阶段模块四 JavaSE Java核心类库(下)

Chapter16 异常机制和File类

1. 异常机制(重点)

基本概念

  • 异常就是"不正常"的含义,在Java语言中主要指程序执行中发生的不正常情况。
  • java.lang.Throwable类是Java语言中错误(Error)和异常(Exception)的超类。
  • 其中Error类主要用于描述Java虚拟机无法解决的严重错误,通常无法编码解决,如:JVM挂掉了 等。
  • 其中Exception类主要用于描述因编程错误或偶然外在因素导致的轻微错误,通常可以编码解决,如:0作为除数等。

异常的分类

  • java.lang.Exception类是所有异常的超类,主要分为以下两种:
    RuntimeException - 运行时异常,也叫作非检测性异常
    IOException和其它异常 - 其它异常,也叫作检测性异常,所谓检测性异常就是指在编译阶段都能被编译器检测出来的异常。
  • 其中RuntimeException类的主要子类:
    ArithmeticException类 - 算术异常
    ArrayIndexOutOfBoundsException类 - 数组下标越界异常
    NullPointerException - 空指针异常
    ClassCastException - 类型转换异常
    NumberFormatException - 数字格式异常
  • 注意:
    当程序执行过程中发生异常但又没有手动处理时,则由Java虚拟机采用默认方式处理异常,而默认处理方式就是:打印异常的名称、异常发生的原因、异常发生的位置以及终止程序。
    在这里插入图片描述

异常的避免

  • 在以后的开发中尽量使用if条件判断来避免异常的发生。
  • 但是过多的if条件判断会导致程序的代码加长、臃(yong)肿,可读性差。

异常的捕获

  • 语法格式
    try {
     编写可能发生异常的代码;
    }
    catch(异常类型 引用变量名) {
     编写针对该类异常的处理代码;
    }
    catch(异常类型 引用变量名) {
     编写针对该类异常的处理代码;
    }

    finally {
    编写无论是否发生异常都要执行的代码
    }
  • 注意事项
    a.当需要编写多个catch分支时,切记小类型应该放在大类型的前面
    b.懒人的写法:
     catch(Exception e) {}
    c.finally通常用于进行善后处理,如:关闭已经打开的文件等。
  • 执行流程
    try {
      a;
      b; - 可能发生异常的语句
      c;
    }catch(Exception ex) {
      d;
    }finally {
      e;
    }
    当没有发生异常时的执行流程:a b c e;
    当发生异常时的执行流程:a b d e;

异常的抛出

  • 基本概念
    在某些特殊情况下有些异常不能处理或者不便于处理时,就可以将该异常转移给该方法的调用者,这种方法就叫异常的抛出。当方法执行时出现异常,则底层生成一个异常类对象抛出,此时异常代码后续的代码就不再执行
  • 不建议在main方法中抛出异常。异常抛给main方法,JVM处理异常,JVM负担很重,已经有很多事要做了。
  • 语法格式
    访问权限 返回值类型 方法名称(形参列表) throws 异常类型1,异常类型2,…{ 方法体; }
    如:
    public void show() throws IOException{}
  • 方法重写的原则
    a.要求方法名相同、参数列表相同以及返回值类型相同,从jdk1.5开始支持返回子类类型;
    b.要求方法的访问权限不能变小,可以相同或者变大;
    c.要求方法不能抛出更大的异常;(可以:相同,子类,不抛)(不可以:平级,父类)
  • 注意:
    子类重写的方法不能抛出更大的异常、不能抛出平级不一样的异常,但可以抛出一样的异常、更小的异常以及不抛出异常。
  • 经验分享
      若父类中被重写的方法没有抛出异常时,则子类中重写的方法只能进行异常的捕获处理。
      若一个方法内部又以递进方式分别调用了好几个其它方法,则建议这些方法内可以使用抛出的方法处理到最后一层进行捕获方式处理。

自定义异常

  • 基本概念
    当需要在程序中表达年龄不合理的情况时,而Java官方又没有提供这种针对性的异常,此时就需要程序员自定义异常加以描述。
  • 实现流程
    a.自定义xxxException异常类继承Exception类或者其子类。
    b.提供两个版本的构造方法,一个是无参构造方法,另外一个是字符串作为参数的构造方法。
    c.序列化的版本号
  • 异常的产生
    throw new 异常类型(实参);
    如:
      throw new AgeException(“年龄不合理!!!”);
  • Java采用的异常处理机制是将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序
    简洁、优雅,并易于维护。

2. File类(重点)

基本概念

  • java.io.File类主要用于描述文件或目录路径的抽象表示信息,可以获取文件或目录的特征信息,如:大小等。

常用的方法

方法声明 功能概述
File(String pathname) 根据参数指定的路径名来构造对象
File(String parent, String child) 根据参数指定的父路径和子路径信息构造对象
File(File parent, String child) 根据参数指定的父抽象路径和子路径信息构造对象
boolean exists() 测试此抽象路径名表示的文件或目录是否存在
String getName() 用于获取文件的名称
long length() 返回由此抽象路径名表示的文件的长度
long lastModified() 用于获取文件的最后一次修改时间
String getAbsolutePath() 用于获取绝对路径信息
boolean delete() 用于删除文件,当删除目录时要求是空目录
boolean createNewFile() 用于创建新的空文件
boolean mkdir() 用于创建目录
boolean mkdirs() 用于创建多级目录
File[] listFiles() 获取该目录下的所有内容
boolean isFile() 判断是否为文件
boolean isDirectory() 判断是否为目录
File[] listFiles(FileFilter filter) 获取目录下满足筛选器的所有内容
  • 案例题目
    遍历指定目录以及子目录中的所有内容并打印出来。(递归思想)

  • 绝对路径:根目录开始的路径信息 如:c:/ d:/ /…(linux)

  • 相对路径:当前目录开始的路径信息 如:./(当前目录) …/(上个目录) 推荐

3. 总结

1.异常机制(重点)
概念,分类,避免异常发生,捕获处理,抛出异常,自定义异常
2.File类(重点)
概念,文件的管理,目录的管理,目录的遍历

Chapter17 IO流

1. IO流的概念

  • IO就是Input和Output的简写,也就是输入和输出的含义。
  • IO流就是指读写数据时像流水一样从一端流到另外一端,因此得名为“流"。

2. 基本分类

  • 按照读写数据的基本单位不同,分为 字节流字符流
    其中字节流主要指以字节为单位进行数据读写的流,可以读写任意类型的文件。
    其中字符流主要指以字符(2个字节)为单位进行数据读写的流,只能读写文本文件。
  • 按照读写数据的方向不同,分为 输入流输出流(站在程序的角度)。
    其中输入流主要指从文件中读取数据内容输入到程序中,也就是读文件。
    其中输出流主要指将程序中的数据内容输出到文件中,也就是写文件。
  • 按照流的角色不同分为 节点流处理流
    其中节点流主要指直接和输入输出源对接的流。
    其中处理流主要指需要建立在节点流的基础之上的流。
    在这里插入图片描述

3. 体系结构

分类 字节输入流 字节输出流 字符输入流 字符输出流
抽象基类 InputStream OutputStream Reader Writer
访问文件 FileInputStream FileOutputStream FileReader FileWriter
访问数组 ByteArrayInputStream ByteArrayOutputStream CharArrayReader CharArrayWriter
访问管道 PipedInputStream PipedOutputStream PipedReader PipedWriter
访问字符串 StringReader StringWriter
缓冲流 BufferedInputStream BufferedOutputStream BufferedReader BufferedWriter
转换流 InputStreamReader OutputStreamWriter
对象流 ObjectInputStream ObjectOutputStream
。。。。。 FilterInputStream FilterOutputSstream FilterReader FilterWriter
打印流 PrintStream PrintWriter
推回输入流 PushbackInputStream PushbackReader
特殊流 DataInputStream DataOutputStream

在这里插入图片描述

4. 相关流的详解

FileWriter类(重点)

  • 基本概念
    java.io.FileWriter类主要用于将文本内容写入到文本文件。

  • 常用的方法
    (FileWriterTest.java)

方法声明 功能介绍
FileWriter(String fileName) 根据参数指定的文件名构造对象, 若文件不存在,该流会自动创建新的空文件, 若文件存在,该流会清空文件中的原有内容 (拿着一个水管直接碓到水桶里,FileWriter是水管)
FileWriter(String fileName, boolean append) 以追加的方式根据参数指定的文件名来构造对象, 若文件不存在则自动创建新的空文件,若文件存在则保留文件原有数据内容
void write(int c) 写入单个字符, 每当写入一个字符后文件中的读写位置向后移动一位
void write(char[] cbuf, int off, int len) 将指定字符数组中从偏移量off开始的len个字符写入此文件输出流, 每当写入一个字符后文件中的读写位置向后移动一位
void write(char[] cbuf) 将cbuf.length个字符从指定字符数组写入此文件输出流中, 每当写入一个字符后文件中的读写位置向后移动一位
void flush() 刷新流(流里残留的刷倒水桶里)
void close() 关闭流对象并释放有关的资源 (close 自带 flush功能)

FileReader类(重点)

  • 基本概念
    java.io.FileReader类主要用于从文本文件读取文本数据内容。

  • 常用的方法

方法声明 功能介绍
FileReader(String fileName) 根据参数指定的文件名构造对象
int read() 读取单个字符的数据并返回,返回-1表示读取到末尾
int read(char[] cbuf, int offset, int length) 从输入流中将最多len个字符的数据读入一个字符数组中,返回读取到的字符个数,返回-1表示读取到末尾
int read(char[] cbuf) 从此输入流中将最多 cbuf.length 个字符的数据读入字符数组中,返回读取到的字符个数,返回-1表示读取到末尾
void close() 关闭流对象并释放有关的资源
  • 案例题目
    文本拷贝
    (FileCharCopyTest.java)
    图片拷贝 X

FileOutputStream类(重点)

  • 基本概念
    java.io.FileOutputStream类主要用于将图像数据之类的原始字节流写入到输出流中。

  • 常用的方法
    (FileByteCopyTest.java)

方法声明 功能介绍
FileOutputStream(String name) 根据参数指定的文件名来构造对象
FileOutputStream(String name, boolean append) 以追加的方式根据参数指定的文件名来构造对象
void write(int b) 将指定字节写入此文件输出流
void write(byte[] b, int off, int len) 将指定字节数组中从偏移量off开始的len个字节写入此文件输出流
void write(byte[] b) 将 b.length 个字节从指定字节数组写入此文件输出流中
void flush() 刷新此输出流并强制写出任何缓冲的输出字节
void close() 关闭流对象并释放有关的资源

FileInputStream类(重点)

  • 基本概念
    java.io.FileInputStream类主要用于从输入流中以字节流的方式读取图像数据等。

  • 常用的方法
    (FileByteCopyTest.java)

方法声明 功能介绍
FileInputStream(String name) 根据参数指定的文件路径名来构造对象
int read() 从输入流中读取单个字节的数据并返回,返回-1表示读取到末尾
int read(byte[] b, int off, int len) 从此输入流中将最多len个字节的数据读入字节数组中,返回读取到的字节个数,返回-1表示读取到末尾
int read(byte[] b) 从此输入流中将最多 b.length 个字节的数据读入字节数组中,返回读取到的字节个数,返回-1表示读取到末尾
void close() 关闭流对象并释放有关的资源
int available() 获取输入流所关联文件的大小
  • 案例题目
    编程实现两个文件之间的拷贝功能。
    方式一:以单个字节为单位进行拷贝,也就是每次读取一个字节后再写入一个字节。缺点:文件稍大时,拷贝效率低
    方式二:准备一个和文件大小一样的缓冲区,一次性将文件中的所有内容取出到缓冲区然后一次性写入进去。 缺点:若文件过大时,无法申请和文件大小一样的缓冲区,真是物理内存不足
    方法三:准备一个相对适当的缓冲区,分多次将文件拷贝完成 (推荐)

BufferedOutputStream类(重点)

  • 基本概念
    java.io.BufferedOutputStream类主要用于描述缓冲输出流,此时不用为写入的每个字节调用底层系统。

  • 常用的方法
    (BufferedByteCopyTest.java)

方法声明 功能介绍
BufferedOutputStream(OutputStream out) 根据参数指定的引用来构造对象
BufferedOutputStream(OutputStream out, int size) 根据参数指定的引用和缓冲区大小来构造对象
void write(int b) 写入单个字节
void write(byte[] b, int off, int len) 写入字节数组中的一部分数据
void write(byte[] b) 写入参数指定的整个字节数组
void flush() 刷新流
void close() 关闭流对象并释放有关的资源

BufferedInputStream类(重点)

  • 基本概念
    java.io.BufferedInputStream类主要用于描述缓冲输入流。

  • 常用的方法
    (BufferedByteCopyTest.java)

方法声明 功能介绍
BufferedInputStream(InputStream in) 根据参数指定的引用构造对象
BufferedInputStream(InputStream in, int size) 根据参数指定的引用和缓冲区大小构造对象
int read() 读取单个字节
int read(byte[] b, int off, int len) 读取len个字节
int read(byte[] b) 读取b.length个字节
void close() 关闭流对象并释放有关的资源

BufferedWriter类(重点)

  • 基本概念
    java.io.BufferedWriter类主要用于写入单个字符、字符数组以及字符串到输出流中。

  • 常用的方法
    (BufferedCharCopyTest.java)

方法声明 功能介绍
BufferedWriter(Writer out) 根据参数指定的引用来构造对象
BufferedWriter(Writer out, int sz) 根据参数指定的引用和缓冲区大小来构造对象
void write(int c) 写入单个字符到输出流中
void write(char[] cbuf, int off, int len) 将字符数组cbuf中从下标off开始的len个字符写入输出流中
void write(char[] cbuf) 将字符串数组cbuf中所有内容写入输出流中
void write(String s, int off, int len) 将参数s中下标从off开始的len个字符写入输出流中
void write(String str) 将参数指定的字符串内容写入输出流中
void newLine() 用于写入行分隔符到输出流中 (\r\n)
void flush() 刷新流
void close() 关闭流对象并释放有关的资源

BufferedReader类(重点)

  • 基本概念
    java.io.BufferedReader类用于从输入流中读取单个字符、字符数组以及字符串。

  • 常用的方法
    (BufferedCharCopyTest.java)

方法声明 功能介绍
BufferedReader(Reader in) 根据参数指定的引用来构造对象
BufferedReader(Reader in, int sz) 根据参数指定的引用和缓冲区大小来构造对象
int read() 从输入流读取单个字符,读取到末尾则返回-1,否则返回实际读取到的字符内容
int read(char[] cbuf, int off, int len) 从输入流中读取len个字符放入数组cbuf中下标从off开始的位置上,若读取到末尾则返回-1,否则返回实际读取到的字符个数
int read(char[] cbuf) 从输入流中读满整个数组cbuf
String readLine() 读取一行字符串并返回,返回null表示读取到末尾
void close() 关闭流对象并释放有关的资源

PrintStream类

  • 基本概念
    java.io.PrintStream类主要用于更加方便地打印各种数据内容。

  • 常用的方法
    (PrintStreamChatTest.java)

方法声明 功能介绍
PrintStream(OutputStream out) 根据参数指定的引用来构造对象
void print(String s) 用于将参数指定的字符串内容打印出来
void println(String x) 用于打印字符串后并终止该行
void flush() 刷新流
void close() 用于关闭输出流并释放有关的资源

PrintWriter类

  • 基本概念
    java.io.PrintWriter类主要用于将对象的格式化形式打印到文本输出流。

  • 常用的方法
    (PrintStreamChatTest.java)

方法声明 功能介绍
PrintWriter(Writer out) 根据参数指定的引用来构造对象
void print(String s) 将参数指定的字符串内容打印出来
void println(String x) 打印字符串后并终止该行
void flush() 刷新流
void close() 关闭流对象并释放有关的资源
  • 案例题目
    不断地提示用户输入要发送的内容,若发送的内容是"bye"则聊天结束,否则将用户输入的内容写入到文件d:/a.txt中。
    要求使用BufferedReader类来读取键盘的输入 System.in代表键盘输入。
    要求使用PrintStream类负责将数据写入文件。

OutputStreamWriter类

  • 基本概念
    java.io.OutputStreamWriter类主要用于实现从字符流到字节流的转换。

  • 常用的方法
    (PrintStreamChatTest.java)

方法声明 功能介绍
OutputStreamWriter(OutputStream out) 根据参数指定的引用来构造对象
OutputStreamWriter(OutputStream out, String charsetName) 根据参数指定的引用和编码构造对象
void write(String str) 将参数指定的字符串写入
void flush() 刷新流
void close() 用于关闭输出流并释放有关的资源

InputStreamReader类

  • 基本概念
    java.io.InputStreamReader类主要用于实现从字节流到字符流的转换。

  • 常用的方法
    (PrintStreamChatTest.java)

方法声明 功能介绍
InputStreamReader(InputStream in) 根据参数指定的引用来构造对象
InputStreamReader(InputStream in, String charsetName) 根据参数指定的引用和编码来构造对象
int read(char[] cbuf) 读取字符数据到参数指定的数组
void close() 用于关闭输出流并释放有关的资源

字符编码

  • 编码表的由来
    计算机只能识别二进制数据,早期就是电信号。为了方便计算机可以识别各个国家的文字,就需要
    将各个国家的文字采用数字编号的方式进行描述并建立对应的关系表,该表就叫做编码表。

  • 常见的编码表
    ASCII:美国标准信息交换码, 使用一个字节的低7位二位进制进行表示。
    ISO8859-1:拉丁码表,欧洲码表,使用一个字节的8位二进制进行表示。
    GB2312:中国的中文编码表,最多使用两个字节16位二进制为进行表示。
    GBK:中国的中文编码表升级,融合了更多的中文文字符号,最多使用两个字节16位二进制位表示。
    Unicode:国际标准码,融合了目前人类使用的所有字符,为每个字符分配唯一的字符码。所有的文字都用两个字节16位二进制位来表示。

  • 编码的发展
    面向传输的众多 UTF(UCS Transfer Format)标准出现了,UTF-8就是每次8个位传输数据,而UTF-16就是每次16个位。这是为传输而设计的编码并使编码无国界,这样就可以显示全世界上所有文化的字符了。
    Unicode只是定义了一个庞大的、全球通用的字符集,并为每个字符规定了唯一确定的编号,具体存储成什么样的字节流,取决于字符编码方案。推荐的Unicode编码是UTF-8和UTF-16。
    UTF-8:变长的编码方式,可用1-4个字节来表示一个字符。
    0 开头:一个字节
    110 开头:两个字节
    1110 开头:三个字节

DataOutputStream类(了解)

  • 基本概念
    java.io.DataOutputStream类主要用于以适当的方式将基本数据类型写入输出流中。

  • 常用的方法
    (DataOutputStreamTest.java)

方法声明 功能介绍
DataOutputStream(OutputStream out) 根据参数指定的引用构造对象 OutputStream类是个抽象类,实参需要传递子类对象
void writeInt(int v) 用于将参数指定的整数一次性写入输出流,优先写入高字节
void close() 用于关闭文件输出流并释放有关的资源

DataInputStream类(了解)

  • 基本概念
    java.io.DataInputStream类主要用于从输入流中读取基本数据类型的数据。

  • 常用的方法
    (DataInputStreamTest.java)

方法声明 功能介绍
DataInputStream(InputStream in) 根据参数指定的引用来构造对象 InputStream类是抽象类,实参需要传递子类对象
int readInt() 用于从输入流中一次性读取一个整数数据并返回
void close() 用于关闭文件输出流并释放有关的资源

ObjectOutputStream类(重点)

  • 基本概念
    java.io.ObjectOutputStream类主要用于将一个对象的所有内容整体写入到输出流中。
    只能将支持 java.io.Serializable 接口的对象写入流中。
    类通过实现 java.io.Serializable 接口以启用其序列化功能。
    所谓序列化主要指将一个对象需要存储的相关信息有效组织成字节序列的转化过程。需要:serialVersionUID

  • 常用的方法
    (User.java
    ObjectOutputStreamTest.java)

方法声明 功能介绍
ObjectOutputStream(OutputStream out) 根据参数指定的引用来构造对象
void writeObject(Object obj) 用于将参数指定的对象整体写入到输出流中
void close() 用于关闭输出流并释放有关的资源

ObjectInputStream类(重点)

  • 基本概念
    java.io.ObjectInputStream类主要用于从输入流中一次性将对象整体读取出来。
    所谓反序列化主要指将有效组织的字节序列恢复为一个对象及相关信息的转化过程。

  • 常用的方法
    (User.java
    ObjectInputStreamTest.java)

方法声明 功能介绍
ObjectInputStream(InputStream in) 根据参数指定的引用来构造对象
Object readObject() 主要用于从输入流中读取一个对象并返回 无法通过返回值来判断是否读取到文件的末尾 (问题:无法判断是否到末尾)
void close() 用于关闭输入流并释放有关的资源
  • 序列化版本号
    序列化机制是通过在运行时判断类的serialVersionUID来验证版本一致性的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID与本地相应实体类的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化,否则就会出现序列化版本不一致的异常(InvalidCastException)。

  • transient关键字
    transient是Java语言的关键字,用来表示一个域不是该对象串行化的一部分。当一个对象被串行化的时候,transient型变量的值不包括在串行化的表示中,然而非transient型的变量是被包括进去的。(User.java)

  • 经验的分享
    当希望将多个对象写入文件时,通常建议将多个对象放入一个集合中,然后将集合这个整体看做一个对象写入输出流中,此时只需要调用一次readObject方法就可以将整个集合的数据读取出来,从而避免了通过返回值进行是否达到文件末尾的判断。

RandomAccessFile类

  • 基本概念
    java.io.RandomAccessFile类主要支持对随机访问文件的读写操作。

  • 常用的方法
    (RandomAccessFileTest.java)

方法声明 功能介绍
RandomAccessFile(String name, String mode) 根据参数指定的名称和模式构造对象
r: 以只读方式打开
w:打开以便读取和写入
rwd:打开以便读取和写入,同步文件内容的更新
rws:打开以便读取和写入,同步文件内容和元数据的更新
int read() 读取单个字节的数据
void seek(long pos) 用于设置从此文件的开头开始测量的文件指针偏移量
void write(int b) 将参数指定的单个字节写入
void close() 用于关闭流并释放有关的资源

5. 总结

  • IO流(重点)
    概念,分类,体系结构,相关类的详解等

Chapter18 多线程

1. 基本概念

程序和进程的概念

  • 程序 - 数据结构 + 算法,主要指存放在硬盘上的可执行文件。
  • 进程 - 主要指运行在内存中的可执行文件。
  • 目前主流的操作系统都支持多进程,为了让操作系统同时可以执行多个任务,但进程是重量级的,也就是新建一个进程会消耗CPU和内存空间等系统资源,因此进程的数量比较局限。

线程的概念

  • 为了解决上述问题就提出线程的概念,线程就是进程内部的程序流,也就是说操作系统内部支持多进程的,而每个进程的内部又是支持多线程的,线程是轻量的,新建线程会共享所在进程的系统资源,因此目前主流的开发都是采用多线程。

  • 多线程是采用时间片轮转法来保证多个线程的并发执行,所谓并发就是指宏观并行微观串行的机
    制。

2. 线程的创建(重中之重)

Thread类的概念

  • java.lang.Thread类代表线程,任何线程对象都是Thread类(子类)的实例。
  • Thread类是线程的模板,封装了复杂的线程开启等操作,封装了操作系统的差异性。

创建方式

  • 方法一:自定义类继承Thread类重写run方法,然后创建该类的对象调用start方法。不推荐,继承Thread无法继承其他类。
    (SubThreadRun.java
     SubThreadRunTest.java)
  • 方法二:自定义类实现Runnable接口并重写run方法,创建该类的对象作为实参来构造Thread类型的对象,然后使用Thread类型的对象调用start方法。推荐,便于维护。
    (SubRunnableRun.java
     SubRunnableRunTest.java
    ThreadNoNameTest.java

相关的方法
(ThreadTest.java)

方法声明 功能介绍
Thread() 使用无参的方式构造对象
由源码可知:Thread类中的成员变量target的数值为null
Thread(String name) 根据参数指定的名称来构造对象
Thread(Runnable target) 根据参数指定的引用来构造对象,其中Runnable是个接口类型
Thread(Runnable target, String name) 根据参数指定引用和名称来构造对象
void run() 若使用Runnable引用构造了线程对象,调用该方法时最终调用接口中的版本
若没有使用Runnable引用构造线程对象,调用该方法时则啥也不做。
由源码可知:由于成员变量的target的数值为null,因此条件if(target!=null)不成立,跳过{}中的代码不执行,而run方法中除了上述代码再无代码,因此证明run方法确实啥也不干
void start() 用于启动线程Java虚拟机会自动调用该线程的run方法
相当于启动了一个线程,加上执行main方法的线程,是两个线程

执行流程

  • 执行main方法的线程叫做主线程,执行run方法的线程叫做新线程/子线程。
  • main方法是程序的入口,对于start方法之前的代码来说,由主线程执行一次,当start方法调用成功后线程的个数由1个变成了2个,新启动的线程去执行run方法的代码,主线程继续向下执行,两个线程各自独立运行互不影响。
  • 当run方法执行完毕后子线程结束,当main方法执行完毕后主线程结束。
  • 两个线程执行没有明确的先后执行次序,由操作系统调度算法来决定。

方式的比较

  • 继承Thread类的方式代码简单,但是若该类继承Thread类后则无法继承其它类,而实现Runnable接口的方式代码复杂,但不影响该类继承其它类以及实现其它接口,因此以后的开发中推荐使用第二种方式。

匿名内部类的方式

  • 使用匿名内部类的方式来创建和启动线程。

3. 线程的生命周期(熟悉)

在这里插入图片描述

  • 新建状态 - 使用new关键字创建之后进入的状态,此时线程并没有开始执行。
  • 就绪状态 - 调用start方法后进入的状态,此时线程还是没有开始执行。
  • 运行状态 - 使用线程调度器调用该线程后进入的状态,此时线程开始执行,当线程的时间片执行完毕后任务没有完成时回到就绪状态。
  • 消亡状态 - 当线程的任务执行完成后进入的状态,此时线程已经终止。
  • 阻塞状态 - 当线程执行的过程中发生了阻塞事件进入的状态,如:sleep方法。
    阻塞状态解除后进入就绪状态。
    (游乐园碰碰车,排队等,玩三分钟,在排队等,玩一分钟接电话,重新排队…)

4. 线程的编号和名称(熟悉)

  • 线程编号: 身份证  不可重复, 唯一标识
  • 线程名称: 姓名  可重复
方法声明 功能介绍
long getId() 获取调用对象所表示线程的编号
String getName() 获取调用对象所表示线程的名称
void setName(String name) 设置/修改线程的名称为参数指定的数值
static Thread currentThread() 获取当前正在执行线程的引用
  • 案例题目
    自定义类继承Thread类并重写run方法,在run方法中先打印当前线程的编号和名称,然后将线程的名称修改为"zhangfei"后再次打印编号和名称。
    要求在main方法中也要打印主线程的编号和名称。
    ( ThreadIdNameTest.java
     RunnableIdNameTest.java)

5. 常用的方法(重点)

(ThreadSleepTest.java
 ThreadPriorityTest.java
 ThreadJoinTest.java
 ThreadDaemonTest.java)

方法声明 功能介绍
static void yield() 当前线程让出处理器(离开Running状态),使当前线程进入Runnable状态等待 (yield:放弃)
static void sleep(times) 使当前线程从 Running 放弃处理器进入Block状态, 休眠times毫秒, 再返回到Runnable如果其他线程打断当前线程的Block(sleep), 就会发生 InterruptedException。
int getPriority() 获取线程的优先级
void setPriority(int newPriority) 修改线程的优先级。优先级越高的线程不一定先执行,但该线程获取到时间片的机会会更多一些
void join() 等待该线程终止(当前正在执行的线程等待调用线程终止)
void join(long millis) 等待参数指定的毫秒数(当前正在执行的线程等待参数指定的毫秒数)
boolean isDaemon() 用于判断是否为守护线程
void setDaemon(boolean on) 用于设置线程为守护线程(必须线程启动之前调该方法)(主线程结束之后子守护线程随之结束即使没有执行完)
  • 案例题目
    编程创建两个线程,线程一负责打印1 ~ 100之间的所有奇数,其中线程二负责打印1 ~ 100之间的所有偶数。
    在main方法启动上述两个线程同时执行,主线程等待两个线程终止。
    (SubThread1.java
     SubThread2.java
     SubThreadTest.java
     SubRunnable1.java
     SubRunnable2.java
     SubRunnableTest.java)

6. 线程同步机制(重点)

基本概念

  • 当多个线程同时访问同一种共享资源时,可能会造成数据的覆盖等不一致性问题,此时就需要对线程之间进行通信和协调,该机制就叫做线程的同步机制
  • 多个线程并发读写同一个临界资源时会发生线程并发安全问题
  • 异步操作:多线程并发的操作,各自独立运行。
  • 同步操作:多线程串行的操作,先后执行的顺序。
    (AccountRunnableTest.java)

解决方案

  • 由程序结果可知:当两个线程同时对同一个账户进行取款时,导致最终的账户余额不合理。
  • 引发原因:线程一执行取款时还没来得及将取款后的余额写入后台,线程二就已经开始取款。
  • 解决方案:让线程一执行完毕取款操作后,再让线程二执行即可,将线程的并发操作改为串行操作。
  • 经验分享:在以后的开发尽量减少串行操作的范围,从而提高效率。
    (AccountRunnableTest.java
     AccountThreadTest.java)

实现方式

  • 在Java语言中使用synchronized关键字来实现同步/对象锁机制从而保证线程执行的原子性(要么执行完,要么不执行,中间不可打断)
    具体方式如下:
  • 使用同步代码块的方式实现部分代码的锁定,格式如下:
    synchronized(类类型的引用) { //new 的方法不可行
      编写所有需要锁定的代码;
    }
    (AccountRunnableTest.java
     AccountThreadTest.java)
  • 使用同步方法的方式实现所有代码的锁定。
    直接使用synchronized关键字来修饰整个方法即可
    该方式等价于:
      synchronized(this) { 整个方法体的代码 }
    (AccountRunnableTest.java
     AccountThreadTest.java)

静态方法的锁定

  • 当我们对一个静态方法加锁,如:
     public synchronized static void xxx(){….}
  • 那么该方法锁的对象是类对象。每个类都有唯一的一个类对象。获取类对象的方式 : 类名.class。
    类名.class : 该类型对应的class对象,由于类型是固定的,所以class对象也是唯一的,因此可以实现同步
  • 静态方法与非静态方法同时使用了synchronized后它们之间是非互斥关系的。
  • 原因在于:静态方法锁的是类对象而非静态方法锁的是当前方法所属对象。

注意事项

  • 使用synchronized保证线程同步应当注意:
    多个需要同步的线程在访问同步块时,看到的应该是同一个锁对象引用。
    在使用同步块时应当尽量减少同步范围以提高并发的执行效率。

线程安全类和不安全类

  • StringBuffer类是线程安全的类,但StringBuilder类不是线程安全的类。
  • Vector类和 Hashtable类是线程安全的类,但ArrayList类和HashMap类不是线程安全的类。
  • Collections.synchronizedList() 和 Collections.synchronizedMap()等方法实现安全。

  • 线程一执行的代码:
    public void run(){
      synchronized(a){ //持有对象锁a,等待对象锁b
       synchronized(b){
       编写锁定的代码;
      }
     }
    }
  • 线程二执行的代码:
    public void run(){
      synchronized(b){ //持有对象锁b,等待对象锁a
        synchronized(a){
          编写锁定的代码;
       }
      }
    }
  • 注意:
    在以后的开发中尽量减少同步的资源,减少同步代码块的嵌套结构的使用!

使用Lock(锁)实现线程同步

  • 基本概念

从Java5开始提供了更强大的线程同步机制—使用显式定义的同步锁对象来实现。

java.util.concurrent.locks.Lock接口是控制多个线程对共享资源进行访问的工具。

该接口的主要实现类是ReentrantLock类,该类拥有与synchronized相同的并发性,在以后的线程安全控制中,经常使用ReentrantLock类显式加锁和释放锁。

  • 常用的方法
方法声明 功能介绍
ReentrantLock() 使用无参方式构造对象
void lock() 获取锁
void unlock() 释放锁
  • 与synchronized方式的比较

Lock是显式锁,需要手动实现开启和关闭操作,而synchronized是隐式锁,执行锁定代码后自动释放。

Lock只有同步代码块方式的锁,而synchronized有同步代码块方式和同步方法两种锁。

使用Lock锁方式时,Java虚拟机将花费较少的时间来调度线程,因此性能更好。

Object类常用的方法

线程和线程之间的交互
(ThreadCommunicateTest.java)

方法声明 功能介绍
void wait() 用于使得线程进入等待状态,直到其它线程调用notify()或notifyAll()方法
void wait(long timeout) 用于进入等待状态,直到其它线程调用方法或参数指定的毫秒数已经过去为止
void notify() 用于唤醒等待的单个线程
void notifyAll() 用于唤醒等待的所有线程

在这里插入图片描述
(StoreHouse.java
 ProduceThread.java
 ConsumerThread.java
 StoreHouseTest.java)

线程池(熟悉)

  • 实现Callable接口

从Java5开始新增加创建线程的第三种方式为实现java.util.concurrent.Callable接口。

常用的方法如下:
(ThreadCallableTest.java)

方法声明 功能介绍
V call() 计算结果并返回
  • FutureTask类

java.util.concurrent.FutureTask类用于描述可取消的异步计算,该类提供了Future接口的基本实现,包括启动和取消计算、查询计算是否完成以及检索计算结果的方法,也可以用于获取方法调用后的返回结果。

常用的方法如下:
(ThreadCallableTest.java)

方法声明 功能介绍
FutureTask(Callable callable) 根据参数指定的引用来创建一个未来任务
V get() 获取call方法计算的结果
  • 线程池的由来

在服务器编程模型的原理,每一个客户端连接用一个单独的线程为之服务,当与客户端的会话结束时,线程也就结束了,即每来一个客户端连接,服务器端就要创建一个新线程。

如果访问服务器的客户端很多,那么服务器要不断地创建和销毁线程,这将严重影响服务器的性能

  • 概念和原理

线程池的概念:首先创建一些线程,它们的集合称为线程池,当服务器接受到一个客户请求后,就从线程池中取出一个空闲的线程为之服务,服务完后不关闭该线程,而是将该线程还回到线程池中。

在线程池的编程模式下,任务是提交给整个线程池,而不是直接交给某个线程,线程池在拿到任务后,它就在内部找有无空闲的线程,再把任务交给内部某个空闲的线程,任务是提交给整个线程池,一个线程同时只能执行一个任务,但可以同时向一个线程池提交多个任务。

  • 相关类和方法

(ThreadPoolTest.java)
从Java5开始提供了线程池的相关类和接口:java.util.concurrent.Executors类和 java.util.concurrent.ExecutorService接口。

其中Executors是个工具类和线程池的工厂类,可以创建并返回不同类型的线程池,常用方法如下:

方法声明 功能介绍
static ExecutorService newCachedThreadPool() 创建一个可根据需要创建新线程的线程池
static ExecutorService newFixedThreadPool(int nThreads) 创建一个可重用固定线程数的线程池
static ExecutorService newSingleThreadExecutor() 创建一个只有一个线程的线程池

其中ExecutorService接口是真正的线程池接口,主要实现类是ThreadPoolExecutor,常用方法如下:

方法声明 功能介绍
void execute(Runnable command) 执行任务和命令,通常用于执行Runnable
Future submit(Callable task) 执行任务和命令,通常用于执行Callable
void shutdown() 启动有序关闭

7. 总结

1.多线程(重点)
概念,创建方式,线程的生命周期,线程的编号和名称,常用的方法,现成的同步,synchronized关键字,线程的通信,生产者消费者模型,线程池等

Chapter19 网络编程

1. 网络编程的常识

  • 目前主流的网络通讯软件有:微信、QQ、飞信、阿里旺旺、陌陌、探探、…

七层网络模型

  • OSI(Open System Interconnect),即开放式系统互联,是ISO(国际标准化组织)组织在1985年研究的网络互连模型。

  • OSI七层模型和TCP/IP五层模型的划分如下:
    在这里插入图片描述

  • 当发送数据时,需要对发送的内容按照上述七层模型进行层层加包后发送出去。

  • 当接收数据时,需要对接收的内容按照上述七层模型相反的次序层层拆包并显示出来。
    在这里插入图片描述

相关的协议(笔试题)

  • 协议的概念

计算机在网络中实现通信就必须有一些约定或者规则,这种约定和规则就叫做通信协议,通信协议
可以对速率、传输代码、代码结构、传输控制步骤、出错控制等制定统一的标准。

  • TCP协议

传输控制协议(Transmission Control Protocol),是一种面向连接的协议,类似于打电话。
 - 建立连接 => 进行通信 => 断开连接
 - 在传输前采用"三次握手"方式。
 - 在通信的整个过程中全程保持连接,形成数据传输通道。
 - 保证了数据传输的可靠性和有序性。
 - 是一种全双工的字节流通信方式,可以进行大数据量的传输。
 - 传输完毕后需要释放已建立的连接,发送数据的效率比较低。
在这里插入图片描述
在这里插入图片描述

  • UDP协议

用户数据报协议(User Datagram Protocol),是一种非面向连接的协议,类似于写信。
 - 在通信的整个过程中不需要保持连接,其实是不需要建立连接。
 - 不保证数据传输的可靠性和有序性。
 - 是一种全双工的数据报通信方式,每个数据报的大小限制在64K内。
 - 发送数据完毕后无需释放资源,开销小,发送数据的效率比较高,速度快。

IP地址(重点)

  • 192.168.1.1 - 是绝大多数路由器的登录地址,主要配置用户名和密码以及Mac过滤。
  • IP地址是互联网中的唯一地址标识,本质上是由32位二进制组成的整数,叫做IPv4,当然也有128位二进制组成的整数,叫做IPv6,目前主流的还是IPv4。
  • 日常生活中采用点分十进制表示法来进行IP地址的描述,将每个字节的二进制转化为一个十进制整数,不同的整数之间采用小数点隔开。
  • 如:
     0x01020304 => 1.2.3.4
  • 查看IP地址的方式:
     Windows系统:在dos窗口中使用ipconfig或ipconfig/all命令即可
     Unix/linux系统:在终端窗口中使用ifconfig或/sbin/ifconfig命令即可
  • 特殊的地址
     本地回环地址(hostAddress):127.0.0.1 主机名(hostName):localhost

端口号(重点)

  • IP地址 - 可以定位到具体某一台设备。
  • 端口号 - 可以定位到该设备中具体某一个进程。
  • 端口号本质上是16位二进制组成的整数,表示范围是:0 ~ 65535,其中0 ~ 1024之间的端口号通常被系统占用,建议编程从1025开始使用。
  • 特殊的端口:
      HTTP:80 FTP:21 Oracle:1521 MySQL:3306 Tomcat:8080
  • 网络编程需要提供:IP地址 + 端口号,组合在一起叫做网络套接字:Socket。

2. 基于tcp协议的编程模型(重点)

C/S架构的简介

  • 在C/S模式下客户向服务器发出服务请求,服务器接收请求后提供服务。
  • 例如:在一个酒店中,顾客找服务员点菜,服务员把点菜单通知厨师,厨师按点菜单做好菜后让服务员端给客户,这就是一种C/S工作方式。如果把酒店看作一个系统,服务员就是客户端,厨师就是服务器。这种系统分工和协同工作的方式就是C/S的工作方式。
  • 客户端部分:为每个用户所专有的,负责执行前台功能。
  • 服务器部分:由多个用户共享的信息与功能,招待后台服务。
    在这里插入图片描述
    在这里插入图片描述

编程模型
(ServerStringTest.java
 ClientStringTest.java
 ServerThread.java)

  • 服务器:
     (1)创建ServerSocket类型的对象并提供端口号;
     (2)等待客户端的连接请求,调用accept()方法;
     (3)使用输入输出流进行通信;
     (4)关闭Socket;

  • 客户端:
     (1)创建Socket类型的对象并提供服务器的IP地址和端口号;
     (2)使用输入输出流进行通信;
     (3)关闭Socket;

相关类和方法的解析

  • ServerSocket类

java.net.ServerSocket类主要用于描述服务器套接字信息(大插排)。

常用的方法如下:

方法声明 功能介绍
ServerSocket(int port) 根据参数指定的端口号来构造对象
Socket accept() 侦听并接收到此套接字的连接请求
void close() 用于关闭套接字
  • Socket类

java.net.Socket类主要用于描述客户端套接字,是两台机器间通信的端点(小插排)。

常用的方法如下:

方法声明 功能介绍
Socket(String host, int port) 根据指定主机名和端口来构造对象
InputStream getInputStream() 用于获取当前套接字的输入流
OutputStream getOutputStream() 用于获取当前套接字的输出流
void close() 用于关闭套接字
  • 注意事项

客户端 Socket 与服务器端 Socket 对应, 都包含输入和输出流。
客户端的socket.getInputStream() 连接于服务器socket.getOutputStream()。
客户端的socket.getOutputStream()连接于服务器socket.getInputStream()

3. 基于udp协议的编程模型(熟悉)

编程模型
(ReceiveTest.java
 SendTest.java)

  • 接收方:
    (1)创建DatagramSocket类型的对象并提供端口号;
    (2)创建DatagramPacket类型的对象并提供缓冲区;
    (3)通过Socket接收数据内容存放到Packet中,调用receive方法;
    (4)关闭Socket;
  • 发送方:
    (1)创建DatagramSocket类型的对象;
    (2)创建DatagramPacket类型的对象并提供接收方的通信地址;
    (3)通过Socket将Packet中的数据内容发送出去,调用send方法;
    (4)关闭Socket;

相关类和方法的解析

  • DatagramSocket类

java.net.DatagramSocket类主要用于描述发送和接收数据报的套接字(邮局)。
换句话说,该类就是包裹投递服务的发送或接收点。

常用的方法如下:

方法声明 功能介绍
DatagramSocket() 使用无参的方式构造对象
DatagramSocket(int port) 根据参数指定的端口号来构造对象
void receive(DatagramPacket p) 用于接收数据报存放到参数指定的位置
void send(DatagramPacket p) 用于将参数指定的数据报发送出去
void close() 关闭Socket并释放相关资源
  • DatagramPacket类

java.net.DatagramPacket类主要用于描述数据报,数据报用来实现无连接包裹投递服务。

常用的方法如下:

方法声明 功能介绍
DatagramPacket(byte[] buf, int length) 根据参数指定的数组来构造对象,用于接收长度为length的数据报
DatagramPacket(byte[] buf, int length, InetAddress address, int port) 根据参数指定数组来构造对象,将数据报发送到指定地址和端口
InetAddress getAddress() 用于获取发送方或接收方的通信地址
int getPort() 用于获取发送方或接收方的端口号
int getLength() 用于获取发送数据或接收数据的长度
  • InetAddress类

java.net.InetAddress类主要用于描述互联网通信地址信息。

常用的方法如下:

方法声明 功能介绍
static InetAddress getLocalHost() 用于获取当前主机的通信地址
static InetAddress getByName(String host) 根据参数指定的主机名获取通信地址

4. URL类(熟悉)

基本概念

  • java.net.URL(Uniform Resource Identifier)类主要用于表示统一的资源定位器,也就是指向万维网上“资源”的指针。这个资源可以是简单的文件或目录,也可以是对复杂对象的引用,例如对数据库或搜索引擎的查询等。
  • 通过URL可以访问万维网上的网络资源,最常见的就是www和ftp站点,浏览器通过解析给定的URL可以在网络上查找相应的资源。
  • URL的基本结构如下:
      <传输协议>://<主机名>:<端口号>/<资源地址>

常用的方法
(URLTest.java)

方法声明 功能介绍
URL(String spec) 根据参数指定的字符串信息构造对象
String getProtocol() 获取协议名称
String getHost() 获取主机名称
int getPort() 获取端口号
String getPath() 获取路径信息
String getFile() 获取文件名
URLConnection openConnection() 获取URLConnection类的实例

URLConnection类

  • 基本概念

java.net.URLConnection类是个抽象类,该类表示应用程序和URL之间的通信链接的所有类的超类,主要实现类有支持HTTP特有功能的HttpURLConnection类。

  • HttpURLConnection类的常用方法
方法声明 功能介绍
InputStream getInputStream() 获取输入流
void disconnect() 断开连接

5. 总结

  • 网络编程
    网络编程的常识,基于tcp协议的编程模型,基于udp协议的编程模型,URL类

Chapter20 反射机制

1. 基本概念

  • 通常情况下编写代码都是固定的,无论运行多少次执行的结果也是固定的,在某些特殊场合中编写代码时不确定要创建什么类型的对象,也不确定要调用什么样的方法,这些都希望通过运行时传递的参数来决定,该机制叫做动态编程技术,也就是反射机制。
  • 通俗来说,反射机制就是用于动态创建对象并且动态调用方法的机制。
  • 目前主流的框架底层都是采用反射机制实现的。
  • 如:
    Person p = new Person(); - 表示声明Person类型的引用指向Person类型的对象
    p.show(); - 表示调用Person类中的成员方法show

2. Class类

基本概念

  • java.lang.Class类的实例可以用于描述Java应用程序中的类和接口,也就是一种数据类型
  • 该类没有公共构造方法,该类的实例由Java虚拟机和类加载器自动构造完成,本质上就是加载到内存中的运行时类

获取Class对象的方式
(ClassTest.java)

  • 使用数据类型.class的方式可以获取对应类型的Class对象(掌握)。
  • 使用引用/对象.getClass()的方式可以获取对应类型的Class对象。
  • 使用包装类.TYPE的方式可以获取对应基本数据类型的Class对象。
  • 使用Class.forName()方法的方式来获取参数指定类型的Class对象(掌握)。
    要求写完整的名称:1. 包名.类名 2. 基本数据类型X
  • 使用类加载器ClassLoader的方式获取指定类型的Class对象。

常用的方法(掌握)
(Person.java
 PersonConstructorTest.java)

方法声明 功能介绍
static Class<?> forName(String className) 用于获取参数指定类型对应的Class对象并返回
T newInstance() 用于创建该Class对象所表示类的新实例
  • 创建对象的类型可以从键盘输入
  • 创建对象的类型可以从配置文件中读取

3. Constructor类

基本概念

  • java.lang.reflect.Constructor类主要用于描述获取到的构造方法信息
    (Person.java
     PersonConstructorTest.java)

Class类的常用方法

方法声明 功能介绍
Constructor getConstructor(Class<?>… parameterTypes) 用于获取此Class对象所表示类型中参数指定的公共构造方法
Constructor<?>[] getConstructors() 用于获取此Class对象所表示类型中所有的公共构造方法

Constructor类的常用方法

方法声明 功能介绍
T newInstance(Object… initargs) 使用此Constructor对象描述的构造方法来构造Class对象代表类型的新实例
int getModifiers() 获取方法的访问修饰符
String getName() 获取方法的名称
Class<?>[] getParameterTypes() 获取方法所有参数的类型
  • getModifiers
    1:public
    2:private

4. Field类

基本概念

  • java.lang.reflect.Field类主要用于描述获取到的单个成员变量信息。
    (PersonFieldTest.java)

Class类的常用方法

方法声明 功能介绍
Field getDeclaredField(String name) 用于获取此Class对象所表示类中参数指定的单个成员变量信息
Field[] getDeclaredFields() 用于获取此Class对象所表示类中所有成员变量信息

Field类的常用方法

方法声明 功能介绍
Object get(Object obj) 获取参数对象obj中此Field对象所表示成员变量的数值
void set(Object obj, Object value) 将参数对象obj中此Field对象表示成员变量的数值修改为参数value的数值
(private 成员变量 无法set,需要这是setAccessible(true) 才可以set)
void setAccessible(boolean flag) 当实参传递true时,则反射对象在使用时应该取消 Java 语言访问检查
int getModifiers() 获取成员变量的访问修饰符
Class<?> getType() 获取成员变量的数据类型
String getName() 获取成员变量的名称

5. Method类

基本概念

  • java.lang.reflect.Method类主要用于描述获取到的单个成员方法信息。
    (PersonMethodTest.java)

Class类的常用方法

方法声明 功能介绍
Method getMethod(String name, Class<?>… parameterTypes) 用于获取该Class对象表示类中名字为name参数为 parameterTypes的指定公共成员方法
Method[] getMethods() 用于获取该Class对象表示类中所有公共成员方法

Method类的常用方法

方法声明 功能介绍
Object invoke(Object obj, Object… args) 使用对象obj来调用此Method对象所表示的成员方法,实参传递args
int getModifiers() 获取方法的访问修饰符
Class<?> getReturnType() 获取方法的返回值类型
String getName() 获取方法的名称
Class<?>[] getParameterTypes() 获取方法所有参数的类型
Class<?>[] getExceptionTypes() 获取方法的异常信息

6. 获取其它结构信息

(Student.java
 MyAnnotation.java
 StudentTest.java)

方法声明 功能介绍
Package getPackage() 获取所在的包信息
Class<? super T> getSuperclass() 获取继承的父类信息
Class<?>[] getInterfaces() 获取实现的所有接口
Annotation[] getAnnotations() 获取注解信息
Type[] getGenericInterfaces() 获取泛型信息

7. 总结

  1. 反射机制
    概念,Class类,获取Class类的对象获取指定的构造方法,获取所有的构造方法,获取指定的成员变量,获取所有成员变量,获取指定的成员方法,获取所有的成员方法,获取其他结构

第一阶段模块四 作业

1. 编程题

基于学生信息管理系统增加以下两个功能:

a. 自定义学号异常类和年龄异常类,并在该成员变量不合理时产生异常对象并抛出。
b. 当系统退出时将 List 集合中所有学生信息写入到文件中,当系统启动时读取文件中所 有学生信息到 List 集合中。

2. 编程题

实现将指定目录中的所有内容删除,包含子目录中的内容都要全部删除。

3. 编程题

使用线程池将一个目录中的所有内容拷贝到另外一个目录中,包含子目录中的内容。

4. 编程题

使用基于 tcp 协议的编程模型实现将 UserMessage 类型对象由客户端发送给服务器;

服 务 器接 收到 对象 后判 断 用户 对象 信息 是否 为 “admin” 和 “123456”, 若 是则 将 UserMessage 对象中的类型改为"success",否则将类型改为"fail"并回发给客户端,客户 端接收到服务器发来的对象后判断并给出登录成功或者失败的提示。

其中 UserMessage 类的特征有:类型(字符串类型) 和 用户对象(User 类型)。

其中 User 类的特征有:用户名、密码(字符串类型)。

如:
 UserMessage tum = new UserMessage(“check”, new User(“admin”, “123456”));

5. 编程题

使用基于 tcp 协议的编程模型实现多人同时在线聊天和传输文件,要求每个客户端将发 送的聊天内容和文件发送到服务器,服务器接收到后转发给当前所有在线的客户端。

第一阶段模块五 Java新特性和项目

Chapter21 常用设计原则和设计模式

1. 常用的设计原则(记住)

软件开发的流程

  • 需求分析文档、概要设计文档、详细设计文档、编码和测试、安装和调试、维护和升级

常用的设计原则

  • 开闭原则(Open Close Principle)
    对扩展开放对修改关闭,为了使程序的扩展性好,易于维护和升级。
    (对测试完的代码,因客户新的要求需要修改代码,直接修改会导致浪费写代码的测试的劳务,这时创建新的类继承已测试完的类,即对扩展开放对修改关闭) (Person.java
    SubPerson.java)
  • 里氏代换原则(Liskov Substitution Principle)
    任何基类(父类)可以出现的地方,子类一定可以出现,多使用多态的方式。
    public static void draw(Rect r) 子类形参
    public static void draw(Circle c) 子类形参
    public static void draw(Shape s) 父类形参 上面两个可以用这个代替,即里氏代换原则,即多态
  • 依赖倒转原则(Dependence Inversion Principle)
    尽量多依赖于抽象类(abstract)或接口(interface)而不是具体实现类,对子类具有强制性和规范性
    (普通类新添加方法,子类无反应,抽象类新添加抽象方法,子类报错需要重写方法,要不然子类也抽象类,即强制性和规范性,普通类管不住子类)
  • 接口隔离原则(Interface Segregation Principle)
    尽量多使用小接口而不是大接口,避免接口的污染,降低类之间耦合度。
    (Animal接口有跑行为飞行为,Dog类实现Animal接口,狗能飞?— 接口污染
    RunAnimal接口有跑行为,FlyAnimal接口有飞行为 — 降低耦合度,接口隔离
    Dog类实现RunAnimal接口,不需要重写飞行为 — 小接口)
    (Animal.java
    Dog.java
    FlyAnimal.java
    RunAnimal.java)
  • 迪[dí]米特法则(最少知道原则)(Demeter Principle)
    一个实体(模块)应当尽量少与其他实体之间发生相互作用,使系统功能模块相对独立。
    高内聚,低耦合。
    (知道的越少越好,Java老师兼容行政,在讲课中去修水龙头修打印机,讲课要停下,高耦合度不好。这个Java老师讲迪米特法则,另外一个老师讲下面的合成服用原则,不太好,说明需要高内聚)
  • 合成复用原则(Composite Reuse Principle)
    尽量多使用合成/聚合的方式,而不是继承的方式。
    (如果我希望在当前类中使用其他类的成员时,我可以把其他类类型的引用声明为该类的成员变量,通过构造方法进行初始化,使用引用点就可以访问所有对象了)
    (生产消费模型,TCP模型)
    (A.java B.java)

2. 常用的设计模式

基本概念

  • 设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结
  • 设计模式就是一种用于固定场合固定套路

基本分类

  • 创建型模式 - 单例设计模式、工厂方法模式、抽象工厂模式、…
    对象的创建
  • 结构型模式 - 装饰器模式、代理模式、…
    结构关系
  • 行为型模式 - 模板设计模式、… (抽象类)
    带来的行为效果

3. 设计模式详解(重点)

单例设计模式

  • 单例设计模式主要分为:饿汉式 和 懒汉式,懒汉式需要对多线程进行同步处理。
    2.声明本类类型的引用指向本类类型的对象并使用 private static 关键字修饰
    1.私有化构造方法,使用private关键字修饰
    3.提供公有的get方法,负责将上述对象返回出去,使用public static 关键字修饰

    饿汉式:第二步直接创建对象,第三步直接返回创建的对象
    懒汉式:第二步 null,第三步只有null时创建并返回对象否则直接返回对象,但有多线程问题,new需要时间还没new完,又要创建对象,此时还是null,就创建了两个对象 — 使用线程同步机制,加关键字synchronized,整个get方法锁起来了,导致每次获取及时已经创建对象了,还要走线程同步机制,锁的意义没了,进行优化
		// 两个 if 都要有
		if(null == sin) {
    
    	//判断是否要走线程同步机制
            synchronized (Singleton.class) {
    
    	// 这里可能有两个申请
                if (null == sin) {
    
    	//判断是否要创建对象,这里只接收一个申请
                    sin = new Singleton();
                }
            }
        }
        return sin;

普通工厂模式

  • 基本概念

普通工厂方法模式就是建立一个工厂类,对实现了同一接口的不同实现类进行实例的创建。

  • 类图结构

一个方框一个类/接口
+ : public
public Sender SendFactory(String type){ }

(code:factory)
在这里插入图片描述

        // 缺点:代码复杂,可读性略差
        // 优点:扩展性和可维护性更强! 尤其是在创建大量对象的前提下
        // 1.声明工厂类类型的引用,指向工厂类类型的对象
        SendFactory sf = new SendFactory();
        // 2.调用生产方法来实现对象的创建
        Sender sender = sf.produce("mail");
        // 3.使用对象调用方法模拟发生的行为
        sender.send();

        System.out.println("------------------------------------------");
        // 优点:代码简单,可读性强      在创建单个对象时有优势
        // 缺点:扩展性和可维护性略差
        Sender sender1 = new MailSender();
        sender1.send();
  • 主要缺点

在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,并且可能出现空指针异常。

多个工厂方法模式

  • 类图结构

普通共创模式中 SendFactory类中的一个方法,改为两个方法(不传参避免空指针异常),一个变多个,多个工厂

(code:factory)
在这里插入图片描述

  • 主要缺点

在多个工厂方法模式中,为了能够正确创建对象,先需要创建工厂类的对象才能调用工厂类中的生产方法。

静态工厂方法模式

  • 类图结构

下划线:静态的含义

(code:factory)
在这里插入图片描述

  • 实际意义

工厂方法模式适合:凡是出现了大量的产品需要创建且具有共同的接口时,可以通过工厂方法模式进行创建。

  • 主要缺点

工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序生产新的产品,就必须对工厂类的代码进行修改,这就违背了开闭原则。

抽象工厂模式

  • 类图结构

两个工厂类各自一个生产方法
实际意义:如果想生产新的产品(除了Mail Sms,上面的方法需要在类里面加代码违背开闭原则)时,更有优势,而且不违背开闭原则

(code:factory)
在这里插入图片描述

装饰器模式

  • 基本概念

装饰器模式就是给一个对象动态的增加一些新功能,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。

  • 类图结构

/- :私有化

(code:source)
在这里插入图片描述

  • 实际意义

可以实现一个类功能的扩展。
可以动态的增加功能,而且还能动态撤销(继承不行)。
缺点:产生过多相似的对象,不易排错。

代理模式

  • 基本概念

(租房子时找中介一样,中介找房子时,不需要我们跟着,他可以代理我们找房子)
代理模式就是找一个代理类替原对象进行一些操作。
比如我们在租房子的时候找中介,再如我们打官司需要请律师,中介和律师在这里就是我们的代理。

  • 类图结构

(code:source)
在这里插入图片描述

  • 实际意义

如果在使用的时候需要对原有的方法进行改进,可以采用一个代理类调用原有方法,并且对产生的结果进行控制,这种方式就是代理模式。
使用代理模式,可以将功能划分的更加清晰,有助于后期维护。

  • 代理模式和装饰器模式的比较

装饰器模式通常的做法是将原始对象作为一个参数传给装饰者的构造器,而代理模式通常在一个代理类中创建一个被代理类的对象。
装饰器模式关注于在一个对象上动态的添加方法,然而代理模式关注于控制对对象的访问。

模板方法模式

  • 基本概念

模板方法模式主要指一个抽象类中封装了一个固定流程,流程中的具体步骤可以由不同子类进行不同的实现,通过抽象类让固定的流程产生不同的结果。

  • 类图结构

斜体 :抽象(类/方法)

在这里插入图片描述

  • 实际意义

将多个子类共有且逻辑基本相同的内容提取出来实现代码复用。
不同的子类实现不同的效果形成多态,有助于后期维护。

4. 总结

  1. 常用的设计原则和设计模式
    软件开发的流程,常用的设计原则,设计模式的概念和分类,常用设计模式的详解

Chapter22 新特性

1. Java8的新特性

  • 之前讲过的
    接口:默认方法 静态方法 私有方法 简化编译运行和一次性完成

Java8的概述

  • Java8是 Java 语言的一个重要版本,该版本于2014年3月发布,是自Java5以来最具革命性的版本,这个版本包含语言、编译器、库、工具和JVM等方面的十多个新特性。

函数式接口

  • 函数式接口主要指只包含一个抽象方法的接口,如:java.lang.Runnable、java.util.Comparator接口等。
  • Java8提供@FunctionalInterface注解来定义函数式接口,若定义的接口不符合函数式的规范便会报错。
  • Java8中增加了java.util.function包,该包包含了常用的函数式接口,具体如下:

(code:functionalInterface)

接口名称 方法声明 功能介绍
Consumer void accept(T t) 根据指定的参数执行操作
Supplier T get() 得到一个返回值
Function<T,R> R apply(T t) 根据指定的参数执行操作并返回
Predicate boolean test(T t) 判断指定的参数是否满足条件

Lambda表达式
(code:functionalInterface)
(code:methodReference)

  • Lambda 表达式是实例化函数式接口的重要方式,使用 Lambda 表达式可以使代码变的更加简洁紧凑。
  • lambda表达式:参数列表、箭头符号->和方法体组成,而方法体中可以是表达式,也可以是语句块。
  • 语法格式:(参数列表) -> { 方法体; }  - 其中()、参数类型(自动类型推断)、{} 以及return关键字 可以省略。

方法引用
(code:methodReference)

  • 方法引用主要指通过方法的名字来指向一个方法而不需要为方法引用提供方法体,该方法的调用交给函数式接口执行。
  • 方法引用使用一对冒号 :: 将类或对象与方法名进行连接,通常使用方式如下:
    对象的非静态方法引用 ObjectName :: MethodName (两个方法保持一致的结构)
    类的静态方法引用 ClassName :: StaticMethodName (两个方法保持一致的结构)
    类的非静态方法引用 ClassName :: MethodName (其中一个参数对象作为调用对象来调用方法时)
    构造器的引用 ClassName :: new (无参Supplier,有参BiFunction)
    数组的引用 TypeName[] :: new (Function)
  • 方法引用是在特定场景下lambda表达式的一种简化表示,可以进一步简化代码的编写使代码更加紧凑简洁,从而减少冗余代码。

Stream接口

  • 案例题目:

准备一个List集合并放入Person类型的对象,将集合中所有成年人过滤出来放到另外一个集合并打印出来。
(code:listPerson)

  • 基本概念

java.util.stream.Stream接口是对集合功能的增强,可以对集合元素进行复杂的查找、过滤、筛选等操作。
Stream接口借助于Lambda 表达式极大的提高编程效率和程序可读性,同时它提供串行和并行两种模式进行汇聚操作,并发模式能够充分利用多核处理器的优势。

  • 使用步骤

创建Stream,通过一个数据源来获取一个流。
转换Stream,每次转换返回一个新的Stream对象。
对Stream进行聚合操作并产生结果。

  • 创建方式

方式一:通过调用集合的默认方法来获取流,如:default Stream stream()
方式二:通过数组工具类中的静态方法来获取流,如:static IntStream stream(int[] array)
方式三:通过Stream接口的静态方法来获取流,如:static Stream of(T… values)
方式四:通过Stream接口的静态方法来获取流,static Stream generate(Supplier<? extends T>s)

  • 中间操作

筛选与切片的常用方法如下:

方法声明 功能介绍
Stream filter(Predicate<? super T> predicate) 返回一个包含匹配元素的流
Stream distinct() 返回不包含重复元素的流
Stream limit(long maxSize) 返回不超过给定元素数量的流
Stream skip(long n) 返回丢弃前n个元素后的流

映射的常用方法如下:

方法声明 功能介绍
Stream map(Function<? super T,? extends R> mapper) 返回每个处理过元素组成的流
Stream flatMap(Function<? super T,? extends Stream<? extends R>> mapper) 返回每个被替换过元素组成的流,并将所有流合成一个流

排序的常用方法如下:

方法声明 功能介绍
Stream sorted() 返回经过自然排序后元素组成的流
Stream sorted(Comparator<? super T> comparator) 返回经过比较器排序后元素组成的流
  • 终止操作

匹配与查找的常用方法如下:

方法声明 功能介绍
Optional findFirst() 返回该流的第一个元素
boolean allMatch(Predicate<? super T> predicate) 返回所有元素是否匹配
boolean noneMatch(Predicate<? super T> predicate) 返回没有元素是否匹配
Optional max(Comparator<? super T> comparator) 根据比较器返回最大元素
Optional min(Comparator<? super T> comparator) 根据比较器返回最小元素
long count() 返回元素的个数
void forEach(Consumer<? super T> action) 对流中每个元素执行操作

规约的常用方法如下:

方法声明 功能介绍
Optional reduce(BinaryOperator accumulator) 返回结合后的元素值

收集的常用方法如下:

方法声明 功能介绍
<R,A> R collect(Collector<? super T,A,R> collector) 使用收集器对元素进行处理

Optional类

  • 案例题目

判断字符串是否为空,若不为空则打印字符串的长度,否则打印0。
(code:optional)

  • 基本概念

java.util.Optional类可以理解为一个简单的容器,其值可能是null或者不是null,代表一个值存在或不存在。(把一个值放入这个容器,通过这个容器,我们可以判断这个值是否空)
该类的引入很好的解决空指针异常,不用显式进行空值检测。

  • 常用的方法
方法声明 功能介绍
static Optional ofNullable(T value) 根据参数指定数值来得到Optional类型的对象(参数指定的值装到容器中)
Optional map(Function<? super T,? extends U> mapper) 根据参数指定规则的结果来得到Optional类型的对象(建立映射关系)
T orElse(T other) 若该值存在就返回,否则返回other的数值。

2. Java9的新特性

Java9的概述

  • Java9发布于2017年9月发布,带来了很多新特性,其中最主要的变化是模块化系统
  • 模块就是代码和数据的封装体,模块的代码被组织成多个包,每个包中包含Java类和接口,模块的数据则包括资源文件和其他静态信息。
    (模块里面多个包)

模块化的使用

  • 语法格式

在 module-info.java 文件中,我们可以用新的关键词module来声明一个模块,具体如下:
module 模块名称 {
}
(code:
java9-01 / Person.java / java9-01.iml( module java9)
java9-02 / PersonTest.java / java9-02.iml( module java92)
)

  • 模块化的优势

-减少内存的开销。
-可简化各种类库和大型应用的 开发和维护。
-安全性,可维护性,提高性能。

钻石操作符的使用升级

  • 在Java9中允许在匿名内部类的使用中使用钻石操作符。
    <> 一对尖括号叫做砖石操作符
    (code:diamond)

集合工厂方法

  • 基本概念

- Java9的List、Set和Map集合中增加了静态工厂方法of实现不可变实例的创建。
- 不可变体现在无法添加、修改和删除它们的元素。
- 不允许添加null元素对象。
(code:collection)

  • 实际意义

- 保证线程安全:在并发程序中既保证线程安全性,也大大增强了并发时的效率。
- 被不可信的类库使用时会很安全。
- 如果一个对象不需要支持修改操作,将会节省空间和时间的开销。
- 可以当作一个常量来对待,并且这个对象在以后也不会被改变。

InputStream的增强

  • InputStream类中提供了transferTo方法实现将数据直接传输到OutputStream中。
    (inputStream)

3. Java10的新特性

Java10的概述

  • Java10于2018年3月发布,改进的关键点包括一个本地类型推断、一个垃圾回收的增强。
  • Java10计划只是一个短期版本,因此公开更新将在六个月内结束,9月份发布的Java11将是Java的长期支持(LTS)版本,LTS版本的发布每三年发布一次。

局部变量类型推断

  • 基本概念

- Java10可以使用var作为局部变量类型推断标识符,此符号仅适用于局部变量,增强for循环的索引,以及传统for循环的本地变量。
(由初始值可以判断出变量的类型,因此可以使用var取代)

- 它不能使用于方法形式参数,构造函数形式参数,方法返回类型,字段,catch形式参数或任何其他类型的变量声明。
(code:var)

  • 实际意义

- 标识符var不是关键字,只是一个保留的类型名称。这意味着var用作变量,方法名或包名的代码不会受到影响,但var不能作为类或则接口的名字。
- 避免了信息冗余。
- 对齐了变量名。
- 更容易阅读。

4. Java11的新特性

Java11的概述

  • Java11于2018年9月正式发布,这是 Java 大版本周期变化 后的第一个长期支持版本,非常值得关注。

简化的编译运行操作

  • 在Java11中可以使用java命令一次性进行编译和运行操作。
  • 执行源文件中的第一个类必须包含主方法。
  • 不可以使用其它源文件中自定义的类。

String类新增方法

方法声明 功能介绍
boolean isBlank() 判断字符串是否为空或只包含空白代码点
Optional map(Function<? super T,? extends U> mapper) 根据参数指定规则的结果来得到Optional类型的对象
T orElse(T other) 若该值存在就返回,否则返回other的数值。

5. 总结

1.新特性
java8:函数型接口,lambda表达式,方法引用,Stream流,Optional类,
java9:模块化系统,砖石操作符的增强,集合的工厂方法,InputStream类的增强
java10:局部变量的类型推断
java11:简化的编译运行,String类新增的方法等

Chapter23 在线考试系统

1. 在线考试系统

软件开发的流程

  • 需求分析文档、概要设计文档、详细设计文档、编码和测试、安装和调试、维护和升级

软件的需求分析

  • 在线考试系统的主要功能分析如下:
    在这里插入图片描述

  • 学员系统
    用户模块:登录、修改密码、退出
    考试模块:开始考试、查询成绩、导出成绩(选)

  • 管理员系统
    学员管理模块:增加学员、删除学员、修改学员、查找学员
    考题管理模块:增加考题、删除考题、修改考题、查找考题、导入考题(选)

软件的概要设计

  • 在线考试系统采用C(Client客户端)/S(Server服务器)架构进行设计,具体如下:
    客户端(Client) - 主要用于提供字符界面供用户选择并将处理结果显示出来。
    服务器(Server) - 主要用于针对字符界面的选择实现真正业务功能的处理。
    数据库(Database) - 主要用于进行数据的存取。
    C/S : C就如微信要安装微信(客户端)S就是Server(服务器)
    B/S : B就如京东淘宝(浏览器)S(服务器)给我一个浏览器就能和服务器通信
    在这里插入图片描述
    软件的详细设计

  • 客户端和服务器之间采用基于tcp协议的编程模型进行通信。
    客户端的对象输出流连接服务器的对象输入流。
    服务器的对象输出流连接客户端的对象输入流。

  • 客户端采用消息的类型作为具体业务的代表,伴随着账户信息等一并发送给服务器。
    当客户端发来的消息类型为"managerCheck"时,则表示要实现管理员账户信息的校验功能。
    当客户端发来的消息类型为"userCheck"时,则表示要实现学员账户信息的校验功能。

  • 服务器采用消息的类型作为是否校验成功的标志发送给客户端。
    当客户端收到的消息类型为"success"时,则表示账户信息正确。
    当客户端收到的消息类型为"fail"时,则表示账户信息错误。

软件的编码流程

  • 管理员登录功能
    编写基于tcp协议的服务器端,也就是初始化服务器;
    编写基于tcp协议的客户端,来连接服务器;
    编写客户端的字符界面并提示客户进行业务的选择;
    将客户的选择和输入的相关信息通过对象输出流发送给服务器;
    服务器通过对象输入流接收客户端发来的消息并进行功能处理,将处理结果发送给客户端;
    客户端通过对象输入流接收服务器的处理结果并给出提示;

  • 学员管理系统的功能
    当项目启动时,将文件中的所有学员账户信息全部读取出来放到一个List集合中。
    客户端输入要增加学员的用户名和密码信息,通过对象输出流发送给服务器。
    服务器接收客户端发来的消息,判断集合中是否存在该学员账户信息并实现具体添加功能。
    服务器将增加学员功能的处理结果发送给客户端,客户端给出对应的提示。
    当项目退出时,将集合中的所有学员账户信息整体写入到文件中

知识点

  • Dao
    涉及数据访问

第一阶段模块五作业

  1. 编程题
    按照《在线考试系统》的需求分析继续实现剩余的功能。
    要求1: 实现功能效果即可,有余力的小伙伴再进行优化处理。
    要求2:服务端对客户端的请求以及响应内容进行打印,
    如:
    “服务端收到客户端A的”
    管理员登录
    “请求,请求数据为”
    XXX
    “,调用”
    XXX
    “方法,响应结果为:{“result”,“success”}“

猜你喜欢

转载自blog.csdn.net/kimyundung/article/details/109920524
今日推荐