java学习笔记


 1.计算机的常识:

   计算机之父 -- 冯.诺依曼  
   计算机最大的奖项  -- 图灵奖,没有诺贝尔奖

  Java之父 -- 詹姆斯.高斯林
   Java1.8 / 8.0 
     计算机是由硬件和软件组成。硬件就是各种计算机的设备,软件是控制设备的代码。常见的计算机硬件包括: CPU(中央处理器)、内存、硬盘、主板、输入输出设备(键盘、鼠标、显示器)、机箱和电源等。CPU主要负责各种运算,是计算机的大脑;内存和硬盘都是存储设备,数据要从内存/硬盘中存取。主板是连接各种设备的,各种设备都需要接入主板。硬件曾经是计算机的绝对主流,硬件公司包括:英特尔、IBM早期等。硬件的价格非常的透明,全球化,因此硬件的赚钱很难。软件包括:系统软件和应用软件。
   系统软件就是操作系统,应用软件就是除了操作系统以外的软件。操作系统包括:Windows系统(Win30/Win95/Win98/Windows2000/Win XP/Server2003
/Vista/Win7/Win8/Win10)、Unix系统(从70年开始,到今天)、类Unix系统(Linux)、其它系统,包括手机的安卓也是Linux系统之一。手机的操作系统:塞班、IOS、安卓、Windows phone等。应用软件就是其它的软件,比如:photoshop、word、excel等。我们程序员就是做软件开发的。

  2.Java分为三个版本:
   JavaSE   -- Java标准版,Java核心的类库和基础环境都需要JAVASE
   JavaEE   -- Java企业版,Java开发的主流。
   JavaME   -- Java微缩版,目前被安卓替代。

  计算机由软件和硬件组成,其中,硬件就是各种设备,包括:CPU(中央处理器)、内存、硬盘、主板、输入输出设备(键盘/鼠标/显示器)、机箱和电源等。软件包括:系统软件和应用软件。系统软件就是操作系统,应用软件就是其它软件的统称。操作系统分为:内核和外壳Shell。
  主流的操作系统:  Windows系列、Unix系列、类Unix(Linux)。
  手机的操作系统:  塞班、安卓、IOS、Windows Phone。

  3.Java的技术术语:
   JDK  -- Java开发工具包,Java开发必需下载安装jdk。
   JRE  -- Java运行环境,安装JDK后就可以有运行环境(需要配置环境变量)。
   JVM  -- Java虚拟机,Java的程序必须运行在Java虚拟机中。安装JDK后即可。
   API  -- 应用程序接口,Java的类库的说明文档。(查手册,写代码)
   IDE  -- 集成开发环境,就是大型的开发工具。

 4. 程序的必备硬件:
    CPU必须有,因为所有的运算都是由CPU完成,代码由CPU执行。
    内存必须有,因为CPU运算的数据只能来自于内存(CPU内部的寄存器只能存少量的临时数据)。 
    硬盘不是必须的,但一般都会有。CPU只能直接访问内存中的数据,硬盘中的数据是不能直接访问的;需要导入内存中才能被使用。内存的容量较少,而硬盘的容量非常大;因此大规模的数据必须放入硬盘。通常意义的内存中的数据关机后会消失,不是永久保存的;硬盘中的数据可以永久保存。
    内存中的数据以变量的形式存取;硬盘中的数据以文件的形式存取。

 5. Java编程的步骤:
   5.1 准备环境。
    5.1.1 下载安装JDK,注意版本/操作系统/32位或64位系统都需要对应(绿色版也可以)。
    5.1.2 配置环境变量。有些操作系统可以自动配置,但大多数还是需要配置。需要配置Path和CLASSPATH。

    Path就是系统路径,默认情况下,命令都是需要带着目录一起才能被执行的;放入Path的目录下的命令可以去掉目录直接执行。
    CLASSPATH就是类的路径,指明类在哪里。一般配置 . 就可以了。点代表当前目录。
    右键点击 计算机或我的电脑,选 属性,点 高级系统设置或高级,点 环境变量 按钮。
    在系统变量中 查找Path,然后双击Path或点 编辑 ,然后在变量值的最前面加上JDK安装目录的bin目录,我的是:C:\Program Files\Java\jdk1.7.0_09\bin; 然后用分号隔开。注意不要删除原来的值,然后一路确定就可以了。
    CLASSPATH直接点新建,然后在变量名的位置敲CLASSPATH,在变量值的位置写一个 . 即可。
    证明方式:启动DOS窗口(视窗键+R后敲cmd回车),输入javac即可。

   5.2 写代码,编译代码,运行代码。
    如果使用记事本,需要去掉文件夹和搜索选项中的查看,去掉其中 隐藏已知文件类型的扩展名的勾选,否则只能建文本文件.txt。
   5. 2.1 右键点新建 选文本文档,修改文件名为: xxx.java  (Hello.java) 弹出确认窗口选是。
   5. 2.2 用记事本打开Hello.java,然后写以下的代码:

     public class Hello{
         public static void main(String[] args){
             System.out.println("Hello Java");
         }
     }
     保存退出后,源代码完成了。
    5.2.3 编译并运行代码。
     cd  源文件所在的目录   (如果不在一个盘,先用E:  D: 切换盘符)
     javac Hello.java      (编译,并生成字节码文件 .class)
     java  Hello           (运行)
    注: Java语言区分大小写。  
        main()方式是Java程序的主方法,Java程序只会执行main()。 
  JAVA语言可以实现跨平台,跨平台就是同样的class文件,Windows和Linux都可以识别。跨平台依赖JVM,不同的操作系统有不同的JVM,然后JVM负责把class解释成不同操作系统能识别的机器指令。

   6.常见快捷键:
    ctrl+C  -- 复制文件/文本    还可以中止一些程序,比如死循环。
    ctrl+V  -- 粘贴文件/文本
    ctrl+A  -- 全选文件/文本
    ctrl+S  -- 保存文件
    ctrl+X  -- 剪切文件/文本
    ctrl+Z  -- 撤销一步(部分软件可以多步撤销)
    ctrl+F  -- 查找
    ctrl+O  -- 打开文件
    ctrl+P  -- 打印文件
    视窗+R  -- 运行窗口
    视窗+E  -- 资源管理器
    视窗+L  -- 锁定屏幕
    视窗+D  -- 回到桌面
    alt+F4  -- 关闭
    alt+tab -- 切换窗口

7.变量和注释(重点)
7.1 基本概念
  计算机的主要硬件:内存、硬盘等。
  变量本质上就是指系统为程序分配的一块存储单元,而且该存储单元中的数据是可变的
  根据存储数据内容的不同,使用数据类型加以描述,为了后续访问该内存空间方便,则需要给该内存区域指定一个名字,叫做变量名。

7.2 声明方式
  数据类型 变量名 [= 初始值];  - []括起来的内容表示可以省略。
                               - 其中;不可以省略的,使用;表示这条语句结束。
如:
  int     age    =   18;  - 推荐该方式,使用0替代之。
   |       |          |
数据类型  变量名    初始值
  int age;

7.3 注意事项
  (1)使用变量之前必须要声明,也就是指定变量的数据类型。
  (2)使用变量之前必须要初始化,也就是指定变量的初始值。   
  (3)每个变量只能声明一次,并且拥有自己独立的作用域和生命周期。

扩展:
  在方法体中声明的变量叫做局部变量,该变量的作用域和生命周期就是从声明开始,一直到方法体结束为止。

7.4 标识符(变量名)的命名规则
  (1)必须由字母、数字、下划线以及美元$组成,其中数字不能开头。
     如:a-z A - Z 0 - 9  _  $   age  age2 
  (2)区分大小写,也就是说大写字母和小写字母代表不同的标识符。
     如:monday Monday 代表不同的标识符 
  (3)不能是java语言中关键字/保留字,如:public class static等。
  (4)长度没有明确的规定,但不宜过长。
  (5)可以是汉字,但不推荐使用。
  (6)尽量做到见名知意。

扩展:
  标识符不仅可以给变量命名,还可以给类/属性/方法/包进行命名。

7.5 注释
  在java语言中主要有以下三种形式的注释:
      //     表示单行注释,也就是从//开始一直到这行结束,所有内容都是注释。
      /* */  表示多行注释,也就是从/*开始一直到*/结束,中间的内容都是注释。
      /** */ 表示多行注释,主要用于使用工具进行提取(了解)。

注意:
  其中/**/表示的多行注释是不允许嵌套的。

8.数据类型
8.1 基本概念
  在java语言中数据类型主要分为两大类:基本数据类型 和 引用数据类型。
  其中基本数据类型主要有(8种):
      byte/short/int/long - 用于描述整数数据的,如:66。
      float/double        - 用于描述小数数据的,如:3.14。
      boolean             - 用于描述真假信息的,如:是否成年。
      char                - 用于描述字符信息的,如:'a'。
  其中引用数据类型主要有:
      数组、类、接口、枚举等。

要求大家掌握的类型:
   int、double、boolean。

8.2 常用的进制
   目前主流的进制有:十进制、二进制、八进制以及十六进制。
   其中十进制表示逢十进1,表示十进制的数字范围是:0 ~ 9,而每个数字对应的权重都是10的次方,从右向左依次为:10^0、10^1、10^2、... ...
   其中二进制表示逢二进1,表示二进制的数字范围是:0 ~ 1,而每个数字对应的权重都是2的次方,从右向左依次为:2^0、2^1、2^2、... ...
   其中八进制表示逢八进1,表示八进制的数字范围是:0 ~ 7,而每个数字对应的权重都是8的次方,从右向左依次为:8^0、8^1、8^2、... ...
   其中十六进制表示逢十六进1,表示十六进制的数字范围是:0 ~ 9 a ~ f,而每个数字对应的权重都是16的次方,从右向左依次为:16^0、16^1、16^2、... ...

   在计算机的底层只识别二进制,而数据有正负数之分,因此二进制中的最高位(最左边)用于表示符号位,其中0作为符号位表示非负数,其中1作为符号位表示负数。

8.3 进制之间的转换
(1)十进制和二进制之间的转换
   a.正十进制转换为二进制的方式
     1)除2取余法,让十进制整数不断地除以2取出余数并记录,当商为0时停止运算,将
            所有的余数反向排列(从下到上)。
     2)拆分法,将十进制整数拆分为多个二进制权重的和,对于出现的权重下面写上1, 
            对于没有出现的权重下面写上0即可(重点)。
如:
   45  =>  0010 1101   
   45  =>  32 + 8 + 4 + 1 
   128 64 32 16 8 4 2 1  
    0  0  1  0  1 1 0 1   => 0010 1101   

   b.正二进制转换为十进制的方式
     1)加权法,让二进制的每一位数字乘以当前位的权重,然后累加起来即可(重点)。
如:
   0010 1101 => 1*2^0 + 0*2^1 + 1*2^2 + 1*2^3 + 0*2^4 + 1*2^5 + 0*2^6 + 0*2^7
             => 1 + 0 + 4 + 8 + 0 + 32 + 0 + 0
             => 45 

   c.负十进制转换为二进制的方式
     1)将负十进制的绝对值拆分为二进制,按位取反再加1(重点)。
如:
   -45的绝对值拆分为二进制:0010 1101  
                  按位取反:1101 0010
                     再加1:1101 0011  

    1101 0010
 +          1 
---------------------
    1101 0011

    45:0010 1101   
   -45:1101 0011 +
---------------------
     1 0000  0000  最高位1就会溢出,通俗来说就是丢失了,8个0的结果是0.

    -1转换为二进制:1111 1111

   d.负二进制转换为十进制的方式
     1)按位取反再加1,然后合并成十进制整数,最后添加负号(重点)。
如:    
   1101 0011 进行按位取反:0010 1100
                    再加1:0010 1101
             转换为十进制:45 
                 添加负号:-45 

练习:
   35和68转换为二进制
     35 => 0010 0011
     68 => 0100 0100

   -35和-68转换为二进制
     -35 => 1101 1101
     -68 => 1011 1100
     
   0101 1101转换为十进制(正) => 93
   0010 1110转换为十进制(正) => 46
   1010 1110转换为十进制(负) => -82
   1101 0101转换为十进制(负) => -43

(2)二进制和八进制之间的转换(了解)
   a.二进制转换为八进制的方式
     1)将每3位二进制合并为一位八进制,前面加0即可。
如:
   000 = 0  
   111 = 7
   0101 0011 => 01 010 011 => 0123

   b.八进制转换为二进制的方式
     1)将每一位八进制拆分为3位二进制即可。
如:
   073 => 111 011 => 11 1011

(3)二进制和十六进制之间的转换(了解)
   a.二进制转换为十六进制的方式
     1)将每4位二进制合并为1位十六进制,前面加0x即可。
如:
   0000 = 0
   1111 = 15

   0101 0011 => 0x53
   
   b.十六进制转换为二进制的方式
     1)将每1位十六进制拆分为4位二进制组成即可。
如:
   0xa5 => 1010 0101

科普:
   1Tb = 1024Gb
   1Gb = 1024Mb
   1Mb = 1024Kb
   1Kb = 1024byte(字节)
   1byte = 8bit(二进制位)

8.4 单个字节(8位二进制位)表示的范围(重中之重)
   在计算机的底层都是二进制形式的,使用符号位1代表负数,使用符号位0代表非负数,那么单个字节的表示范围如下:
   非负数的表示范围是:0000 0000 ~ 0111 1111 => 0 ~ 127 => 0 ~ 2^7-1
      0000 0000转换为十进制是:0
      0111 1111转换为十进制是:127
   负数的表示范围是:1000 0000 ~ 1111 1111  => -128 ~ -1 => -2^7 ~ -2^0
      1000 0000转换为十进制是:-128
      1111 1111转换为十进制是:-1

综上所述:
   对于单个字节来说,所表示的十进制范围是:-128 ~ 127。 

9.数据类型
9.1 数据类型的分类
  在java语言中数据类型主要分为两大类:基本数据类型 和 引用数据类型。
  其中基本数据类型主要有(8种):
      byte/short/int/long  - 用于描述整数数据的,如:66。
      float/double         - 用于描述小数数据的,如:3.14。
      boolean              - 用于描述真假信息的,如:是否成年。
      char                 - 用于描述单个字符的,如:'a'。
  其中引用数据类型主要有:
      数组、类、接口、枚举等。

掌握的类型:
   int、double、boolean。

9.2 整数类型(重点)
   在java中用于描述整数的关键字主要有:byte、short、int、long,推荐首选int类型
   其中byte类型在内存空间中占1个字节(8位),表示的范围是:-128 ~ 127。
                                                         -2^7 ~ 2^7-1。
   其中short类型在内存空间中占2个字节(16位),表示的范围是:-32768 ~ 32767 
                                                         -2^15 ~ 2^15-1
   其中int类型在内存空间中占4个字节(32位),表示的范围是:-2^31 ~ 2^31-1
                                                         (正负二十一亿之间)
   其中long类型在内存空间中占8个字节(64位),表示的范围是:-2^63 ~ 2^63-1
                                                         (比int还大的数)    
   在程序中直接写出的整数数据,叫做直接量/常量/字面值,如:66,默认int类型。
   若希望描述long类型的直接量,则需要在直接量的后面加上l/L,推荐使用L。

扩展:
   若long类型表示的范围还不足以描述时,可以使用java.math.BigInteger类型。

笔试题:
   以下两种写法有区别吗?结果如何?
   byte b1 = 100;  // ok

   int i1 = 100;   // ok
   byte b1 = i1;   // error

9.3 浮点类型(重点)
   在java中用于描述小数数据的关键字有:float和double,推荐首选double类型。
   其中float类型在内存空间中占4个字节,属于单精度浮点数。  
   其中double类型在内存空间中占8个字节,属于双精度浮点数,比float精度更高。
    
   默认的浮点数字面值为double类型,若希望表示float类型,则在字面值后面增加f/F 
 
注意:
   浮点数是不能进行精确计算的,若希望精确计算则使用java.math.BigDecimal类型。

9.4 布尔类型(重点)
   在java中用于描述真假信息的关键字有:boolean。
   该类型变量的数值只有两种:true(真) 和 false(假)。
   该类型本质上使用一个二进制位足够表示了,但通常认为是1个字节。

9.5 字符类型(熟悉)    
   在java中用于描述字符类型数据的关键字有:char,如:'a' '1' '中'等。
   其中char类型在内存空间中占2个字节(16位二进制)。
   字符类型的数据通常都是使用一对单引号括起来的单个字符,若出现多个字符则叫做字符串,使用String类型加以描述。
   
   为了使得单引号的字符在计算机中能够使用二进制进行表示,通常将该字符对应的编号(ASCII)保存在计算机中(要求背下来)。
   'A' 'B' - 65 66 ... ...
   'a' 'b' - 97 98 ... ...
   '0' '1' - 48 49 ... ...
   换行符  - 10
   空格    - 32  

   常用的转义字符有(要求背下来):
       \n  - 换行符,相当于换行的效果。
       \t  - 制表符,相当于按下tab键的效果。
       \\  - 显示一个\
       \"  - 显示"
       \'  - 显示'

扩展:
  实现字符串向整数类型的转换。
  "12345" => 12345
      '1' - '0'  = 1;  
      '2' - '0'  = 2;  1*10 + 2 = 12;
      '3' - '0'  = 3;  12*10 + 3 = 123;
      '4' - '0'  = 4;  123*10 + 4 = 1234;
      '5' - '0'  = 5;  1234*10 + 5 = 12345;

9.6 基本数据类型之间的转换(重点)
  在java语言中基本数据类型之间转换主要有两种形式:自动类型类型 和 强制类型转换
  其中自动类型转换主要指从小范围到大范围之间的转换。  
  其中强制类型转换主要指从大范围到小范围之间的转换。
  
  在java中自动类型转换的规则是:
     byte => short => int => long => float => double
             char  => int
  boolean类型不参与任何类型转换。
  
  强制类型转换的语法格式是:
      目标类型 目标类型变量名 = (目标类型)源类型变量名;
      如:
         byte b1 = (byte)s1;

经验:
   强制类型转换可能会造成数据的丢失,建议能不用则尽量不用强制类型转换。

10.运算符
10.1 算数运算符(重点)

  + 表示加法运算   - 表示减法运算
  * 表示乘法运算   / 表示除法运算符
  % 表示取余(取模)运算

注意:
   a.当两个整数相除时,商只取整数部分,若希望有小数部分,则需要使用浮点数参与
      int => double 发生自动类型转换
   b.0不能做除数,0.0可以做除数,当0作为除数时会产生算数异常,当0.0作为除数
     时结果是无穷大。

10.2 关系/比较运算符(重点)
   > 表示是否大于    >= 表示是否大于等于   
   < 表示是否小于    <= 表示是否小于等于
   == 表示是否等于   != 表示是否不等于
   
   关系运算符的结果一定是boolean类型,只有两个值:true 和 false。 

10.3 自增减运算符(重点)
   + 表示加法运算      ++ 表示自增运算
   - 表示减法运算      -- 表示自减运算
如:
   int ia = 10;
   ia + 1 => 表达式的结果是11,ia的数值是10。 
   ++ia   <=> ia = ia + 1; 表达式的结果是11,ia的数值是11。      
   
   ++ia 表示先++再参与其他运算。
   ia++ 表示先参与其他运算再++。
   --同上。

总结:
   前++和后++若写成独立的语句,不参与其他运算,则效果是等价的(推荐)。
   前++和后++若与其他运算写在一个表达式中,则遵循上述原则。

11.运算符
11.1 算数运算符

   + - * / %
11.2 比较/关系运算符
   > >= < <= == !=
11.3 自增减运算符
   ++  --

   ++ia; 先++再参与其他运算  
   ia++; 先参与其他运算再++

注意:
   推荐单独使用++/--运算,尽量不要与其他运算符一起使用。      

11.4 逻辑运算符(重点)
   && - 逻辑与运算符,相当于“并且”,两侧的操作数都是结果为boolean的表达式。
      - 同真为真,一假为假。
   || - 逻辑或运算符,相当于“或者”,两侧的操作数都是结果为boolean的表达式。
      - 一真为真,同假为假。
   !  - 逻辑非运算符,相当于"非",只有一个右侧的操作数,并且是结果为boolean的
      - 真为假,假为真。
   
   逻辑运算符的操作数都是boolean表达式,该运算符的结果也是boolean类型的。

练习:
   提示用户输入一个正整数,判断该正整数是否为三位数并直接打印表达式的结果。
      >=100 && <=999  
   
短路特性:
   a.对于逻辑与来说,当第一个条件表达式为假时则整个表达式一定为假,此时可以
     省略对第二个条件表达式的判断。
   b.对于逻辑或来说,当第一个条件表达式为真时则整个表达式一定为真,此时可以
     省略对第二个条件表达式的判断。

11.5 条件/三元/三目运算符(重点)
   ?: - 三目运算符
   
   条件表达式?表达式1:表达式2  
   判断条件表达式是否成立,若成立则直接执行表达式1;若不成立则直接执行表达式2

练习:
   提示用户输入一个整数,使用三目运算符判断该整数是负数还是非负数?
   
11.6 赋值运算符(重点)
(1)简单赋值
   = 赋值运算符,用于将=右边的数值/结果存放到=左边变量对应的内存空间中(右结合)
如:
   int num;
   num = 10;
(2)复合赋值(了解)
   += -= *= /= %= ... ...
如:
   num = num + 1; //可读性更强,推荐使用 
   num += 1; //与上述代码的结果一样的。

笔试题:
   ia = 0; 0 = ia; ia == 0; 0 == ia 分别表达什么意思???
解析:
   ia = 0; //ok 将数值0赋值给变量ia,也就是放到ia对应的内存空间中。
   0 = ia; //error 编译直接报错,0是个直接量/常量/字面值。
   ia == 0; //判断ia是否等于0,结果是boolean类型的
   0 == ia; //判断0是否等于ia,结果是boolean类型的

笔试题:
   byte ib = 10; 
   ib = ib + 2; 和 ib += 2 之间有区别吗?
解析:
   ib += 2; 编译运行都是正确的,真正等价的是 ib = (byte)(ib + 2); 
   ib = ib + 2; 编译报错,需要进行强制类型转换 ib + 2的结果是 int类型的。  

11.7 字符串连接/拼接符(重点)
   + 字符串连接符

11.8 移位运算符(了解)
  << 左移运算符,表示将二进制位向左移动,右边填0。
  >> 右移运算符,表示将二进制位向右移动,左边填符号位。
  >>> 无符号右移运算符,表示将二进制位向右移动,左边填0。

11.9 位运算符(了解)
  & 按位与运算符,同1为1,一0为0。
  | 按位或运算符,一1为1,同0为0。
  ~ 按位取反运算符,0为1, 1为0。
  ^ 按位异或运算符,相同为0,不同为1。

12.分支结构(重中之重)
12.1 基本概念
  分支结构就是指根据条件表达式进行判断,从而选择满足条件的分支进行执行的结构,也就是说若条件满足则执行该分支,若条件不满足则跳过该分支。

12.2 if条件分支
(1)语法格式
   if(条件表达式){
      语句块1; => 本质上就是多条语句的集合。
   } 
   语句块2;

(2)执行流程
   判断条件表达式是否成立
       若成立 => 则执行语句块1 => 执行语句块2;
       若不成立 => 执行语句块2;

12.3 if-else分支结构 
(1)语法格式
   if(条件表达式){
      语句块1;
   }
   else{
      语句块2;
   }
   语句块3;

(2)执行流程
   判断条件表达式是否成立
       若成立 => 执行语句块1 => 语句块3;
       若不成立 => 执行语句块2 => 语句块3;

12.4 if-else if-else分支结构
(1)语法格式
   if(条件表达式1){
      语句块1;
   }
   else if(条件表达式2){
      语句块2;
   }
   ... ...
   else{
      语句块3;
   }
   语句块4;

(2)执行流程        
   判断条件表达式1是否成立
     若成立 => 执行语句块1 => 执行语句块4;
     若不成立 => 判断条件表达式2是否成立
         若成立 => 执行语句块2 => 执行语句块4;
         若不成立 => 执行语句块3 => 执行语句块4;

练习:
   提示用户输入考试的成绩,对成绩进行分类打印:
      [90 ~ 100]  - 打印等级A
      [80 ~ 90)   - 打印等级B   
      [70 ~ 80)   - 打印等级C   
      [60 ~ 70)   - 打印等级D   
      [0 ~ 60)    - 打印等级E   

12.5 switch-case分支结构(熟悉)
(1)语法格式
   switch(变量/表达式){
      case 字面值1:语句块1;break;
      case 字面值2:语句块2;break;
      ... ...
      default:语句块3;
   }   
   语句块4;

(2)执行流程
   计算变量/表达式的结果  => 判断是否与字面值1相等
       若相等 => 则执行语句块1 => break(跳出该结构) => 执行语句块4;
       若不相等 => 判断是否与字面值2相等
           若相等 => 则执行语句块2 => break => 执行语句块4;
           若不相等 => 则执行语句块3 => 执行语句块4;

(3)注意事项
   a.当case分支后没有break时,会继续执行下一个case对应的语句块,直到遇到break;
   b.早期jdk中switch()中允许的数据类型有:byte、short、char、int,从jdk1.5
     开始允许使用枚举类型,从jdk1.7开始允许使用String类型。

13.循环结构(重中之重)
13.1 for循环
(1)语法格式
   for(表达式1; 条件表达式2; 表达式3){
      循环体;
   }
   语句块;

(2)执行流程
   执行表达式1 => 判断条件表达式2是否成立
       若成立 => 则执行循环体 => 执行表达式3 => 判断条件表达式2是否成立
       若不成立 => 执行语句块;;

13.2 break和continue关键字
   break关键字可以用于switch-case结构 和 循环结构中,用于跳出当前多分支结构和循环结构(重点)。
   continue关键字只能用于循环结构中,用于结束当前循环体继续下一次循环(熟悉)。

注意:
   当程序中出现多层循环时,通常情况下,break和continue只对内层循环有效果。

13.3 特殊循环
   for(;;) - 这样的循环叫做无限循环,俗称“死循环”。
   通常情况下都与break关键字搭配使用。

13.4 二重循环
(1)语法格式
   for(表达式1; 条件表达式2; 表达式3){
      for(表达式4; 条件表达式5; 表达式6){
          循环体;
      }
   }
   语句块;

(2)执行流程
   执行表达式1 => 判断条件表达式2是否成立
     若成立 => 则执行表达式4 => 判断条件表达式5是否成立
         若成立 => 则执行循环体 => 表达式6 => 判断条件表达式5是否成立
         若不成立 => 表达式3 => 判断条件表达式2是否成立
     若不成立 => 执行语句块;

练习:
  *****      *      i = 0;  1个   列数实际上就是 行变量 + 1
  *****      **     i = 1;  2个
  *****      ***    i = 2;  3个
  *****      ****   i = 3;  4个
  *****      *****  i = 4;  5个

  *****     i = 1时,5个    *的个数其实就是 6 - i
  ****      i = 2时, 4个
  ***       i = 3时,3个
  **        i = 4时, 2个
  *         i = 5时,1个

13.5 while循环
(1)语法格式
   while(条件表达式){
       循环体;
   }
   语句块;

(2)执行流程   
   判断条件表达式是否成立
      若成立 => 执行循环体 => 判断条件表达式是否成立
      若不成立 => 执行语句块

(3)注意事项
   a.while循环和for循环可以完全互换。
   b.while(true)和for(;;)一样,都表示无限循环,俗称"死循环"。
   c.while循环通常用于明确循环条件但不明确循环次数的场合中。
     for循环通常用于明确循环次数的场合中。

13.6 do-while循环(熟悉)
(1)语法格式
   do{
     循环体;
   }while(条件表达式);
   语句块;

(2)执行流程  
   执行循环体 => 判断条件表达式是否成立
      若成立 => 执行循环体 => 判断条件表达式是否成立
      若不成立 => 执行语句块;

(3)注意事项
   当循环条件一开始就不成立时,对于while循环来说,不会执行循环体;对于do-while循环来说,会执行一次循环体。

14.一维数组(重点)
14.1 基本概念

   一维数组就是指内存空间中一段连续存储空间,用于存放多个数据类型相同元素/数据 
   数组 - 主要指存放数据元素的容器。
   数组元素 - 主要指数组中存放的数据内容。
   数组长度 - 主要指数组中最多可以存放的元素个数,使用数组名.length获取。
   数组下标 - 主要指数组元素在数组中的索引位置,从0开始,到数组长度-1。

14.2 数组的声明
(1)语法格式
   数据类型 变量名 = 初始值;
   数据类型[] 数组变量名(引用) = new 数据类型[数组长度];
如:
   int num = 66;
   int[] arr = new int[6];  // 推荐使用
   其中该数组的数组名为arr,数组长度为6,数组下标范围是:0 ~ 5。
   
   int arr[] = new int[6]; // ok 不推荐使用    
     

(2)默认初始化方式
   当数组声明完毕之后,采用默认初始化方式进行,其中byte/short/char/int/long类型的默认初始值为0;float/double类型的默认初始值为0.0;boolean类型的默认初始值为false;引用类型的默认初始值为null。
   
(3)注意事项
   当声明数组时,[]中的数字代表数组的长度,也就是数组元素的个数。
   当使用数组时,[]中的数字代表数组的下标,也就是数组元素的索引位置。

(4)数组的初始化
   当需要声明数组的同时指定初始值时,可以采用以下的语法格式:
       数据类型[] 数组变量名(引用) = {初始值1, 初始值2, ... ...};
   如:
       int[] arr = {11, 22, 33, 44, 55};  
       该数组的长度是:5,下标范围是:0 ~ 4。

扩展:
   java.lang.System类中的方法实现数组的拷贝:static void arraycopy(Object src, int srcPos, Object dest, int destPos, int length),src表示源数组,srcPos表示源数组的起始下标位置,dest表示目的地数组,destPost表示存放数据的起始位置,length表示拷贝的元素个数。 
   java.util.Arrays类中提供大量的方法用于数组元素的处理。
    
15.二维数组(熟悉)
15.1 基本概念

  一维数组本质上就是一段连续的内存空间,用于存放相同数据类型的多个数据。
  二维数组本质上就是由一维数组组成的 一维数组,也就是说二维数组中的每一个元素
都是一个一维数组。
   
15.2 声明方式
(1)语法格式
   数据类型[][] 数组变量名(引用) = new 数据类型[行数][列数];
如:
   int[][] arr = new int[2][4];
   该二维数组中一共有2行4列,其中行下标的范围是:0 ~ 1,列下标范围是:0 ~ 3。

思考:
   arr代表什么?arr[0]代表什么?arr[0][0]代表什么?
解析:
   arr代表二维数组这个容器自己。
   arr[0]代表二维数组的第一行,也就是一维数组这个容器自己。
   arr[0][0]代表二维数组的第一行第一列,也就是二维数组的第一个元素。

   arr.length代表二维数组的长度,也就是行数。
   arr[0].length代表二维数组第一行的长度,也就是列数。   

16.面向对象编程的概念
16.1 什么是对象?
   万物皆对象。

16.2 什么是面向对象?
   面向对象就是指用属性(特性)和行为分析现实世界中事物的方法。

16.3 什么是面向对象编程?
   面向对象编程就是指先用面向对象的观点进行分析,再采用面向对象的编程语言进行翻译/加以描述的过程。
   主流的面向过程语言:C语言、C++等
   主流的面向对象语言:Java、C++、C#等

16.4 为什么需要面向对象编程?
   软件产业化发展的需求。

16.5 如何学好面向对象编程?
   重点理解面向对象编程三大特征:封装、继承、多态。
   
17.类、对象以及引用(重中之重)
学生类:
   属性(特性):学号、姓名、年龄
   行为:学习、吃饭、娱乐
教师类:
   属性:工号、姓名、年龄
   行为:讲课、吃饭、娱乐
... ..

17.1 类的基本概念
   类就是“分类”的概念,是多个对象共性的提取。
   类是用户可以自定义的引用数据类型,包括用于描述属性(特性)信息的成员变量,以及用于描述行为信息的成员方法,换句话说,类可以描述多种不同类型的数据。
   类是一个抽象的概念,对象是客观存在的实体,类是对象创建的模板,而对象在程序中占用一块独立的内存空间,内部结构取决于类。

17.2 类的定义
(1)类定义的语法格式
   class 类名{
      类体;
   }    
如:
   class Person{
   }  

注意:
   通常情况下,当类名由多个单词组成时,每个单词的首字母都要大写。

(2)成员变量定义的语法格式
   class 类名{
      数据类型 成员变量名[ = 初始值]; - 可以省略的
   }
如:
   class Person{
      String name;
      int age;
   } 

注意:
  通常情况下,当成员变量名由多个单词组成时,从第二个单词起的首字母大写。

补充:
  变量根据所在位置的不同可以分为两种:
     成员变量 - 主要指在类体中在方法体外声明的变量,在整个类中有效。
     局部变量 - 主要指在方法体中声明的变量,在整个方法体中有效。

17.3 对象的创建
(1)语法格式
   new 类名();
如:
   new Person(); - 匿名对象,不便于再次访问。   

(2)使用方式
   当一个类定义完毕之后,可以通过new关键字去创建/构造对象,得到该类的一个实体,这个过程叫做类的实例化。
   创建对象的实质就是在内存空间的堆区申请一块存储区域,用于记录该对象独有的成员变量信息。
   
17.4 引用的概念和定义
(1)基本概念
   使用引用类型声明的变量,叫做引用类型变量,简称为 引用。
   
(2)语法格式
   类类型 变量名;
如:
   Person p;

(3)基本作用
   引用类型的变量名通常用于记录对象在堆区中的内存地址信息,通过该引用可以访问堆区中的成员变量信息,访问方式使用 .进行。
如:
   Person p = new Person();
   p.name = "zhangfei";

18.成员方法(重中之重)
18.1 基本概念

   成员方法就是指在类体中方法体外自定义的方法,换句话说,成员方法就是对多条语句的打包,用于描述该类的行为信息,使用成员方法可以提高代码的复用性和可维护性。

18.2 语法格式
  class 类名{

      返回值类型 方法名称(形参列表){
          方法体语句; - 描述方法的功能语句。
      }  
  }
如:
  class Person{
      void show(){
         System.out.println("没事出来秀一下!");
      }
  }
注意:
  当成员方法名由多个单词组成时,从第二个单词起每个单词的首字母大写。

18.3 成员方法的详解
(1)返回值类型
   返回值就是指从方法体内向方法体外传递的数据内容。
   返回值类型就是指返回值的数据类型,如:int、String等
       当需要从方法体内向外传递66时,此时返回值类型写:int即可。
       当需要从方法体内向外传递"hello"时,此时返回值类型写 String即可。
   当需要在方法体中返回数据时,使用return关键字,表示返回数据并结束当前方法。
       当返回66时,则方法体中写:return 66;
       当返回"hello"时,则方法体中写:return "hello";
       当返回变量的数值时,则方法体中写:int num = 66; return num(66);
       当返回表达式的结果时,则方法体中写:return num+100(166);
   当该方法没有需要返回的数据时,则返回值类型写 void即可。
  
(2)形式参数列表
   形式参数就是指从方法体外向方法体内传入的数据内容。
   形式参数列表的语法格式是:数据类型 形参名1, 数据类型 形参名2, ... ...
       当需要向方法体内传入数据66时,则形参列表为:int i。
       当需要向方法体内传入数据"hello"时,则形参列表为:String s。
       当需要传递66和"hello"时,则形参列表为:int i, String s。
   当该方法没有需要传入的数据时,则形参列表位置啥也不写即可。
   
18.4 方法的调用
(1)语法格式
   引用/对象.方法名(实参列表);
如:
   p.show();

(2)基本功能
   调用方法的本质就是执行方法体中的语句,实际参数列表的本质就是用于给形参列表进行赋值,因此参数的类型、参数的个数以及参数的顺序都要保持一致。
   实参可以传递字面值、变量、表达式等。

练习:
   自定义Point类,有两个成员变量分别代表横纵坐标(x,y),提供一个打印横纵坐标的方法、让横坐标加上参数(dx)值的方法,让纵坐标减去参数(dy)值的方法。
   在main()方法中创建对象,并调用上述方法。

19.构造方法和方法重载(重中之重)
19.1 构造方法

如:
   Person p = new Person();

(1)语法格式
   class 类名{

      类名(形参列表){
          构造方法体;
      }
   }
   构造方法的方法名称与类名完全相同,没有返回值类型,连void都不能有。
如:
  class Person{

     Person(){
        System.out.println("这是无参构造方法");
     }
  } 

(2)基本作用
   当使用new关键字创建一个新对象时,会自动调用构造方法进行新对象的初始化,换句话说,就是通过构造方法的方法体来进行对象成员变量的初始化工作。

(3)默认构造方法
   当一个类中没有自定义任何形式的构造方法时,编译器会自动添加一个无参的空构造方法,这样的构造方法叫做默认/缺省构造方法。
   但类中只要出现自定义构造,无论何种版本,编译器都不再提供缺省构造方法。

(4)编程经验
   a.当类中有非常量的成员变量时,通常提供两个版本的构造方法,一个是无参的构造方法,一个是有全属性做参数的构造方法。
   b.当需要使用到无参构造方法时,尽量不要对编译器形成依赖,避免错误的发生。
   c.当类中没有成员变量或者类中所有成员变量都是常量时,则不需要提供任何形式的构造方法。

19.2 方法的重载(Overload)
(1)基本概念
   在同一个类中,方法名相同、参数列表不同之间的方法构成重载关系。
如:
   Person(){}  Person(String n, int a){}  构成重载。

(2)主要形式
   方法重载的主要形式为:参数个数不同、参数类型不同以及参数顺序不同。
   与形参变量名、返回值类型无关,但建议返回值类型最好相同。
   
   判断是否重载的本质:是判断调用方法时能否区分。
   如:
      java.io.PrintStream类中的print()/println()方法都有大量的重载版本。

(3)实际意义
   方法重载的意义在于调用方便,也就是说调用者只需要记住一个方法名就可以调用该方法的任意版本。
    

29.this关键字(重点)
20.1 基本概念

   对于构造方法来说,this关键字就表示当前正在构造的对象。
   对于普通方法来说,this关键字就表示当前正在调用的对象。

   this关键字本质上就是构造方法和普通方法中一个隐含的参数,用于代表当前正在构造/正在调用的对象,当不同的对象被构造/调用方法时,this代表的对象也就随之不同。
   当在构造方法/普通方法中访问成员变量时,虽然只写了成员变量名,但本质就是this.的方式在访问,而this.相当于汉语中"我的",不同的对象在堆区中拥有不同的内存空间,使用不同的对象调用方法时,this代表的对象不同,那么取出来的成员变量值也就随之不同。

20.2 使用方式
   a.当成员变量名与形参变量名同名时,需要使用this.的方式明确指定使用的是成员变量,而不是形参变量(重点)。
   b.使用this.的方式不仅可以访问成员变量,还可以调用成员方法(熟悉)。
   c.使用this()的方式放在构造方法中的第一行,表示调用该类的其他构造方法(熟悉)
  
注意:
   当使用空引用访问成员变量/调用方法时,则会产生空指针异常。
   目前为止的异常:算数异常、数组下标越界异常、空指针异常。

21.方法的传参和递归调用
21.1 方法的传参原理(尽量理解)

  (1)main()方法是程序的入口,先申请实参变量的内存空间,对于变量来说,在栈中申请内存,对于对象来说,在堆区中申请内存。
  (2)当调用方法时,需要给该方法的形参申请内存空间。
  (3)将实参变量的数值拷贝一份给新参变量,放置到形参变量的内存空间中。
  (4)执行该方法的方法体,当方法调用结束时,回收形参变量对应的内存空间。
  (5)将方法的返回值放入main()方法的实参变量中。
  (6)当main()方法结束时,实参变量的内存空间也会被回收。

21.2 递归调用(重点、难点)
(1)基本概念
   递归就是指在方法体内调用该方法自身的形式。

例子:
   编程自定义一个方法,要求计算参数n的阶乘并传出最终的结果。
解析:
   5! = 5 * 4 * 3 * 2 * 1;
   4! = 4 * 3 * 2 * 1;

   5! = 5 * 4!;
   4! = 4 * 3!;
   ... ...
   1! = 1;

(2)使用原则
   a.寻找递归的规律,并指定递归的退出条件。
   b.使用递归必须使得问题简单化,而不是复杂化。
   c.使用递归需要注意程序的执行效率,某些情况下建议用递推的方式(循环)。
  
22.封装(重中之重 )
22.1 封装的由来

   当自定义一个封装类时,若对类中的成员不做任何的限制,则在测试类中可以给封装类赋值一些合法但不合理的数值,为了避免这种情况的发生,则需要对封装类进行封装处理。

22.2 封装的流程
  (1)私有化成员变量,使用private关键字修饰。
  (2)提供公有的get和set成员变量方法,在方法体中进行成员变量值的合理性判断。
  (3)在构造方法中调用公有的set成员变量方法。

22.3 封装的作用
  (1)隐藏类内部的实现细节,使得代码更加安全。
  (2)可以实现对成员变量合理值的判断。
  (3)可以提高代码的复用性和可维护性。

23.static关键字(重点)
23.1 基本概念

   通常情况下,成员变量和成员方法都隶属于对象层级,访问这些成员时需要使用对象/引用.的方式进行,当创建新的对象,每个对象都会在堆区申请一块独立的内存空间,用于保存该对象自己独有的成员变量值。
   当多个对象中的成员变量值完全相同时,若还在每个对象中单独保存一份,则会造成内存空间的浪费,此时可以使用static关键字解决该问题,使用static关键字修饰的成员叫做静态的,表示该成员由对象层级提升到类层级,在整个类中只有一份,并且被所有对象共享,虽然可以使用对象/引用.的方式访问,但推荐使用类名.的方式进行。
   静态成员随着类的加载而准备就绪,与是否创建对象无关。

23.2 使用方式
  (1)在非静态的成员方法中,可以访问非静态的成员,也可以访问静态成员。
     (成员:成员变量 + 成员方法)
  (2)在静态的成员方法中,只能访问静态成员,不能访问非静态成员。
     (静态成员方法中没有this关键字)
  (3)当该成员确实被所有对象共享时才能使用static关键字修饰,否则不能修饰。
     (static关键字不能随便使用) 

23.3 构造块和静态语句块
   构造块 - 主要指在类体中方法体外使用{}括起来的语句块。
   静态语句块 - 主要指在类体中方法体外使用static{}括起来的语句块。

执行流程:
   静态语句块 => 构造块 => 构造方法体

练习:
   自定义一个Singleton类和TestSingleton类,要求在TestSingleton类中能得到且只能得到Singleton类的一个对象。

23.4 单例设计模式(重中之重 )
(1)基本概念
   在某些特殊场合中,要求一个类能创建且只能创建一个对象,这样的类叫做单例类,设计单例类的编程经验总结叫做 单例设计模式。

(2)实现流程
   a.私有化构造方法,使用private关键字修饰。
   b.提供本类类型的对象作为本类的成员变量,使用private static关键字修饰。
   c.提供静态公有的get方法,负责将本类中的对象返回出去。

(3)主要分类
   单例设计模式主要分为两大类:饿汉式 和 懒汉式,以后的开发中推荐饿汉式。

24.继承(重中之重)

人类:
   属性:姓名、年龄
   行为:吃饭、娱乐
学生类 继承 人类:
   属性:学号
   行为:学习
教师类 继承 人类:
   属性:工号
   行为:讲课   

24.1 继承的由来
   当多个类之间有相同的成员变量和相同的成员方法时,则可以将相同的成员提取出来组成一个新类,让原来的多个类继承该新类即可,从而提高代码的复用性、可维护性以及可扩展性。

24.2 基本概念
   继承就是指吸收现有类中已有的成员变量和成员方法,而在新类中只需要编写自己独有的成员变量和成员方法就可以的形式。
   在java中使用extends关键字表达继承关系。
如:
   class Student extends Person{} - 表示Student类继承自Person类。
   其中Person类叫做 超类/基类/父类。
   其中Student类叫做 派生类/子类。

练习:
   编程实现Person类的封装,Person类的属性:姓名、年龄。

24.3 注意事项
  (1)子类可以继承父类中的所有成员变量,包括私有的,但不能直接访问私有的。
     子类不可以继承父类中的构造方法和私有成员方法。
  (2)当创建子类的对象时,无论调用子类构造方法中的哪个版本,都会自动调用父类
     中无参构造方法,用于实现对父类中成员变量的初始化工作,该效果的底层实现
     就是在构造方法中的第一行自动添加代码:super()。    
  (3)java语言不支持多继承,也就是说一个子类只能有一个父类,而一个父类可以
     有多个子类(单继承)。 
  (4)使用继承必须满足 子类 is  a 父类 的逻辑关系才可以。
     
24.4 super关键字
(1)基本概念
   this关键字 可以代表本类的对象。
   super关键字 通常用于代表父类的对象。

(2)使用方式
   使用this.的方式可以访问本类中的成员(成员变量和成员方法)。
   使用super.的方式可以访问父类中的成员(成员变量和成员方法)。

   使用this()的方式可以调用本类中的其他构造方法,要求写在构造方法第一行。
   使用super()的方式可以调用父类中的无参构造方法,要求写在构造方法第一行。
   因此this()和super()不能同时出现,当两个都不写时,默认增加super()。

要求大家重点掌握的用法:
    a.使用this.的方式用于区分成员变量名和形参变量名。
    b.使用super(实参)的方式可以调用父类的构造方法。
    c.使用super.的方式可以调用父类中被重写的方法。

24.5 方法的重写(Override)
(1)基本概念
   当使用父类中继承下来的方法不足以满足子类的需求时,则需要在子类中重写一个与父类一样(访问属性、返回值类型、方法名、参数列表)的方法进行调用,该方法就叫做对父类中继承下来方法的重写/覆盖。

(2)重写的原则
   a.要求有相同的方法名、参数列表以及返回值类型,从jdk1.5起允许返回子类类型。
   b.访问权限不能变小,可以变大。
   c.不能抛出更大的异常。

25.访问控制
25.1 常用的访问控制符

  public - 公开的
  protected - 保护的
  默认权限 - 采用默认方式进行访问的控制
  private - 私有的

35.2 访问控制的级别
  访问控制符   访问权限  本类内部  同一个包中的类   子类    其他类
----------------------------------------------------------------------- 
    public      公开的      ok          ok            ok      ok
    protected   保护的      ok          ok            ok      no
    默认权限    默认的      ok          ok            no      no
    private     私有的      ok          no            no      no

要求大家掌握的内容:
    public - 表示在任意有效位置都可以访问。
    private - 表示只能在本类内部进行访问,其他任何位置都不能访问。
    通常情况下,成员变量都用private修饰,成员方法都用public修饰。

25.3 包的定义
   package 包名;  - 表示创建一个包,为了便于管理和区分相同的类/文件。
   package 包名1.包名2...包名n; - 表示创建多层包,也就是多层目录。

26.final关键字
26.1 基本概念
  final本意为"最终的,不可更改的",使用final关键字可以修饰类/成员方法/成员变量

26.2 基本作用(重点)
  使用final修饰一个类表示该类不能被继承,如:java.lang.String/System类等
      - 为了防止滥用继承。
  使用final修饰一个方法表示该方法不能被重写。
      - 为了防止不经意间造成的重写。
  使用final修饰一个成员变量表示该成员变量必须被赋值,而且不能更改,不能依赖于默认初始化方式。

补充(重点):
   通常情况下,单独使用static和单独使用final的意义不大,以后的开发中更多的是用public static final共同修饰成员变量,表示常量的概念。
   对于常量来说,要求所有字母都要大写,不同单词之间使用_连接。
   如:
       public static final int MAX_VALUE = 10;
       public static final double PI = 3.14;

27.对象创建的过程(尽量理解,观察一下执行流程就行了)
27.1 单个对象的创建过程
  (1)运行程序时首先需要将类的字节码文件加载到内存中的方法区,这个过程叫类加载
  (2)当创建对象时需要在堆区申请内存空间,若指定了成员变量的初始值则使用指定的数值放入堆区内存,若没有指定初始值则使用默认初始化方式进行。
  (3)执行构造块中的代码,可以实现对成员变量的更改。
  (4)执行构造方法体中的代码,可以再次更改成员变量的数值。
  (5)此时对象创建完毕,继续执行main()方法中后续的代码。

27.2 创建子类对象的执行流程
  (1)运行程序时先进行类的加载,首先加载父类,因此先执行父类的静态语句块。
  (2)加载子类的字节码文件,此时执行子类的静态语句块。
  (3)当创建子类对象时,需要先创建子类对象中的父类小对象,因此执行父类的构造块和构造方法体。
  (4)继续创建子类对象,执行子类的构造块和构造方法体。
  (5)此时对象构造完毕,继续执行main()方法后面的代码。

28.多态(重中之重)
28.1 基本概念
  多态就是同一种事物表现出来的多种形态。
如:
  宠物:猫、狗、猴、鸟、小强、...
  饮料:可乐、雪碧、红牛、加多宝、果啤、...
  整数: byte b = 66; short s = 66; int i = 66; ...
  方法重载:show(){} show(int i){} ...
  ... ...

28.2 语法格式
  父类类型 引用变量名 = new 子类类型();

  在编译阶段引用是父类类型的,只能调用父类中的show()方法;在运行阶段引用是子类类型的,最终调用子类中重写以后的show()方法。
   
练习:
   编程实现Person类的封装(姓名、年龄)和Student类的封装(学号)继承Person类。
   再写TestStudent的测试类,负责创建父类对象 子类的对象 调用show()方法

28.3 多态的效果
  (1)父类的引用只能访问父类中的成员变量和成员方法。
  (2)父类的引用不能直接访问子类中的成员变量和成员方法,若希望能够访问子类中的成员,则需要进行强制类型转换。
     目标类型 目标类型的变量名 = (目标类型)源类型的变量名;
  (3)对于非静态的方法来说,最终调用子类中重写以后的版本。
     对于静态方法来说,最终调用父类自己的版本。

28.4 引用类型之间的转换
  (1)引用类型之间的转换必须发生在父子类之间。
  (2)子类向父类转换时只需要自动类型转换即可;
     但父类向子类的转换需要进行强制类型转换。 
  (3)若没有父子类关系就进行强制类型转换,则编译阶段报错,执行不到运行阶段。
     若拥有父子类关系进行强制类型转换,则编译阶段不报错,但目标类型若不是
     该引用真正指向的子类类型,则在运行阶段产生类型转换异常。
  (4)为了避免上述错误的产生,通常建议在类型转换之前先做一个类型的判断,具体
     方式如下:
         if(引用名 instanceof 数据类型){} 
         若引用指向的对象确实是后面的数据类型则返回true,否则返回false。

28.5 强制类型转换成功的条件(两个):子父类关系,父类的引用指向指向子类。

练习:
   自定义矩形类,成员变量主要有:横坐标、纵坐标、长度、宽度,成员方法有:打印所有成员变量的方法,实现矩形类的封装。
   自定义圆形类,成员变量主要有:横坐标、纵坐标、半径,成员方法有:打印所有成员变量的方法,实现圆形类的封装。
   自定义形状类,描述矩形类和圆形类的共性。
   Rect Circle Shape  x  y  len  wid  r 
    
28.5 多态的作用
   多态的作用主要在屏蔽不同子类之间的差异性,实现通用的编程,达到不同的效果。

29.抽象类(重点)
29.1 抽象方法的概念

  抽象方法就是指不能具体实现的方法,并且使用abstract关键字修饰。
  抽象方法的语法格式:
     访问控制符 abstract 返回值类型 方法名(形参列表);
     如: 
        public abstract void cry(); 

29.2 抽象类的概念
  抽象类通常指使用abstract关键字修饰并且有抽象方法的类,抽象类是不能实例化对象

29.3 注意事项
  (1)抽象类中可以有成员变量、成员方法以及构造方法。
     构造方法存在的价值是为了让子类通过super()的方式调用,从而构造父类小对象。
  (2)抽象类中可以有抽象方法,也可以没有抽象方法。
  (3)拥有抽象方法的类必须声明为抽象类。

29.4 抽象类的意义
   抽象类本身的意思不在于创建对象,而在于被继承,当一个类继承抽象类之后则必须要重写抽象类中的抽象方法,否则该类也变成抽象类,从而使得抽象类对子类实现了强制性和规范性。
   这种设计的方式叫做模板设计模式。

经验分享:
   在以后的开发中若没有明确的要求,推荐使用父类引用指向子类对象的方式,因为使用该方式编程时,该引用直接调用的所有方法必然都是父类中的方法,那么以后更改指向的对象时,只需要将子类类型修改即可,其他代码都不用改动,因此可维护性更强。  

30.接口(重点)
30.1 基本概念

  接口本质上就是一种比抽象类还抽象的类,里面的所有方法都是抽象方法。
  定义抽象类使用class关键字,而定义接口使用interface关键字。
  继承类使用extends关键字,而实现接口使用implements关键字。

30.2 使用方式
  (1)接口中所有的属性都必须由public static final共同修饰,也就是常量。
  (2)接口中所有的方法都必须由public abstract共同修饰,也就是抽象方法。

30.3 类和接口的比较
   类和类之间的关系      使用extends关键字      支持单继承
   类和接口之间的关系    使用implements关键字   支持多实现
   接口和接口之间的关系  使用extends关键字      支持单继承

30.4 抽象类和接口的主要区别
  (1)定义抽象类使用class关键字,定义接口使用interface关键字。
  (2)继承抽象类使用extends关键字,实现接口使用implements关键字。
  (3)继承抽象类只能是单继承,而实现接口可以是多实现。
  (4)抽象类中可以有构造方法,接口中没有构造方法。
  (5)接口中所有的属性都是常量,使用public static final共同修饰。
  (6)接口中所有的方法都是抽象方法,使用public abstract共同修饰。
  (7)接口中只要增加方法必然影响到子类,而抽象类可以不影响。

40.内部类(了解)
40.1 基本概念

  将一个类的定义写在另外一个类的内部,该类就叫做内部类,所在的类叫外部类。
  类的主要组成:成员变量、成员方法、构造方法、构造块、静态语句块、内部类。

40.2 语法格式
  class 类名{
     class 内部类名{
        类体;
     }
  }

40.3 基本作用
  当一个类存在的价值仅仅是为某一个类单独服务时,就可以将该类写成那个类的内部类,内部类可以直接访问外部类的成员,包括私有的,而不再需要提供公有的get/set方法

40.4 内部类的主要分类
  普通内部类 - 直接将类的定义放在另外一个类的内部。
             - 隶属于对象层级,需要使用外部类对象.的方式创建。
  静态内部类 - 使用static关键字修饰的内部类。
             - 外部类是不能使用static关键字修饰的。
  局部内部类 - 直接将类的定义放在一个方法体中。
             - 局部内部类只能在方法体内使用。
  匿名内部类 - 没有名字的内部类,用于构造接口/父类类型的对象(重点)。

40.5 匿名内部类的语法格式(重点)
  接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };

经验分享:
   当使用接口类型的引用作为方法的形参时,实参的传递有两种方式:a.自定义一个新类实现接口,然后创建新类的对象作为实参传递;b.直接使用匿名内部类去创建接口类型的对象作为实参传递。

41.Object类
41.1 常用的包

   java.lang包 - 是java中的核心包,该包中的所有类由java虚拟机自动导入。
   java.util包 - 是java中的工具包,该包中包括了各种工具类和集合类。
                 如:Scanner类、Random类以及List、Set接口等
   java.io包   - 是java中输入输出包,该包包含了大量输入输出类,实现文件读写等
   java.net包  - 是java中网络包,该包中包含了基于socket通信的实现类等。
   java.sql包  - 是java中连接和处理数据的包。
   ... ...

41.2 Object类
(1)基本概念
   java.lang.Object类是java类层次结构中的根类,是所有类的超类。

(2)常用的方法(重点)
   Object() - 无参的构造方法,用于子类通过super()的方式进行调用。   
   boolean equals(Object obj) - 判断调用对象是否与参数对象相等。
       - 形参是Object类型的引用,因此实参可以传递本类对象,也可以传递子类对象
       - 默认比较的是两个对象的地址是否相等,效果等同于 == 。
       - 具有自反性、对称性、传递性、一致性、非空性。
       - 若希望该方法比较两个对象中的内容,则需要进行方法的重写。
       - 只要重写了该方法则记得去重写hashCode()方法。
   int hashCode() - 用于返回调用对象的哈希码值(内存地址的编号)。
       - 只要equals()方法比较的信息没有修改,则调用该方法都应该返回相同的整数
       - equals()比较两个对象相等,则两个对象调用该方法返回的整数相同。
       - equals()比较不相等,则对象调用该方法返回的整数可以相同,但最好不相同
   String toString() - 用于返回调用对象的字符串形式。
       - 字符串格式为:包名.类名@哈希码的无符号十六进制形式。
       - 若希望打印其他内容,则需要进行方法的重写。
       - println()方法打印引用时,会自动调用toString()方法。
       - 若使用+进行字符串连接时,也会自动调用toString()方法。
 
42.包装类和数学处理类
42.1 包装类的由来

   java语言是一门纯面向对象的编程语言,万物皆对象。
如:
   int num = 30; 
   Person p = new Person();
   
   在某些特殊场合(集合)中,要求放入的所有数据都必须是对象,而对于基本类型的数据来说并不满足是对象的要求,因此不能直接放入,为了能够放入该类数据就需要对数据进行对象化处理,于是需要借助包装类。
   
42.2 常用的包装类
  int     => java.lang.Integer类(重点)
  double  => java.lang.Double类
  float   => java.lang.Float类
  byte    => java.lang.Byte类
  short   => java.lang.Short类
  long    => java.lang.Long类
  boolean => java.lang.Boolean类
  char    => java.lang.Character类
  
42.3 Integer类(重点)
(1)基本概念
   java.lang.Integer类被final关键字修饰,表示该类不能被继承。
   该类内部包装了一个int类型的数据。

(2)常用的方法  
   Integer(int value) - 采用参数指定的整数来构造对象。
   Integer(String s) - 采用参数指定的字符串来构造对象。
   该类重写了equals()、hashCode()、toString()方法。
   static int parseInt(String s) - 用于将字符串转换为int类型的整数。
        - 使用类名.的方式调用
   int intValue() - 将Integer类型对象中的整数值返回。
  

43.包装类和数学处理类
43.1 常用的包装类

  int     =>  java.lang.Integer类(重点)
  double  =>  java.lang.Double类
  float   =>  java.lang.Float类
  byte    =>  java.lang.Byte类
  short   =>  java.lang.Short类
  long    =>  java.lang.Long类
  boolean =>  java.lang.Boolean类
  char    =>  java.lang.Character类 

43.2 Integer类
  java.lang.Integer类由final修饰,表示该类不能被继承。

43.3 装箱和拆箱
  装箱就是指从基本数据类型到引用数据类型之间的转换,如:int => Integer类。
  拆箱就是指从引用数据类型到基本数据类型之间的转换,如:Integer类 => int。
    
  从jdk1.5开始,支持自动装箱和自动拆箱的功能。

43.4 自动装箱池(尽量理解)
  从jdk1.5开始支持自动装箱和自动拆箱的功能,为了提供装箱的效率,Integer类的内部提供了一个自动装箱池,里面已经放好了-128 ~ 127之间的数据对象,当程序中需要对该范围中的数据进行装箱时,直接从装箱池中获取,否则才需要创建新的对象。

43.5 BigDecimal类(了解)
(1)基本概念
   在java语言中描述浮点数使用float类型和double类型,但float类型和double类型都会有误差,为了实现精确计算,可以使用java.math.BigDecimal类加以描述。

(2)常用的方法
   BigDecimal(String val) - 根据参数指定的字符串来构造对象。
   BigDecimal add(BigDecimal augend) - 用于计算调用对象和参数对象的和并返回
   BigDecimal subtract(BigDecimal subtrahend) - 计算调用对象减去参数对象的差
   BigDecimal multiply(BigDecimal multiplicand) - 计算调用对象和参数对象的积
   BigDecimal divide(BigDecimal divisor) - 计算调用对象和参数对象的商 
 
43.6 BigInteger类(了解)
(1)基本概念
   在java语言中描述整数首选int类型,若int类型范围不够则使用long类型,若long类型还是不够,则使用java.math.BigInteger类加以描述。

(2)常用的方法 
   参数BigDecimal类型即可。

44.String类(重中之重)
44.1 基本概念
  java.lang.String类由final关键字修饰,表示该类不能被继承。
  该类用于描述字符串对象,应用程序中所有的字符串字面值都可以使用该类实例描述。
  该类描述的字符串内容是个常量,不可更改。
如:
     String       name    =    "zhangfei";
       |           |              |
    数据类型   引用变量名    字符串的字面值(常量)

     name = "guanyu";  - 本质上就是在修改引用的指向,而不是指向的内容。

注意:
    String str = "";    有字符串对象,但没有字符串内容。
    String str = null;  没有字符串对象。
    
44.2 字符串常量池(尽量理解)
   为了提高字符串的使用效率,当程序中出现字符串常量时,首先去字符串常量池中进行查找,若存在则直接返回该对象,若不存在再创建对象并放入常量池中。  

44.3 常用的方法(练熟)
(1)常用的构造方法
   String() - 使用无参的形式构造对象。
   String(byte[] bytes) - 根据参数指定的byte数组来构造字符串对象。
   String(byte[] bytes, int offset, int length) - 使用数组中的一部分构造对象。
   String(String original) - 使用字符串字面值来构造字符串对象。
   String(StringBuffer buffer) - 用于将StringBuffer类型转换为String类型。
   String(StringBuilder builder) - 用于将StringBuilder类型转换为String类型。

(2)常用的其他方法
   char charAt(int index) - 用于返回当前字符串中参数指定索引位置的单个字符。
   int length() - 用于返回当前字符串的长度。

   int compareTo(String anotherString) - 比较调用字符串和参数字符串的大小。
       - 若调用字符串比较大则返回正数;
       - 若调用字符串比较小则返回负数;
       - 若相等则返回0;
       - 先比较相同索引位置的单个字符,后比较长度确定大小
   int compareToIgnoreCase(String str) - 比较字符串的大小,不考虑大小写。
   boolean equals(Object anObject) - 比较调用对象和参数对象是否相等。
   boolean equalsIgnoreCase(String anotherString) - 比较是否相等时不考虑大小写

45.String类(重中之重)
45.1 常用的方法

   String substring(int beginIndex)
      - 用于获取当前字符串中从beginIndex位置(包括)开始一直到该字符串结尾的子串    String substring(int beginIndex, int endIndex) 
      - 用于获取当前字符串中从beginIndex位置(包括)开始到endIndex位置(不包括)
        之间的子串。   
   boolean matches(String regex) 
      - 用于判断当前字符串是否满足参数指定的正则表达式规则。
   String replaceAll(String regex, String replacement) 
      - 用于按照正则表达式进行字符串的全部替换。
   String replaceFirst(String regex, String replacement) 
      - 用于替换满足正则表达式的第一个子字符串。
   String[] split(String regex) 
      - 用于按照指定的正则表达式进行字符串的拆分。

45.2 正则表达式(记住)
(1)基本概念
   正则表达式本质就是一个字符串,用于进行数据格式的验证。
   通常情况下,正则表达式使用^开头,使用$结尾,可以省略,但推荐写上。

(2)常用的规则
   [abc] - 表示可以出现a、b或c中的任意字符。
   [^abc] - 表示可以出现任意字符,除了a、b以及c。
   [a-zA-Z] - 表示可以出现a到z和A到Z之间的任意字符,也就是所有字母都可以出现。
   
   \d - 表示可以出现任何数字,相当于[0-9]。
   \D - 表示可以出现任何非数字,相当于[^0-9]。
   \s - 表示可以出现任何空白字符,相当于[ \t\n\x0B\f\r]。
   \S - 表示可以出现任何非空白字符,相当于[^\s]。        
   \w - 表示可以出现任何单词字符,相当于[a-zA-Z_0-9]。
   \W - 表示可以出现任何非单词字符,相当于[^\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。
           
46.StringBuilder类和StringBuffer类(查手册会用即可)
46.1 StringBuilder类和StringBuffer类的由来
   在java中使用String类可以描述所有的字符串数据,但String类的对象一旦创建,则该对象中的字符序列就不可更改,当需要更改字符串内容时,需要拷贝出来多个副本并单独进行保存,因此对空间和时间的消耗比较大,为了解决该问题,可以用StringBuilder类和StringBuffer类,这两个类描述的字符序列可以直接更改。    
   StringBuilder类是后来增加的类,不支持线程同步/安全,因此效率比较高。
   StringBuffer类是早期就有的类,支持线程同步/安全,因此效率比较低。
   

46.2 StringBuilder类
(1)基本概念
   java.lang.StringBuilder类由final修饰,表示该类不能被继承。
   该类用于描述可变的字符序列,不支持线程的同步,因此效率比较高。   

(2)常用的方法
   StringBuilder() - 使用无参的形式进行对象的构造,初始容量是16个字符。
   StringBuilder(int capacity) - 根据参数指定的容量来构造该类的对象。
   StringBuilder(String str) - 容量为16 + 字符串的长度。

   int capacity() - 返回调用对象的容量。
   int length() - 返回调用对象中字符的个数。

   StringBuilder insert(int offset, String str) 
     - 用于将str插入到当前调用对象中下标为offset的索引位置上。
   StringBuilder append(String str) 
     - 用于将str指向的字符串内容追加到当前字符串的末尾
   StringBuilder delete(int start, int end) 
     - 用于将当前字符串中下标从start(包含)到end(不包含)之间的字符串内容删除。 
   StringBuilder replace(int start, int end, String str) 
     - 用于将当前字符串中下标从start到end之间的字符串内容替换成str。 
   StringBuilder reverse() - 用于反转字符序列。 

47.日期相关的类(查手册会用即可)
47.1 Date类

(1)基本概念
   java.util.Date类用于描述日期和时间的类型,可以描述年月日时分秒的信息。

(2)常用的方法 
   Date() - 使用当前系统时间来构造对象。
   Date(long date) - 使用参数指定的毫秒数来构造对象。
      - 从1970年1月1日0时0分0秒到指定日期的毫秒数。 
   long getTime() - 获取调用对象距离1970年1月1日0时0分0秒之间的毫秒数。
   void setTime(long time) - 将参数指定的毫秒数设置到当前调用对象中。

47.2 SimpleDateFormat类
(1)基本概念
   java.text.SimpleDateFormat类用于格式化和解析日期数据的。

(2)常用的方法    
   SimpleDateFormat(String pattern) - 根据参数指定的日期格式构造对象。
       - 日期格式中:y代表年 M代表月 d代表日 H代表时 m代表分 s代表秒。
   String format(Date date) - 用于将参数指定的日期对象格式化字符串并返回。
   Date parse(String source) - 将字符串转换为Date类型的对象。

47.3 Calendar类
(1)基本概念
   java.util.Calendar类是一个抽象类,有构造方法,但不能构造/实例化对象。
   该类可以为Date类构造指定年月日时分秒的日期对象。

(2)常用的方法   
   static Calendar getInstance() - 使用类名.的方式调用该方法可以得到本类的对象
   void set(int year, int month, int date, int hourOfDay, int minute, int second) - 根据参数指定的年月日时分秒来指定调用对象中的日期和时间信息。
        - 月份-1作为实参传递给该方法。
   Date getTime() - 用于转换为Date类型的对象并返回。

48.集合类
48.1 基本概念

  数组 - 本质上就是在内存空间中申请的一段连续内存空间,存放多个相同类型的数据
       - 数组一旦定义完毕,则在内存空间中的长度固定。
       - 插入/删除元素时可能导致大量元素的移动,因此效率比较低。
       - 使用数组下标访问元素非常便利。
       - 数组中的元素可以是基本数据类型,也可以是引用数据类型。
  集合 - 内存空间不一定连续,数据类型不一定相同。
       - 内存空间的长度不固定,可以动态调整。
       - 插入/删除元素时可以不移动大量元素,效率可以提高。
       - 不一定支持下标访问。
       - 集合中的所有元素都必须是引用数据类型,借助包装类。
  集合类 - 主要指用于描述集合的相关类和接口。

48.2 基本分类
  集合/容器主要分为两大类:Collection接口 和 Map接口。
  其中Collection接口中存放元素的基本单元:单个元素。
  其中Map接口中存放元素的基本单元:单对元素。

  Collection接口本身很少使用,通常都使用子接口:List接口、Queue接口以及Set接口

48.3 Collection接口(熟悉)
  boolean add(E e) - 用于将参数指定的元素放入当前集合中。
     - 若当前集合发生更改则返回true,否则返回false。
  boolean addAll(Collection<? extends E> c) 
     - 用于将参数指定集合中的所有元素都增加到当前集合中。
   
  boolean contains(Object o) - 判断参数指定的元素是否在当前集合中。
  boolean containsAll(Collection<?> c)
     - 判断参数指定集合中所有元素是否在当前集合中。 
  
  boolean remove(Object o) - 用于删除参数指定的单个元素。
  boolean removeAll(Collection<?> c) - 删除参数指定的所有元素。
  void clear() - 用于清空当前集合。
  
  boolean isEmpty() - 判断当前集合是否为空。
  int size() - 用于获取当前集合中的元素个数。
 
  boolean retainAll(Collection<?> c) - 用于计算两个集合的交集,保留在当前集合中。
  Iterator<E> iterator() - 用于获取当前集合中的迭代器,可以访问集合中的所有元素。

49.List接口(重点)
49.1 基本概念

  java.util.List接口是Collection接口的子接口,继承自Collection接口。
  该集合中的元素是有序的(放入次序,并不是大小次序),允许有重复的元素存在。
  该接口的主要实现类有:ArrayList类、LinkedList类、Stack类、Vector类(笔试)。     其中ArrayList类的底层是采用动态数组实现的,访问和修改方便,增删不方便。
  其中LinkedList类的底层是采用链表实现的,访问和修改不方便,增删方便。
  其中Stack类的底层是采用动态数组实现的,该类是一种具有后进先出特性的数据结构,简称为LIFO(last in first out 栈)。
  其中Vector类的底层是采用动态数组实现,与ArrayList相比,支持线程安全,效率比较低,java官方推荐使用ArrayList取代之。

49.2 常用的方法
  该接口中包含了Collection接口中的方法。
  void add(int index, E element) - 将数据element插入到index指向的位置。
  boolean addAll(int index, Collection<? extends E> c) 
     - 将集合c中的所有元素插入到index指向的位置。
  
  E remove(int index) - 删除index指向位置的元素,返回该位置被删除的元素值。
  E set(int index, E element) 
    - 将index位置的元素替换为element,返回替换之前的元素值。
    - index的取值范围是:[0, size()-1]。
  E get(int index) - 返回index指向位置的元素值。
  
  List<E> subList(int fromIndex, int toIndex) 
     - 获取集合中下标从fromIndex(包含)到toIndex(不包含)之间的所有元素。
  
49.3 泛型机制
   早期的集合中允许存放不同类型的数据,但本质上都是将这些数据看做Object类型进行存储的,当需要从集合中取出数据时,并表达真正的数据类型时,就需要进行强制类型转换,而转换的目标类型若不是真正指向的类型,则产生类型转换异常。
   为了避免以上错误的发生,从jdk1.5开始提供了泛型机制,也就是在集合的名称后面使用<数据类型>的方式明确规定了元素的类型,若放入其他类型数据,则编译报错。
如:
   List<String> list = new ArrayList<String>();

今天内容:
   (1)Queue接口
   (2)Set接口
   (3)Map接口
   (4)异常

50.Queue接口(重点)
50.1 基本概念

  栈本质上就是一种具有后进先出特性的数据结构,简称为LIFO(last in first out)。
  队列本质上就是一种具有先进先出特性的数据结构,简称为FIFO(first in first out)
  java.util.Queue接口是Collection接口的子接口,与List接口是平级关系。
  该接口的常用子接口有:Deque接口,表示双端队列。
  该接口的主要实现类有:LinkedList类,增删方便,查改不方便。

50.2 常用的方法
  boolean offer(E e) - 用于将参数指定的数据插入到队列中
       - 成功返回true,否则返回false。
  E peek() - 用于获取队列的队首元素值,若队列为空则返回null。
  E poll() - 获取并移除此队列的头,如果此队列为空,则返回 null。 
  
51.Set接口(重点)
51.1 基本概念

  java.util.Set接口是Collection接口的子接口,与List接口平级关系。
  该接口中的元素是无序的(无放入顺序),不允许有重复的元素。
  该接口的主要实现类:HashSet类 和 TreeSet类。
  其中HashSet类的底层是采用哈希表进行数据的管理。
  其中TreeSet类的底层是采用二叉树进行数据的管理。

51.2 常用的方法
  该接口的常用方法与Collection接口中的一样。
  Iterator<E> iterator() - 用于获取当前集合中的迭代器,用于遍历集合中所有元素
  
51.3 迭代器的使用
  boolean hasNext() - 判断集合中是否有可以迭代的元素,若有则返回true。
  E next() - 获取集合中的一个元素,并且指向下一个元素。
  void remove() - 用于删除迭代的一个元素。
 
注意:
  使用迭代器遍历集合中的元素时,不允许调用集合中的方法删除元素,只能通过迭代器自己的remove()进行元素的删除,否则引发对象并发修改异常。

51.4 增强版的for循环(for each)
(1)语法格式
   for(元素类型 变量名 : 数组名/集合名){
      循环体,使用变量名代表当前元素;
   }
  
(2)执行流程
   先声明元素类型的变量 => 从数组/集合中取出元素赋值给变量 => 执行循环体 => 取出下一个元素赋值给变量 => 执行循环体 => ... => 元素取完为止。

(3)经验
   在以后的开发中若只是遍历集合中的所有元素,则推荐使用for each结构。
   在以后的开发中若遍历的同时还希望删除元素,则推荐使用迭代器结构,并且切记调用的是迭代器自己的remove()方法,使用集合的remove()方法有风险。

总结:
   对于List集合来说遍历的方式有4种:toString()、get()、迭代器、for each结构。
   对于Set集合来说遍历的方式有3种:toString()、迭代器、for each结构。
 
51.5 元素放入HashSet类的过程(尽量理解)
  (1)调用放入元素的hashCode()方法,得到该元素的哈希码值。
  (2)通过哈希算法算出该元素在哈希表的索引位置。
  (3)若该索引位置没有元素,则将该元素直接放入。
  (4)若该索引位置有元素,则调用equals()方法与已经存在的元素依次进行比较。
  (5)若相等,则放弃该元素的插入;若不相等,则将该元素插入到最后的位置。

51.6 TreeSet类
(1)什么是二叉树?
   二叉树就是指每个节点最多拥有两个子节点的树形结构,通俗来说,最多有两个分叉
   
(2)什么是有序二叉树?
   满足以下三个特征的二叉树叫做有序二叉树,又叫做二叉查找树。
   a.要求左子树中所有的节点都必须小于根节点。
   b.要求右子树中所有的节点都必须大于根节点。
   c.左右子树内部还要满足上述规则。

(3)什么是平衡二叉树
   平衡二叉树就是指左右子树高度差的绝对值不超过1的二叉树。
   TreeSet类的底层就是一颗平衡有序二叉树。

(4)TreeSet类放入元素的过程
   当向TreeSet类中放入元素时,需要指定元素的比较规则,指定方式有两种:
      a.让元素类型实现java.lang.Comparable接口,重写compareTo()方法,自然排序
      b.在创建集合时传入java.util.Comparator对象,重写compare()方法,比较器

51.7 Collections类
  java.util.Collections类是java官方提供的一个工具类,该类中提供了大量针对集合中元素操作的方法,如:max()获取集合中最大值。

52.Map接口(重点)
52.1 基本概念

  java.util.Map<K,V>接口是一个顶层接口,里面存放数据的单元是:单对元素。
     - K 表示描述的键的类型,也就是key的类型。
     - V 表示描述的值的类型,也就是value的类型。
     - Map就是用于存放key-value键值对的集合。
     - 该集合中key是不允许重复的,而一个key只能对应一个value。
  该接口的主要实现类:HashMap类(哈希表) 和 TreeMap类(红黑树)。   
    
52.2 常用的方法
   V put(K key, V value) - 将参数指定的key和value组成一个完整键值对,放入集合
      - 若集合之前没有key,则返回null,否则返回key之前对应的value值。
   V remove(Object key) - 删除参数指定key对应的键值对,返回key对应的value。
      - 若key不存在,则返回null。
   boolean containsKey(Object key) - 用于判断参数指定的key是否存在。
   boolean containsValue(Object value) - 用于判断参数指定的value是否存在。
   V get(Object key) - 用于获取参数key对应的value值。
   
   Set<Map.Entry<K,V>> entrySet() - 用于获取Map集合的Set视图。
       K getKey() - 用于获取调用对象的key值。
       V getValue() - 用于获取调用对象的value值。
   Set<K> keySet() - 获取Map集合中key的Set视图。

53.异常(熟悉)
53.1 基本概念

  异常本质就是不正常的意思,主要指程序在运行期间产生的错误。
  java.lang.Throwable类是java语言中所有错误和异常的超类。
  其中错误使用java.lang.Error类加以描述,通常指比较严重的错误,无法编程解决。
  其中异常使用java.lang.Exception类加以描述,通常指使用代码可以解决的小问题。

53.2 基本分类
  java.lang.Exception类的子类主要分成以下两大类:
      RuntimeException - 运行时异常,也叫作非检测性异常。
                       - 在编译阶段检测不出来,在运行阶段发生的异常。
      IOException和其他异常类 - 其他异常类,也叫作检测异常。
                       - 在编译阶段就报错,必须处理,否则走不到运行阶段。
 
注意:
   当发生异常并没有手动进行异常的处理时,该异常由java虚拟机采用默认方式处理,而默认处理的方式就是打印异常名、异常信息、发生的位置等,并终止程序。

   RuntimeException类的主要子类(记住):
       ArithmeticException - 算数异常
       ArrayIndexOutOfBoundsException - 数组下标越界异常(间接子类)
       NullPointerException - 空指针异常
       ClassCastException - 类型转换异常
       NumberFormatException - 数字格式异常

53.3 非检测异常的处理方式
   对于绝大多数的非检测异常来说,只需要使用if()条件判断就可以避免异常的发生。

53.4 异常的捕获
(1)语法格式
   try{
      编写可能会产生异常的语句块;
   }
   catch(异常类型 引用名){
      编写针对该类型异常的处理语句块;
   }
   ... ...
   finally{
      编写无论是否发生异常都应该执行的语句块,通常用于进行善后处理;
   }

(2)注意事项
   一个try{}后面跟多个catch{}分别处理不同类型的异常对象,但切记异常类型范围小的放在范围大的异常类型前面。
   懒人的写法:
       catch(Exception e){ ... ...}

(3)执行流程
   try{
      a;
      b;  - 可能发生异常的代码
      c;
   }catch(Exception e){
      d;
   }finally{
      e;
   }

  当没有发生异常时,执行流程是:abce;
 当发生异常时,执行流程是:ab d e;
         
53.5 异常的抛出
(1)基本概念
   在某些特殊场合中,产生的异常对象不便于处理或者无法处理,此时就需要将异常抛出给调用者,异常的抛出并不是异常的处理,而是异常的转移。
   
(2)语法格式
   访问修饰符 返回值类型 方法名(形参列表) throws 异常类型,异常类型{ ... ...}
如:
   public static void main(String[] args) throws FileNotFoundException {}
     
(3)异常对象的语法格式
   throw new 异常类型();  - 表示抛出一个指定的异常对象,用于方法体内部。

(4)方法重写的原则
   a.要求方法名相同、参数列表相同、返回值类型也相同(返回子类类型)。
   b.访问权限不能变小,可以相同或者变大。
   c.不能抛出更大的异常。

总结:
   子类中重写以后的方法可以抛出与父类中相同的异常、可以抛出子类异常、不抛出异常,但是不能抛出更大的异常 或者 同级不一样的异常。
    
53.6 自定义异常
(1)为什么需要自定义异常?
   在java语言中提供了大量的异常类型,但是没有一种类型能够专门表达学号异常,这些异常类型虽然可以使用,但没有对学号不合理的针对性,为了专门表达学号不合理的异常,此时就需要自定义异常。

(2)自定义异常的方式
   a.自定义异常类继承Exception或者其子类。
   b.提供一个无参的和一个字符串做参数的构造方法即可。

54.File类(重点)
54.1 基本概念

  java.io.File类用于描述文件和目录的路径信息。
  使用该类可以获取文件的属性信息,如:文件名、文件大小等,但不能修改文件内容。 

54.2 常用的方法
  File(String pathname) - 根据参数指定的路径构造File类的对象。
  boolean exists() - 判断文件/目录是否存在。
  String getName() - 获取文件/目录的名称。
  long length() - 获取文件的长度。
  String getAbsolutePath() - 获取文件的绝对路径信息。
      绝对路径 - 以根目录开始的路径,如:C:  D: ...  
      相对路径 - 以当前目录开始的路径,如:./code
                 . 表示当前目录   .. 表示当前目录的上一级目录
      以后的开发中推荐使用相对路径,所有的路径分隔符一律使用 ./。
  long lastModified() - 获取文件的最后一次修改时间。
      - 返回的是距离1970年1月1日0时0分0秒的毫秒数,与Date的有参构造搭配使用
  
  boolean createNewFile() - 用于创建新的空文件。
  boolean mkdir() - 用于创建目录。
  boolean delete() - 用于删除文件/目录。

  File[] listFiles() - 获取当前目录中的所有内容(文件和子目录)。
  boolean isDirectory() - 判断是否为目录。
  boolean isFile() - 判断是否为文件。

55.I/O流
55.1 基本概念

  I/O就是Input/Output的简写,也就是输入/输出的含义。
  I/O流就是指像流水一样源源不断地进行读写的过程。

55.2 基本分类
  根据读写数据的单元分为:字节流 和 字符流。
      其中字节流就是指以字节为单位进行读写的流,可以读写任意文件。 
      其中字符流就是指以字符为单位进行读写的流,只能读写文本文件。 
  根据读写数据的方向分为:输入流 和 输出流(程序的角度)
      其中输入流就是指从文件读取数据输入到程序中。
      其中输出流就是指将程序中的数据输出到文件中,也就是写文件。
  
55.3 常用的类
  字节流的顶层父类:InputStream类 和 OutputStream类。
  InputStream类的主要实现类:
     FileInputStream类、DataInputStream类(间接子类)、ObjectInputStream类         OutputStream类的主要实现类:
     FileOutputStream类、DataOutputStream类(间接子类)、ObjectOutputStream类   
  
  字符流的顶层父类:Reader类 和 Writer类。
  Reader类的主要实现类:
     BufferedReader类、InputStreamReader类、StringReader类。
  Writer类的主要实现类:
     BufferedWriter类、OutputStreamWriter类、StringWriter类。

补充:
  PrintStream类是OutputStream类的间接子类。

55.4 FileOutputStream类(重点)
(1)基本概念
   java.io.FileOutputStream类主要用于将字节流数据写入到输出流中。

(2)常用的方法 
   FileOutputStream(String name) - 按照参数指定的路径构造对象。
   FileOutputStream(String name, boolean append)
       - 按照追加的方式构造对象与指定的路径关联。
   void write(int b) - 写入单个字节。
   void write(byte[] b, int off, int len) - 写入数组中的一部分字节数据。
   void write(byte[] b) - 写入整个数组的字节数据。   
   void flush() - 刷新输出流并强制写入缓冲数据。
   void close() - 关闭输出流并释放资源。

55.5 FileInputStream类(重点)
(1)基本概念
   java.io.FileInputStream类用于读取诸如图像之类的原始字节流。

(2)常用的方法
   FileInputStream(String name) - 根据参数指定的文件进行关联并创建对象。 
   int read() - 用于读取一个字节数据,返回-1表示读到文件末尾,否则返回数据。
   int read(byte[] b) - 用于读满整个字节数组。
       - 若读到文件尾就返回-1,否则返回实际读取的字节数。
   int read(byte[] b, int off, int len) - 用于读满字节数组的一部分空间。
   void close() - 关闭流并释放资源。

55.6 DataOutputStream类(熟悉)
(1)基本概念
   java.io.DataOutputStream类用于将java中的基本数据类型写入输出流中。

(2)常用的方法
   DataOutputStream(OutputStream out) - 根据参数指定的引用构造对象。
      - OutputStream类是一个抽象类,实参需要传递该类的子类对象。
   void writeInt(int v) - 用于将参数指定的整数写入输出流中。
   void flush() - 刷新输出流 
   void close() - 关闭输出流

55.7 DataInputStream类(熟悉)
(1)基本概念
   java.io.DataInputStream类用于读取java中的基本数据类型。

(2)常用的方法
   DataInputStream(InputStream in) - 根据参数指定的引用构造对象。
       - 引用是一个抽象类,实参需要传递子类的对象。
   int readInt() - 用于读取一个int类型的数据并返回。
   void close() - 关闭输入流。
  
55.8BufferedReader类(重点)
(1)基本概念
   java.io.BufferedReader类用于读取单个字符、字符数组、一行字符的数据。

(2)常用的方法    
   BufferedReader(Reader in) - 根据参数指定的引用构造对象。
     - Reader是个抽象类,实参传递子类的对象(InputStreamReader)。
   String readLine() - 用于读取一行文本。
   void close() - 关闭流对象并释放资源

55.9 PrintStream类(重点)
(1)基本概念
   java.io.PrintStream类用于打印各种数据内容。

(2)常用的方法  
   PrintStream(OutputStream out) - 根据参数指定的引用构造对象。
      - OutputStream类是个抽象类,实参需要传递子类的对象。
   void print(String s) - 打印参数指定的字符串。
   void println(String x) - 打印字符串并换行。
   void close() - 关闭流。 
   void flush() - 刷新流对象。

例子:
   不断地提示用户输入要发送的内容,每次读取用户输入的一行文字并写入到文件c:/a.txt中,要求使用上述一对流,当用户输入"bye"时结束程序(不考虑汉字)。
 
55.10 ObjectOutputStream类(重点)
(1)基本概念
   java.io.ObjectOutputStream类用于将一个对象整体写入到输出流中。
   只能将支持 java.io.Serializable 接口的对象写入流中。
   类通过实现 java.io.Serializable 接口以启用其序列化(将整个对象的所有信息转换为字节流信息的过程)功能。

(2)常用的方法
   ObjectOutputStream(OutputStream out) - 根据参数指定的引用构造对象。
      - OutputStream类是抽象类,实参传递该类的子类对象。
   void writeObject(Object obj) - 将参数指定的对象整体写入到流中。
   void flush() - 刷新流对象。
   void close() - 关闭流对象。

55.11 ObjectInputStream类
(1)基本概念
   java.io.ObjectInputStream类用于将文件的对象整体读取出来。

(2)常用的方法
   ObjectInputStream(InputStream in) - 根据参数指定的引用构造对象。
      - InputStream类是个抽象类,实参需要传递子类的对象。
   Object readObject()  - 用于读取输入流中的一个对象并返回。
      - 无法根据返回值来判断是否读取到文件的末尾。
   void close() - 关闭流对象。

经验:
   当需要向文件中写入多个对象时,通常的做法是先将所有被写入的对象放入一个集合中,然后将该集合整体看做一个对象写入文件中,此时读取文件中的内容时,只需要调用一次readObject()方法就可以全部读出。

56.线程(重点)
56.1 基本概念

   程序 - 存放在硬盘/磁盘上的可执行文件。
   进程 - 运行在内存中的程序。

   目前主流的操作系统都支持多进程,但进程是重量级的,新建进程对系统的资源消耗比较大,提供多进程是为了让操作系统同时执行多个任务。
   线程就是指进程内部的程序流,线程是轻量级的,新建线程对系统的资源消耗比较小,通常会共享所在进程的资源,以后的主流开发都采用多线程技术。
   操作系统中采用时间片轮转法来保证多个进程/线程并发执行,所谓的并发就是宏观并行,微观串行。
   目前主流的操作系统都支持多进程,可以让操作系统同时执行多个任务,进程是重量级的,新建进程对系统的资源消耗比较大。
   为了避免资源消耗过大,引出线程的概念,线程是进程内部的程序流,共享所在进程的系统资源,通俗来说,操作系统支持多进程,而每一个进程支持多线程。
   以后的主流的开发都采用多线程技术。

56.2 线程的创建(重点)
(1)Thread类的基本概念
   java.lang.Thread类用于创建线程对象,java虚拟机允许同时运行多个线程。
   创建和启动线程的主要方式:
       a.自定义类继承自Thread类,并重写run()方法,调用start()方法启动线程。
       b.自定义类实现Runnable接口,并重写run()方法,调用start()方法启动线程。

(2)Thread类的常用方法
   Thread() - 使用无参的形式构造线程对象。
   Thread(String name) - 使用参数指定的名称来构造线程对象。
   Thread(Runnable target) - 根据参数指定的接口引用来构造线程对象。
   Thread(Runnable target, String name) - 根据接口引用和线程名称共同构造对象。
   
   void run() - 若使用Runnable接口作为参数创建了线程对象,则调用该接口中被重写以后的run()方法;否则该方法什么也不做就直接返回。
   void start() - 使得线程启动起来,java虚拟机会自动调用该线程的run()方法。 
     
(3)线程的原理分析
   执行main()方法的线程叫做主线程,调用start()方法出现出来的线程叫做新/子线程
   对于start()方法之前的代码来说,只会被主线程自己执行一遍,而start()方法一旦调用成功,该进程中的线程瞬间由1个变成了2个,其中主线程继续执行start()方法之后的语句块,而新启动的子线程去执行run()方法中的语句块。
   当run()方法的方法体执行完毕时,子线程结束;当main()方法的方法体执行完毕时,主线程结束,主线程和子线程各自独立运行,没有执行的先后次序,取决于操作系统的调度算法。

经验:
   目前创建线程的方式有两种,第一种继承的方式代码相对简单但不支持多继承;第二种实现接口的方式代码相对复杂但可以多实现并单继承,因此以后开发中推荐使用第二种方式。

练习:
   使用匿名内部类的技术来实现上述两种创建和启动线程的方式。
  
56.3 线程的名称和编号
   long getId() - 用于返回当前线程的标识符/编号。
   String getName() - 用于返回当前线程的名称。
   void setName(String name) - 用于修改当前线程的名称。 
   static Thread currentThread() - 用于返回当前正在执行的线程对象的引用。

56.4 线程的主要状态(尽量理解)
   新建状态 - 当线程对象刚被创建出来的状态。
            - 此时线程并没有开始执行。
   就绪状态 - 当线程调用start()方法之后进入的状态。
            - 此时线程还是没有开始执行。
   运行状态 - 当线程调用调度器调度就绪状态的线程之后的状态
            - 当时间片执行完毕但任务没有完成时回到就绪状态
   消亡状态 - 当线程的任务已经完成时进入的状态。
   阻塞状态 - 当线程的执行过程中发生了阻塞事件(sleep)进入的状态。         
            - 当阻塞状态解除之后进入就绪状态。

56.5 线程的基本操作
   static void yield() - 用于暂停当前正在执行的线程,转而执行其他线程。
         - 让出CPU的执行权,回到就绪状态。
   static void sleep(long millis) - 让当前正在执行的线程休眠参数指定的毫秒。
   void interrupt() - 中断线程,通常用于打断睡眠。
   void join() - 等待当前线程终止,没有时间的限制。
   void join(long millis) - 最多等待当前线程参数指定的毫秒。
   void setPriority(int newPriority) - 更改线程的优先级。
   int getPriority() - 获取线程的优先级。
       - 优先级最高的线程不一定最先执行,只是获取时间片的机会更多一些而已。

掌握:
   sleep() 和 join()

57.线程的同步(重点)
复习:
   StringBuilder类 - 后期增加的类,非线程安全的类,效率比较高。
         - 不支持线程的同步技术。
   StringBuffer类 - 早期就有的类,线程安全的类,效率比较低。
         - 支持线程的同步技术。

57.1 基本概念
   当多个线程在同一时刻访问同一种共享资源时,可能会造成数据的不一致等问题,为了避免该问题的发生,就需要对线程之间进行协调和通信,而线程之间的协调和通信就是线程同步机制。

57.2 解决方案
   只需要将线程的并行改为串行就可以解决该问题。
   此时可以解决问题,但是效率相对比较低,因此建议能不用则不用。 

57.3 实现方法
   为了实现线程的同步,需要借助java中synchronized关键字来保证原子性,具体实现方式如下:
   (1)使用synchronized关键字修饰整个方法,语法格式:   
      访问修饰符 synchronized 返回值类型 方法名(形参列表){}
   (2)使用synchronized关键字修饰方法中的一部分代码,语法格式:
      synchronized(this){
         写入需要被锁定的语句块;
      } 

57.4 原理分析(尽量理解)
   当多个线程同时执行同一个方法时,为了避免线程之间的冲突问题,通常都会给该方法加上一把同步锁,当有线程先抢到同步锁时就可以进入同步语句块执行,其他线程只能进入阻塞状态,当该线程执行完毕同步语句块后会自动释放同步锁,阻塞的线程又可以抢占同步锁,抢占成功的线程去执行同步语句块,抢占不成功的线程继续阻塞。

57.5 死锁的发生
线程一执行的代码:
    public void run(){
        synchronized(a){      - 该线程持有对象锁a,等待对象锁b
           synachronized(b){
              ... ...
           }
        }
    }   

线程二执行的代码:
    public void run(){
        synchronized(b){      - 该线程持有对象锁b,等待对象锁a
           synachronized(a){
              ... ...
           }
        }
    }   

注意:
   切记尽量不要使用同步代码块的嵌套!

57.6 Object类中的方法
    void wait() - 用于让当前线程进入阻塞状态,直到其他线程调用notify()等方法,                   否则一直保持阻塞状态。
    void wait(long timeout) - 用于让当前线程进入阻塞状态,直到其他线程调用                       notify()等方法或者指定的时间到了,否则一直保持阻塞。
    void notify() - 用于解除当前对象锁上的单个线程的阻塞状态(随机)。
    void notifyAll() - 用于唤醒所有阻塞状态的线程。

58.网络编程的基本常识
   目前主流的网络通讯软件有:QQ、微信、支付宝、飞信、阿里旺旺、... ...

58.1 七层网络模型
   ISO(国际标准委员会组织)将数据的传递从逻辑上分为以下七层:
       应用层、表示层、会话层、传输层、网络层、数据链路层、物理层。
   当发送数据时,需要按照上述七层进行一层一层加包的操作,再发出去。
   当接收数据时,需要按照上述七层相反的次序一层层拆包,再解析出来。

58.2 IP地址(重点)
如:
   192.168.1.1 - 是绝大多数路由器的默认登录地址。
   
   在windows系统中查看IP地址的方式:在dos窗口中使用ipconfig命令或ipconfig/all
   在unix/linux系统中查看IP地址的方式:在终端中使用ifconfig命令。

   IP地址本质上是由32位二进制组成的整数,叫做ipv4,也有128位二进制组成的整数,叫做ipv6。
   日常生活中采用点分十进制表示法来进行IP地址的描述,也就是将每8位二进制转换为一个十进制整数,不同十进制整数之间采用小数点分隔。
   如:
       0x01020304 => 1.2.3.4
   为了便于IP地址的管理,将IP分为网络地址和主机地址两部分内容,其中网络地址可以定位到具体某一个子网中,而主机地址可以定位到该子网中的具体设备。
   IP地址是设备在互联网中的唯一地址标识,通过该IP地址可以找到设备。

58.3 端口号(重点)
   IP地址可以定位到具体某一台设备。
   端口号可以定位到设备中具体某一个进程。
   网络编程需要提供:IP地址 + 端口号。
   
   端口号本质就是由16位二进制组成的整数,范围是:0 ~ 65535,其中0 ~ 1024之间的端口号已经被系统占用,因此自己编程时从1025开始使用。

58.4 常见的网络协议
   http - 超文本传输协议
   ftp  - 文件传输协议
   tcp  - 传输控制协议
   udp  - 用户数据报协议
   ip   - 互联网协议
   ... ...

   协议 - 本质上就是一种约定/规则,用于描述不同主机之间通信的方式。

59.基于tcp协议的编程模型
59.1 相关的概念
  C(Client)/S(Server) - Client就是指客户端,Server就是指服务器。
  B(Browser)/S(Server) - Browser就是指浏览器,Server就是指服务器。
  Socket - 本意为"插座",在网络编程中叫做用于通信的逻辑载体,该逻辑载体中包含了IP地址和端口号。

59.2 编程模型(重点、套路)
服务器:
   (1)创建ServerSocket类型的对象,并提供端口号。
   (2)等待客户端的连接请求,使用accept()方法。
   (3)当客户端连接成功,则创建Socket对象使用输入输出流进行通信。
   (4)关闭Socket对象和ServerSocket对象。

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

59.3 相关类和方法的解析
(1)ServerSocket类
   java.net.ServerSocket类是用于创建服务器套接字对象,用于等待客户端的连接。
   ServerSocket(int port) - 创建于参数指定端口绑定的服务器套接字。
   Socket accept() - 用于监听并接收客户端的连接请求。
   void close() - 用于关闭服务器套接字。

(2)Socket类
   java.net.Socket类是用于创建客户端套接字对象,套接字是两台主机通信的端点。
   Socket(String host, int port) - 使用参数指定的IP地址和端口号进行对象的创建
   InputStream getInputStream() - 用于获取当前套接字的输入流。
   OutputStream getOutputStream() - 用于获取当前套接字的输出流。
   void close() - 关闭套接字。

60.tcp协议和udp协议的比较
60.1 tcp协议

  tcp协议 - 传输控制协议,是一种面向连接的协议,类似打电话。
          - 建立连接 => 进行通信 => 断开连接
          - 在通信的整个过程中全程保持连接
          - 保证了数据传递的可靠性和有序性
          - 是一种全双工的字节流通信方式
          - 服务器压力比较大,资源消耗比较高,发送数据效率低

60.2 udp协议
  udp协议 - 用户数据报协议,是一种非面向连接的协议,类似写信。
          - 在通信的整个过程中不需要保持连接
          - 不保证数据传递的可靠性和有序性
          - 是一种全双工的数据报通信方式
          - 服务器压力比较小,资源比较低,发送数据效率比较高

61.基于udp协议的编程模型(重点)
61.1 编程模型

发送方:
   (1)创建DatagramSocket类型的对象,不需要提供任何的信息。
   (2)创建DatagramPacket类型的对象,指定发送的内容、IP地址以及端口号。
   (3)发送数据,使用send()方法。
   (4)关闭相关的资源。

接收方:     
   (1)创建DatagramSocket类型的对象,并绑定指定的端口。
   (2)创建DatagramPacket类型的对象,用于接收发来的数据。
   (3)接收数据,使用receive()方法。
   (4)关闭相关的资源。

61.2 相关类和方法的解析
(1)DatagramSocket类
   DatagramSocket() - 使用无参的方式构造对象。
   DatagramSocket(int port) - 使用参数指定的端口来创建对象并绑定。
   void send(DatagramPacket p) - 发送参数指定的数据报。
   void receive(DatagramPacket p) - 接收数据存放到参数指定的数据报。
   void close() - 关闭套接字。
 
(2)DatagramPacket类
   DatagramPacket(byte[] buf, int length, InetAddress address, int port) 
     - 将参数指定的数据内容发送到参数指定的主机端口上。
   DatagramPacket(byte[] buf, int length)
     - 用于接收数据并存放到参数指定的位置上。
   InetAddress getAddress() - 用于获取发送方/接收方的IP地址。
   int getPort() - 用于获取发送方/接收方的端口号。
   int getLength() - 用于获取发送方/接收方的数据长度。

(3)InetAddress类
   static InetAddress getLocalHost() - 用于获取本机地址。
   static InetAddress getByName(String host) - 根据主机名获取地址信息。
   String getHostName() - 用于获取字符串形式的主机名。
   String getHostAddress() - 用于返回字符串形式的IP地址。

62.反射(尽量理解、难点)
62.1 基本概念

   反射本质上就是一种动态编程的技术,可以在运行阶段动态地创建对象以及动态地调用方法,具体由实参决定。
   目前主流的框架技术底层都是反射的机制,如:structs、spring、hibernate等
如:
    Person p = new Person();   -  只能创建Person类型的对象。
    Student s = new Student(); -  只能创建Student类型的对象。    
  
    void show(){}
    void show(int i){}
    void show(double d){}
    ... ...

62.2 Class类
(1)基本概念
   java.lang.Class类的实例代表应用程序的类和接口,通俗来说,就是该类的实例代表一种数据类型。
   该类没有公共的构造方法,该类的实例都是由java虚拟机和类加载器自动构造。

(2)Class对象的获取方式
   a.使用数据类型.class的方式可以获取该类型的Class对象。
   b.使用对象.getClass()的方式可以获取该类型的Class对象。
   c.使用包装类的TYPE属性获取该包装类对应基本数据类型的Class对象。
   d.使用Class类的forName()方法获取参数类型的Class对象。

(3)常用的方法
   static Class<?> forName(String className) - 获取参数指定类型的Class对象。
   T newInstance()  - 根据Class对象创建新实例。

   Constructor<T> getConstructor(Class<?>... parameterTypes) 
       - 用于获取当前Class对象对应类中指定的公共构造方法。
   Constructor<?>[] getConstructors() - 获取对应类中所有的公共构造方法。
   
   Field getDeclaredField(String name) - 获取对应类中指定的成员变量。
   Field[] getDeclaredFields() - 获取对应类中所有的成员变量。

   Method getMethod(String name, Class<?>... parameterTypes) 
      - 用于获取对应类中指定的公共成员方法。
   Method[] getMethods() 
      - 用于获取对应类中所有的公共成员方法。
   
62.3 Constructor类
   java.lang.reflect.Constructor类用于描述获取到的构造方法。
   T newInstance(Object... initargs) - 调用当前描述的构造方法去创建新实例。

62.4 Field类
   java.lang.reflect.Field类用于描述获取到的成员变量。
   Object get(Object obj) - 用于获取指定对象中此成员变量的数值。
   void setAccessible(boolean flag) - 参数为true表示可以访问私有成员。
   void set(Object obj, Object value) - 用于修改指定对象中当前成员变量的数值。

62.5 Method类
   java.lang.reflect.Method类用于描述获取到的成员方法。
   Object invoke(Object obj, Object... args) 
       - 用于obj对象调用当前方法,并传递args作为实参。    

62.6 JavaBean规范
   JavaBean本质上就是一种习惯性的编程风格,并不是绝对的编程规则或者语法要求,通常的习惯如下:
   (1)要求满足JavaBean规范的类必须放在一个包中。
   (2)要求满足JavaBean规范的类必须有无参构造方法。
   (3)要求满足JavaBean规范类中的成员变量都是私有的。
   (4)要求满足JavaBean规范类中提供公有的get和set方法。
   (5)要求满足JavaBean规范的类支持序列化接口。

63.常用的设计原则和设计模式(重点)
63.1 软件开发的流程
   需求设计/分析文档、概要设计文档、详细设计文档、编码、测试、安装和调试、维护和升级。
   职位的发展:初级软件工程师、中级软件工程师、高级软件工程师、系统架构师、
               项目经理/产品经理、讲师。 
               初级讲师、中级讲师、高级讲师、金牌讲师。

63.2 常用的设计原则
   开闭原则(OCP)- 对扩展开放,对修改关闭(bug 臭虫,任何软件都是bug的)。
                  - 实现热插拔的效果。
                  - 为了软件的扩展性比较好,易于维护和升级。
如:
   class Person{}
   class SubPerson extends Person{}
   
   里氏代换原则(LSP)- 任何父类可以出现的地方,子类一定可以出现。
                      - 子类 is a 父类。
如:
   class Shape{}
   class Rect extends Shape{}
   
   void draw(Shape s){  ... ...}
   draw(new Rect());
     
   依赖倒转原则(DIP)- 尽量依赖于抽象类,而不是具体实现类。
                      - 对子类具有强制性和规范性。
如:
   abstract class Person{ void show(); }
   class Student extends Person{ void show(){} }
 
   接口隔离原则(ISP) - 尽量依赖于小接口,而不是大接口。
                       - 为了升级和维护方便。
如:
   interface RunAnimal{
       void run();
   }
   interface FlyAnimal{
       void fly();
   }

   class Dog implements RunAnimal{ 
       void run(){ ...}      
   }
   class Bird implements FlyAnimal{
       void fly(){ ... }
   }

   迪米特法则(最少知道原则)(DP) 
     - 一个实体应当尽量少与其他实体之间发生相互作用,使得系统功能模块相对独立
     - 高内聚,低耦合。
     - 内聚就是指将一个实体的功能尽量聚集在该实体的内部。
     - 耦合就是指一个实体与其他实体之间的关联度。
   
   合成复用原则(CRP)- 尽量使用合成的方式,而不是继承。
如:
   class A{ void show(){ ...}  ... }
   class B extends A{
        
   }

   class B{
      A a;
   }

63.3.设计模式
   1.1 概念 
         被人反复使用     多数人知晓的  经过分类的    代码设计经验的总结 
   1.2 分类 
          创建模式    工厂模式  抽象工厂模式     单例模式  ... 
          结构模式    装饰器模式    代理模式     组合模式 ... 
          行为模式    模板模式    观察者模式、迭代子模式 ...
   1.3 工厂模式 
         简单工厂模式       根据一个字符串 得到对应的对象  
         工厂方法模式       一个工厂中有多个方法(生产线)  
                                    这里有个问题 就是要得到对应的产品 必须先创建一个工厂对象
         静态工厂模式       把工厂中的方法变成静态的方法 
                                    (增加生产线 就会改动工厂  这样违反开闭原则)
         抽象工厂模式       指定建造工厂的规范  每个工厂生产一种产品   这样 增加新产品 就意味
                                    着增加新的工厂 。

    1.4 单例模式
          程序中使用时推荐使用   饿汉式    
          笔试中考察比较多的是 懒汉式    如果没有特殊规定 建议 饿汉式 
     1.5 装饰器模式  
          对一个方法的功能 进行增强 
          增强一个方法的功能  大家可以使用 继承      
                   long   timeStart =  ...;
                   super.method(); 
                   timeEnd - timeStart
     1.6  代理模式   和 组合模式
64.常用的查找算法 
  64.1 线性查找
          从一个数列中 依次查找数据  和  目标元素做对比  如果相等就返回对应的位置  
          如果不相等就继续和下一个数据比较  直到查找结束。
          
          设计一个方法 可以从一个整数 数组中 查找一个整数数据的位置  如果找到了这个数据在数组
                 中的位置 就返回数组对应的下标  如果找不到就返回 -1
           
  64.2 二分查找
         要求数列有序,为了书写方便 假设数列是升序。
         先传入 左侧下标  和 右侧下标  然后 计算出中间下标    取出中间下标对应的值 和 目标元素比较
         如果中间值相等 就返回对应下标  
         如果中间值大了  就去左侧查找  查找范围   左侧下标 到  中间下标-1 这个范围内重复这个查找过程
         如果中间值小了  就去右侧查找   查找范围   中间下标+1  到 右侧下标    
         找不到 返回  -1 
         int   binarySearch(int[] datas,int left,int right,int target);
                 
65.常用的排序算法
  65.1 冒泡排序 (50%)
          1.让相邻的两个元素比较   如果满足交换条件   就交换元素位置  如果不满足交换条件 
             就继续下一次比较
          2.重复步骤 直到这一轮交换 完成   就 完成了第一轮交换 效果是找出了最大值 或者最小值
          3.进行第二轮 重复第一轮的步骤   上面的过程要进行  n -1  轮 就完成了 

          int[]  datas  =  {9,5,2,7,0};
          优化: 
          让相邻的元素比较   发现本轮没有交换时   就结束排序 
          
          不使用中间变量  来交换数据?       0111
          a   b                                a = 9   1001           b  =  7    0111   
          a =  a ^ b;                      a =      1110
          b  = a ^ b;                      b =      1001
          a  = a ^ b;                       a =      0111                

  65.2 快速排序 (30%)   升序 
         1.先算出中间下标位置   然后取出中间下标对应的值  单独保存 
         2.先从左侧开始 和  中间下标对应的值 做比较  如果比中间小 就放左边(不用动了) 
            如果比中间值大就放右边(中间下标记录位置)  
         3.重复上面的逻辑   使用递归 

           

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值