当前位置: 首页 > backend >正文

Java基础

三、Java基础

1. Java

1.1 什么是Java?

  1. Java
    • Java是由sun公司发明的
    • Java之父:James Gosling
    • Java开发团队:*7(星号7)
    • Java诞生记:Green -> Oak(橡树)-> Java
      • 1991年Sun公司的James Gosling等人开始为“绿色计划”研发一种全新的可跨平台的语言
      • 1994年将本想命名为Oak的语言更名为Java
      • Sun Microsystems于1995年正式发布Java
      • 一句话定义:1995年SUN公司倡导的James Gosling发明的面向对象的可跨平台的类的语言
  2. Sun公司
    • SUN:Stanford University Network
    • Sun公司名字由来
      • SUN公司是斯坦福联合网络学院创办的
      • SUN是由斯坦福联合网络学院的首字母缩写组成
    • SUN公司在发明Java之前是研发Solaris(Linux操作系统的一个版本)和Sparc(CPU)
      • Solaris + Sqarc = 工作站
    • 08年10亿美金收购mysql
    • 10年74亿被甲骨文收购
  3. Java的优缺点
    • 优点
      • 平台无关、面向对象、无指针、分布式应用、多线程开发、自动收集内存
    • 缺点
      • 运行速度慢、占用资源多、复杂
      • 中间字节码需要二次编译,解释执行
      • JVM占用资源多
      • 无指针无法直接操作内存
      • 垃圾回收线程占用资源,不能实时手机内存

1.2 Java与Internet

  • Java基于网络写业务逻辑
  • Internet使Java更广泛,Java对Internet具有深远影响
  • 在Java出现之前,web只能展现静态的文字、图片等内容,是java让web能够与用户动态的交互
  • Applet程序可以对用户的出入和操作做出响应
  • D/SC/S
    • D/S:基于web浏览器应用
    • C/S:基于客户端应用

1.3 Java的三个分支

  1. SE
    - SE:Standard Edition标准编译器,完整保留
  2. EE
    • EE:Enterprise Edition企业级编译器
    • EJB(企业级Javabean)被淘汰,9种变13种,改名为Web开发
    • 现在说的Java EE指的是快速开发框架,代替了淘汰的EJB功能
  3. ME
    • ME:Mobile Rdition移动编译器,完全被淘汰

1.4 语言执行的三种方式

1.4.1 编译执行
  • 源代码一次性被翻译成机器码,然后直接在计算机上执行
  • 缺点:无法跨平台
  • 优点:速度快
  • 如:C语言
1.4.2 转译执行
  • 编写一段源代码,在不同的平台或环境中都可以执行
  • 一次编写到处执行
  • 如:html、JavaScript
1.4.3 中间码+虚拟机
  • 源代码被翻译成中间码,然后通过虚拟机执行
  • 虚拟机是一个可以解释执行中间码的程序,通常用于解决跨平台执行的问题
  • 一次编译到处执行
  • 如:Java

1.5 Java的跨平台

  1. 平台

    • CPU + 操作系统 = 平台

    • 硬平台:CPU

      • 不同的CPU指的是CPU上搭载的不同的指令集
      • CPU指令集:CPU中用来计算和控制计算机系统的一套指令的集合,每种CPU都有其特定的指令集
      • 指令集分类

        Windows操作系统只认CISC指令集
        IOS操作系统即认CISC指令集,又认RISC指令集

        • CISC指令集:Intel、AMD
        • RISC指令集:PowerPC
    • 软平台:操作系统

      • 操作系统是充当用户和计算机之间交互的界面软件,不同的操作系统支持不同的CPU(CPU指令集)
      • 操作系统分类:windows操作系统、 Linux操作系统/Mac操作系统

        三种主流的操作系统都支持CISC指令集

  2. 跨平台

    • 跨平台指的是编译以后可以跨平台
    • 只有编译后才知道是“谁”的东西
    • 所有的源程序都可以跨平台,但是不会将源程序给别人
  3. 跨平台原理

    • 不能编译成机器语言,因为那样就与平台相关了,先编译成中间码,再将中间码由解释器二次编译,解释执行,二次编译后就不能跨平台了
    • C语言的“不跨平台”
      • .c源程序:编译以后不能跨平台
        • winNT编译器(VS):编译生成winNT程序
        • Linux编译器(GCC、ICC):编译生成Linux程序
        • 其他OS编译器:编译生成其他OS程序
    • Java的“跨平台”
      • .java源程序:一次编译到处执行
        • 先编译成.class中间字节码,再通过编译器二次编译(解释)生成对应的程序
          • winNT编译器(VS):二次编译生成winNT程序
          • Linux编译器(GCC、ICC):二次编译生成Linux程序
          • 其他OS编译器:二次编译生成其他OS程序
      • 一次编译:与平台无关的编译器生成与平台无关的中间码
      • 二次编译(解释):解释器是与平台相关的

2. JDK

2.1 JDK的组成

  • JDK:Java Development Kit(Java开发工具包)
  • JDK = Java编译器 + Java解释器 + 其他组件
  • 开发Java需要从源文件到中间字节码的编译器
  • 运行Java需要Java解释器
  • JRE:运行时环境(只运行Java可以只使用它)
  • JDK:运行 + 开发时的环境(包括JRE)

2.2 JDK的部署

  1. JDK的安装路径:C:\Program Files\Java(默认的)在这里插入图片描述
  2. 配置环境变量
    • JDK的安装目录:JAVA_HOME,配置的是JDK的安装根目录(此处使用的自定义的JDK安装路径,不是默认安装路径)
      在这里插入图片描述

    • 类路径:CLASSPASH,配置的是安装根目录下面的lib目录下面的dt.jartoos.jar(需要先配置“.”)
      在这里插入图片描述在这里插入图片描述

    • 编译工具路径:PATH,配置的是java安装根路径下的bin目录(此处的%JAVA_HOME指的是前面JDK的安装目录)在这里插入图片描述在这里插入图片描述

2.3 JDK的包

  1. db:全世界最小的数据库Derby
  2. demo:有关样例,不影响使用
  3. sample:有关样例,不影响使用
  4. bin:Java的JDK编译命令(程序员使用的命令)
  5. include:JDK与底层操作系统(Windows)打交道的东西(Java底层自己使用的)
  6. lib:Java在操作系统 (Windows)上要执行的类库(Java底层自己使用的)
  7. jre:运行时环境,只运行Java可以只使用它
  8. src.zip:Java源码压缩包在这里插入图片描述

2.4 常用的cmd命令

  • cmd:打开命令提示符
  • java:执行命令
    • 如:java MyClass(MyClass是Java程序的类名)
  • javac:编译命令
    • 如:javac MyClass.java (MyClass.java是源代码文件)
  • javadoc:查看Java文档
    • 如:javadoc MyClass.java (MyClass.java是源代码文件,会生成相应的文档)
  • cd..:返回上一层文件夹
  • cd:进入下一层文件夹
  • d:进入盘符d

2.5 JVM、JRE、SDK

  1. JVM:Java虚拟机(Java Virtual Machine),包括类加载器、字节码校验器、Java解释器
  2. JRE:运行时环境,包括JVM和Java运行支持的类库
  3. Java SDK:Java Software develop kit,Java的另一个称呼

3. IDE和Eclipse

3.1 IDE

  1. IDE:Integerted Development Environment集成开发环境
  2. IDE包括代码编辑器、编译器、调试器和图形用户界面工具
  3. IDE集成了代码编写功能、分析功能、编译功能、调试功能等一体化 的开发软件套
  4. 任何语言都要经过编辑、编译和调试
  5. 常用的IDE工具:IDEA、Jbuilder、NetBeans、Eclipse

3.2 Eclipse

源于IBM的优秀的开源的可扩展的插件化的IDE工具

  1. 工作空间(工作区)

    • 本质是个文件夹,Java所写的所有项目都在里面
      在这里插入图片描述

    • 可以有不同的工作区,里面放不同的项目

    • 运行Eclipse的基本单位

    • Eclipse配置信息基于工作空间,%eclipseHome&\configuration\.setting设置工作空间基本信息
      在这里插入图片描述

  2. 源文件夹和目标文件夹

    • JVM识别的是目标文件夹,将源文件夹里的文件进行编译后,产生的.class文件就会自动进入目标文件夹
    • 目标文件夹的结构会根据源文件的结构而一摸一样的创建
    • 保存就编译,源文件只有在源文件夹里才会被编译
    • 分类
      • 源文件夹src):放源文件的(.java文件
      • 目标文件夹bin或classes):放目标文件的(.class文件),默认为bin
    • Eclipse中先建源文件夹,再建包,再建类,如果没有包,则是默认包,会出现问题的
    • 所有的包都以com开头,用 . 隔开 ,不能个中文
    • 包本质就是一级又一级的文件夹
  3. 快捷键

    • Crtl + S :保存 + 编译(Eclipse中保存就编译)
    • Alt + ?快捷键:自动生成
  4. 保存项目的三种方式

    • 备份工作空间
      • 优点:保存配置信息
      • 缺点:文件过大
    • 备份项目
    • 只备份源文件
      • 优点:文件最小

4. 基础语法

4.1 常量与变量

作用域常量与C语言不同外,其余一摸一样,可看 C语言基础 中的6. 次小编程单元(数据类型)

java只有一般常量,无符号常量。
  1. 常量

    Java中只有一般常量,无符号常量,可以用finally修饰变量,来达到符号常量的用处

    public finally int NUMBER = 10;
    
    • 什么是常量?
      • 常量:在程序中值不能改变的量
    • 常量分类
      • 一般常量:不能变的常量
      • 数值常量,如:10
        • 字符常量,如:‘a’
        • 字符串常量,如:“OK”
  2. 变量

    作用域外都与C语言一摸一样,但是C语言中的变量必须先声明在使用,且变量的声明语句必须在函数的开始处。

    • 什么是变量?
      • 在程序中,其值可以改变的量
      • 变量的本质是一片连续的内存空间
      • 变量是一个最小的、离散的、不带结构的容器,用来存放数据
    • 变量的使用
      • 变量必须先声明后使用
      • 方式:
        • 方式一:声明语句:类型 变量名;
          执行语句:变量名 = 初始值;
          int a;
          a = 10;
          
        • 方式二:声明初始化语句:类型 变量名 = 初始化;
          int a = 10
          
    • 变量的命名规则
      • 变量必须由数字字母下划线(_)组成,且字母下划线开头
      • 变量必须见名之意,且首字母小写
      • 变量不能和关键字重名,且大小写敏感
    • 变量作用域 :从定义的地方开始一直到所在的块的结束(与C语言不一样)

4.2 数据类型

分类与C语言不同外,其余一摸一样,可看 C语言基础 中的7.最小的编程单元
C语言中的数据类型 + byte类型 + boolean类型 = Java的基本数据类型

  1. 什么是数据类型?
    • 什么样的数据就用什么样的类型来存

    • 约束内存空间的大小

    • 数据类型代替运算法则

       例如:10+10=20“10” + “10” = 1010
      
  2. 数据类型的分类
    • 基本数据类型
      • 数值型
        • 整数类型:byteintshortlong
        • 浮点类型:floatdouble
      • 字符型:char
        • 字符数据存储的时候是把其ASCII码存储在内存中
        • ‘a’ ~ ‘z’:97 ~ 122
        • ‘A’ ~ ‘Z’:65 ~ 90
        • ‘0’ ~ ‘9’:48 ~ 57
      • 布尔型:booleantrue为真、false为假
    • 引用数据类型:类(class)、接口(interface)、数组
      • 引用数据类型在使用时传递的是地址
  3. 类型转换
    与C语言一摸一样,但是java中一般用于引用数据类型的转换,同时对象类型的不能自动类型转换
    • 自动类型转换
      • 原则:把表示范围小的类型转换成表示范围大的类型的值
      • short -> int -> long -> float -> double
    • 强制类型转换
      • 原则:把表示范围大的类型转换成表示范围小的类型的值
      • 语法:类型名 变量或数值
        int a = 1;
        double b = 1.5;
        int c = (int)b + a;
        
      • 强转类型转换可能出现的问题:丢失精度、乱码、一运行就死机

4.3 运算符

与C语言一摸一样,可看 C语言基础 中的11.运算符

  1. 表达式
    • 表达式 = 操作数 + 运算符
    • 操作数:由常量、变量和子表达式组成
    • 由什么样的运算符组成的表达式就叫什么表达式
  2. 分类
    与java一样,但java返回值是ture和false
    1. 算数运算符
      • 分类
        • 一元运算符:由一个操作数组成,如:“++”、“--

        • 二元运算符:由两个操作数组成,如: “+”、“-”、“*”、“/”、“%

            "/":当除号两边都是整型时,结果是整型的商; 当除号两边有一个实型或者两个都是实型,结果是精确的值;"%":两边必须是整型
          
      • 运算符前缀:操作数在后面(先操作后使用),如:++a
      • 运算符后缀:操作数在前面(先使用后操作),如:a++
    2. 赋值运算符
      - =+=-=*=/=%=
    3. 关系运算符(比较运算符)
      • <<=!=>>===
      • 返回值是true,falsefalse代表假,true代表真)
    4. 逻辑运算符
      • 用于连接一个或多个条件,判断是否成立
      • 分类:
        • 与(&&):一假即假
        • 或(||):一真即真
        • 非(!):取反
  3. 运算符优先级
    • 从左到右依次降低:() --> !,++,--,sizeof --> *,/,% --> +,- --> <,<=,>,>= --> ==,!= --> && --> || --> =,+=,*=,/=,%=,-=

4.4 结构化(顺序、分支、循环)

与C语言一摸一样,可看 C语言基础 中的10.结构化

  1. 顺序结构
    在这里插入图片描述

  2. 分支选择结构

    • 单分支结构
      • 简单单分支
        if() {}
        
      • 标准单分支
        if() {} else {}
        
    • 多分支结构
      • 否定式:否定了第一个条件,才能进入下一个条件

          switch能做的多重if都能做,但是多重if能做的,switch不一定能做,因为多重if可以处理连续的范围,但是switch只能处理离散得到的点。
        
        • 多重if:相当于第一次成立的单选
          if () {} else if () {} else {}
          
        • switch结构:
          switch() {case 1:111;break;case 2:222;break;default:	000;break;
          }
          
          注意事项:
          • 只能处理离散的点,不能处理连续的范围
          • case的顺序可以调换,但是case不可以重复
          • break可以不写,语法不会报错,但是逻辑有问题
          • default可以省略,相当于多重if里面没有最后的else
          • switch的参数必须是整型的,可以是常量、变量、表达式
          • case后面的数必须是整型常量
      • 肯定式(递进式):肯定了第一个条件,才能进入下一个条件,相当于第一次不成立的单选

        if() {if() {if() {} else {}} else {}
        } else {}
        
  3. 循环结构

    • 循环分类
      1. 当型循环
        在这里插入图片描述
      • 先判断后执行
      • 分类:
        • while循环:一般用在未知次数的当型循环
          while() {}
          
        • for循环:一般用于已知次数的当型循环
          for(表达式1,表达式2,表达式3) {}
          
      1. 直到型循环
        在这里插入图片描述
      • do...while循环:先执行后判断
        do {} while();
        

4.5 数组

  1. 数组概念
    • 什么是数组?
      • 一堆数据放在一起简称数组
      • 数组是一段连续的有序的并存储类型相同的单元
      • 数组是一个带结构的大容器,用来存放小容器
    • 什么是变量?
      • 值可以改变的量称为变量
      • 变量的本质是一段连续的内存单元
      • 变量是一个离散的容器,用来存储数据
  2. 一维数组
    • 数组大小
      • 在声明语句结束之前,存储大小必须确定
      • 数组大小是存储整型常量
    • 数组下标(索引)
      • 下标从0开始,一直到存储大小减1,且中间是连续的
      • 数组下标可以是整型常量、变量、表达式
    • 命名方式
      • 静态初始化(声明初始化)
        • 方式一:int 数组名[10] = {1,2,3,4}
        • 方法二:int 数组名[4] = {1,2,3,4}
        • 方法三:int 数组名[] = {1,2,3,4,}
      • 动态初始化(先声明,后赋值)
        • int 数组名[10]; 数组名[0]= 1; 数组名[1]=2
  3. 二维数组
    • 定义
      • 把一个数组套在另一个数组里面,且每一层的结构相同,类型也相同
      • 可以理解为行列矩阵,前面的[]代表行,后面的[]代表列
    • 命名方式
      • 静态初始化:类型名 数组名[size][size]={{},{}}(第一个size可以不用写,推荐写上)
      • 动态初始化:一般使用for循环嵌套进行初始化

4.6 冒泡排序

  • 定义:每一轮把要比的数据的最大的数据冒到最后面

  • 外层循环

    • 外层循环比的是排序的次数
    • 外层循环每进行一次,数组中要比的数据的最大值就被确定了
    • 外层循环次数一般为arr.length - 1数组长度 - 1
  • 内层循环

    • 内层循环比的是未确定元素比较的次数
    • 内层循环负责不确定数据的比较和位置是否交换
    • 内层循环次数一般为arr.length - i - 1数组长度 - 外层循环已经排序的次数 - 1
  • 代码示例:

    public static void main(String[] args) {int[] num = {10, 25, 65, 45, 9};//冒泡排序for(int i = 0; i < num.length - 1; i++) {for(int j = 0; j < num.length - i - 1; j++) {if(num[j] > num[j + 1]) {int temp = num[j];num[j] = num[j + 1];num[j + 1] = temp;}}}for(int i = 0; i < num.length; i++) {System.out.print(num[i] + "  ");}
    }
    

4.7 二分查找

  • 前提:二分查找前提数据必须是有序

  • 定义:二分查找是将待查找的元素与数组中间位置的元素进行比较,从而确定待查找元素存在的位置间,然后在区间中继续进行查找,直到找到目标元素或确定目标元素不存在为止

  • 索引

    • 开始索引:start = 0;
    • 结束索引:end = arr.length - 1;
    • 中间索引:middle = (start + end)/ 2;
  • 循环退出条件为:start > end开始索引大于结束索引

  • 代码示例:

    public static void main(String[] args) {// 二分查找//排序int[] arr = {12, 45, 56, 48, 89, 456, 48, 56, 25, 2};for(int i = 0; i < arr.length - 1; i++) {for(int j = 0; j < arr.length - i - 1; j++) {if(arr[j] > arr[j + 1]) {int temp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = temp;}}}//查找int num = 0;int start, end, middle;start = 0;end = arr.length - 1;while(true) {middle = (start + end) / 2;if(arr[middle] > num) {end = middle - 1;} else if(arr[middle] < num) {start = middle + 1;} else if(arr[middle] == num) {System.out.println("找到了,该数是" + arr[middle] + ",位置是" + (middle + 1));break;}if(start > end) {System.out.println("很抱歉,该数不存在!");break;}}
    }
    

5. 类和对象

5.1 面向对象(OOP

  1. 什么是面向对象?
    • OOP:Object Oriented Programming,面向对象编程
    • 面向对象不是技术,而是一个主流的先进的编程思想
    • 面向对象关注的是做事情的主体(这些主体就是对象),即谁在做
  2. 面向对象宗旨
    • 用计算机中的对象(实体)来模拟现实世界中的对象(实体)
    • 能够用计算机中实体模拟现实世界中的实体
  3. Everything is object!
    • OOP中现实世界的所有东西都被视为对象
    • 面向对象世界是主观模型(主观世界)
    • 面向对象世界是人们抽象过得认识到以后得概念模型组成的

5.2 类和对象

  1. 如何描述事物?
    • 现实生活中的任何事物,我们都可以用属性(状态)(特征)和方法(行为)(功能)来描述它
      • 属性 - 方法
      • 特性 - 功能
      • 状态 - 行为
  2. 属性和方法
    • 什么是属性?
      • 属性是事物(类)(对象)本身的特征,用来描述它的状态
    • 什么是方法?
      • 方法(行为)用来说明这个事物(类)(对象)所具有的功能
  3. 什么是对象(类)?
    • :具有相同属性和方法的一组对象(实例)(个体)的集合
  4. 什么是对象(实例)?
    • 实例:符合某一类标准的事物的具体的一个个体
  5. 类和实例的关系
    • 类是主观模型,实例是客观模型
    • 类是抽象的,实例是具体的
    • 类是模糊的,实例是清晰的
    • 类是个模子模型,实例是在这个模子里面诞生的个体
    • OOP世界是由类组成,而真真正正存在的世界由实例组成
  6. 类与面向对象编程的关系
    • 类是现实世界的实体(实体类)
    • 类是面向对象编程的核心
    • 类可以完成特定的任务
    • 类是现代应用程序的基础

5.3 类的实现

  1. 类的语法

    • 语法:class 类名 { 类体 }
      public class Student{}
      
  2. 类的命名规则

    和变量的命名规则类似,但是变量的首字母小写

    • 必须由数字字母下划线组成,并且下划线字母开头
    • 必须见名知意,且首字母大写
    • 不能和关键字重名,且大小写敏感
  3. 类的定义

    • 属性

      • 属性是事物本身的特征,用来描述它的功能
      • 如何实现类里面的属性?
        • 类中的属性就由写在类体里的变量来充当
        • 属性名称被所有类的实例所共享
      • 属性的命名规则
        • 必须由数字字母下划线组成,并且下划线字母开头
        • 必须见名知意,且首字母小写
        • 不能和关键字重名,且大小写敏感
        class  Person {String  name = null;int  age = -1;String  sex = null;
        }
        
    • 方法

      与C语言中的函数一样

      • 方法是事物本身所具有的功能

      • 如何实现类里面的方法?

        • 类中的方法就是写在类体里面的函数
      • 方法的语法:返回值类型 方法名(参数){ 方法体 }

        void  eat() {System.out.println("吃东西");
        }
        
  4. 类的使用

    • 使用:先让该类开空间new),然后用实例名空间的别名)+“.”调用类里面的属性方法
      Student student = new Student();
      student.study();//调用学生学习方法
      System.out.println(student.name + student.age);//输出学生名字和年龄
      
    • new 关键字
      • new就是开空间
      • 定义完一个类后,无论类里代码的多少,new之前都不开空间
      • 见到了new就开了空间,没见new就没开空间
      • 在运行过程中,没有new,会报错空指针异常
    • 点操作符
      • " . " 操作符
      • " . "的前面是实例的名字,“ . ”的后面是类里面的属性方法
      • 类的实例+“ . ”操作符 可以调用类里面的属性和方法

5.4 构造方法

  1. 什么是构造方法?
    • 构造方法:方法的名字和类名完全相同且没有返回值类型
      public class Student() {public String name;//空参构造Student() {方法体}//实参构造Student(String name) {this.name = name;方法体}
      }
      
  2. 构造方法的作用
    • 语法作用
      • 让类能够new(开辟空间)
    • 业务逻辑作用
      • 在开辟空间的过程中想做的事情都写在构造方法中
      • 一般来说是初始化的作用
  3. 构造方法的调用时机
    • 构造方法也是方法,符合方法的调用规则:见到名字就调用
    • new的时候自动调用,传什么样的参数就调什么样的构造方法
  4. 构造方法的分类
    • 不带参的构造方法(隐式构造方法
      • 只能有一个
      • 当一个类里面没有任何的构造方法,系统会提供个默认的空参空方法体的构造方法,只能用来进行语法作用
    • 带参的构造方法(显式构造方法)(逻辑构造方法
      • 可以有好多个,理论上可以有200多个
      • 参数的个数和类型不同就是不同的构造方法
      • 当一个类里面有构造方法,写了谁就是谁,没写的构造方法就没有,系统不再提供默认的空参方法

6. 包和封装

6.1 命令行参数

  • 命令行参数(启动时参数)(运行时参数):String[] args
  • 在程序运行的过程中,可以通过传递命令行参数,将信息传递至main()方法中
  • 启动虚拟机(启动main()方法)的时候要添加参数时使用的
  • 如:有一个Java程序,可以接收两个整数作为命令行参数,并将它们相加并输出结果
    public class CommandArgsExample {public static void main(String[] args) {if (args.length < 2) {System.out.println("请输入两个整数作为参数");return;}int num1 = Integer.parseInt(args[0]);int num2 = Integer.parseInt(args[1]);int sum = num1 + num2;System.out.println("相加结果为: " + sum);//30}
    }
    
    使用命令行工具运行这个程序:将整数1020作为参数传递给main()方法
    java CommandArgsExample 10 20
    

6.2 包(package)和导包import

  1. 什么是个包(java里面的包)?

    • 包的本质是在硬盘上的文件夹,具有文件夹的功能
    • 包是Java命名机制的一部分
      • 包名是类名的一部分
      • 虚拟机在找类时,找的是包名 + 类名
        • 例如:com.itheima.test1.Person,其中com.itheima.test1包名Person类名
    • 导包
      • 该类需要用到不同包下面的类时,这个类在能够看到(访问修饰符允许访问)的情况下,必须要导包
      • 导包关键字:import
        import com.itheima.test1.Person
      • 完整路径名
        public com.itheima.test1.Person p1 = null
    • 包是封装机制的一部分
      • 封装 = + 访问修饰符
      • 封装必须用访问修饰符联合起来作用的
  2. package 关键字

    • 定义包使用package包路径
      package com.likou.text;
      
  3. import 关键字

    • 导入包使用import包路径
    • 使用异包下面的类都要导包
      import java.util.ArrayList;
      
  4. 包的命名

    • 公司网络域名的反转,如:淘宝的数据库:com.taobao.db

6.3 Static静态修饰符

static方法static代码块是属于级别的,而不是具体对象的实例级别。因此在静态方法或静态代码块中是不能使用this关键字的,因为this代表当前对象的引用,而静态方法或静态代码块是在类加载时就被调用,此时还没有具体的对象实例存在

  1. 成员化

    • 成员属性
    • 成员方法
    • 只有new出来(开辟空间),才能使用成员属性成员方法
  2. static

    • 可以修饰属性,也可以修饰方法,但是不能修饰
      public class Student{public static String name;public static void print() {System.out.println(name);}
      }
      
    • 实例名也可以调用静态修饰的东西,但是一般都是直接类名 + “.” 调用
      public static void do() {Student student = new Student();student.print();//实例名调用Student.print();//类名调用
      }
      
  3. 静态属性(类属性)

    • static修饰符修饰的属性就叫静态属性
      public static String name = null
    • 静态属性和成员属性的区别
      • 成员属性必须new(开空间)后才能使用
      • 静态属性不new就可以使用,即类名 + “.“ 就可以使用
      • 保存类的信息,一般就放在static里面
  4. 静态方法

    • static修饰符修饰的方法就叫静态方法
  5. 为什么 类名 + “.” 就可以用?

    • 因为成员化的东西必须new完开空间了后才能使用,而静态的东西,只要类编译器通过,那么静态的东西就开空间了(静态池中)
    • 成员化的东西自己调用自己,自己改变,别人访问的值不会改变;静态修饰的东西强调只有一份,共享一片空间,自己改变,别人访问的值也随之改变
    • 静态池
      • Java虚拟机中存在好多池(大概8.9个),静态池是其中一种
      • 静态池是Java虚拟机启动就存在

6.4 封装

  1. 封装
    • 有选择的提供数据叫做封装(记这个)
    • 隐藏事物内部的实现细节叫做封装
    • 特征
      • 对象的特征:属性方法
      • 面向对象特征:封装继承多态
    • 封装的优点
      • 内部的修改不影响外部的使用
      • 防止外界误修改程序单元
      • 对象使用变得更简单
  2. 访问修饰符
    • 作用:限制的是访问的作用(范围)
    • 分类
      • private:私有的
        • 只有本类内部可以访问
      • 默认(default)
        • 本类可以访问
        • 同包下的类可以访问
      • protected:受保护的
        • 本类可以访问
        • 同包下的类可以访问
        • 异包下的子类可以访问
      • public:公共的
        • 本类可以访问
        • 同包下的类可以访问
        • 异包下的子类可以访问
        • 异包下的非子类可以访问
  3. 访问属性和方法的两种场景
    • 本类的内部访问
      • 不需要new,直接用
    • 本类的外部访问
      • 将该类new出来(开辟空间),然后实例名+“.”访问该类里面的属性和方法
  4. 实体类
    • 现实生活里的物体对应的是实体,实体在数据库里是,在Java里对应,Java里面的类对应程序设计里面的表,这样的类称为实体类
    • 实体类的名字和表的名字一摸一样,不过要首字母大写
    • 表里面有什么样的字段,实体类里面就得有什么的属性,名字与数据类型一摸一样,但是访问修饰符必须是私有的private
  5. 访问器
    • set方法
      • 给私有属性赋值
        public  void  setId_stu (String  id_stu){this.id_stu = id_stu;
        }
        
    • get方法
      • 获取私有属性的值
        public  String  getId_stu (){return  this.id_stu;
        }
        

7. 方法重写和继承

7.1 继承

  1. 继承
    • 继承(派生):在一个类的基础上生成一个新类
    • 子类:新生成的类
    • 父类(超类):原来的那个类
  2. 继承的优点
    • 提高代码的复用性
    • 父类的属性方法可以用于子类
    • 可以轻松定义子类
    • 使设计应用程序变得简单

7.2 继承语法要点

  1. Java中由extends关键字来实现
    public class Son extends Father {}
    
  2. 父子关系是相对
    • 在Java里,只能认识相邻的两代
    • 父类就代表了祖先,继承了所有祖先类的属性和方法
    • 父类只能认识子类,子类只能认识父类
  3. 继承关系由“子类是父类”确定
    • 例如:老虎是动物(老虎是子类,动物是父类)
  4. Java中只有单继承
    • 一个儿子只有一个父亲
    • 一个父亲可以有多个儿子
    • 好处:Java的子类不管经过多少代,都可以追根溯源

7.3 方法重写(overwrite)

  1. 子类可以拥有父类的属性和方法(私有的暂时无法使用)
  2. 子类可以有自己的属性和方法
  3. 子类可以重写覆盖父类的方法
    • 属性也可以被重写(覆盖),但是重写属性没有意义
    • 方法重写(overwrite):子类的访问修饰符的访问要大于父类的
      • 方法重写:在子类里面有一个和父类方法原型部分完全相同的方法,但是有不同的方法体
      • 方法原型返回值类型 + 方法名 + 参数,与修饰符无关
      • 方法重写后,外部调用就分不清子类和父类了,无论怎么调用,调用的都是子类
      • 方法重写后,内部调用依旧可以分清子类和父类,用this调用子类,用super调用父类
        public class Father{public void run() {System.out.println("我每天要跑10公里");}
        }
        public class Son extends Father{@overwritepublic void run() {System.out.println("我每天要跑5公里");}
        }
        
  4. 可以声明父类,创建子类(用父类装载子类
    • 父类能出现的地方,子类一定能出来(装载)(向上转型
      • 子类转化成父类:new的是子类,接的是父类类型
        父类:Father;子类:Son
        Father  f = new  Son()
    • 特点:
      1. 声明什么类型(拿什么类型的实例名),就只能调用什么类型的属性和方法
        父类:Father;子类:Son
        Father f = new Son()
        • 声明的是Father类型,将子类类型的Son转化成了父类类型的Father,开的是Son的空间,里面存放的是Son的属性和方法,但是拿Father类型来接的,因此只能调用Father类型里面的属性和方法。
      2. 创建什么类型的空间,就真正运行的什么类型的方法(前提要方法重写+装载
        • 没有重写时,父类就是父类的方法,子类就是子类的方法
        • 方法重写+重载后,调用的是父类的方法,完成的是子类的功能
        • 子类重写父类方法时,当创建了子类的空间,却拿了父类的类型去接(装载),当调用父类中被子类重写的方法时,调用的是父类方法的原型,但是实现的是子类重写方法的功能。(因为子类重写的方法已经将父类的方法覆盖了)
          父类:Father	      父类方法:method( );
          子类:Son	      子类方法:method( );(重写父类的method)Father f = new Son()
          • 当调用father类型里面的method方法时,调用的是父类的方法,实现的却是子类method的功能,因为子类的method方法的已经将父类的method方法覆盖了。
      3. 创建的什么类型的空间,就可以强转为什么类型强转)(向下转型
        • 父类转化成子类
          父类:Father;子类:Son
          Father  f = new Son()Son  s  =Son)f;
          
          • 在这段代码中,FatherSon的父类,且将一个Son类型的实例(空间)赋给了Father类型f。因此,可以将Father类型f 强制转换为Son类型实例 s ,因为s本类就是Son类型的空间,只不过之前是拿Father类型接受的。

7.4 属性和方法的调用方式

  1. 当自己的属性名和父类一样时,不加this或者super时,编译器会优先调用自己
  2. 内部调用
    • 调用属性
      • this:调用本类属性
      • super:调用父类属性
      • 什么都不加:表示传递的参数
    • 调用方法
      • this:调用本类方法
      • super:调用父类方法
  3. 外部调用
    • 实例名 + “ . ”(但是看不出来哪些是父类的哪些是自己的)
    • 方法重写后,实例名 + “ . ” 只能调用子类

7.5 thissuper

  1. this
    • this:指向当前对象的引用
    • this表明调用本类声明的属性和方法
    • this使用在构造方法中表示调用本类其它构造方法
  2. super
    • super:指向当前对象的父引用
    • super表示调用父类声明的属性和方法

7.6 继承中的构造方法

  1. 情况一
    • 当调用子类的构造方法,诞生自己的空间之前,父类的空间也已经诞生了
    • 当调用子类时,传什么样的参数,调用什么样的构造器
    • 无论怎样构造子类的空间,都会以默认的方法(super())构造父类
      public class Animal {public Animal() {System.out.println("父类Animal的构造方法被调用");}
      }public class Dog extends Animal {public Dog() {System.out.println("子类Dog的无参构造方法被调用");}public Dog(String name) {System.out.println("子类Dog的带参构造方法被调用,参数为:" + name);}
      }public class Main {public static void main(String[] args) {// 调用子类Dog的无参构造方法Dog dog1 = new Dog();// 输出:// 父类Animal的构造方法被调用// 子类Dog的无参构造方法被调用System.out.println("------------------");// 调用子类Dog的带参构造方法Dog dog2 = new Dog("旺财");// 输出:// 父类Animal的构造方法被调用// 子类Dog的带参构造方法被调用,参数为:旺财}
      }
      
  2. 情况二
    • 当子类在构造自己时,需要以某一种显示的方法构造父类,就需在子类构造器的第一句按照子类的意愿去调用父类的构造器。
      class Parent {private int num;public Parent(int num) {this.num = num;System.out.println("Parent: " + this.num);}
      }class Child extends Parent {private String name;public Child(int num, String name) {super(num); // 调用父类的构造方法this.name = name;System.out.println("Child: " + this.name);}
      }public class Main {public static void main(String[] args) {Child child = new Child(10, "Alice");}
      }
      
  3. 情况三
    • 如果父类没有隐式构造器,这时必须在子类每一个构造器的第一句都显示的调用父类有的构造器
      class Animal {private String name;public Animal(String name) {this.name = name;}
      }class Dog extends Animal {private String breed;public Dog(String name, String breed) {super(name);//显示的调用父类有的构造器this.breed = breed;}
      }class Cat extends Animal {private String color;public Cat(String name, String color) {super(name);//显示的调用父类有的构造器this.color = color;}
      }
      

8. 方法重载和多态

8.1 方法重载

  1. 方法重载overload):一个类里面有若干个名字相同而参数(类型或者个数)不同的方法

  2. 要点

    • 与参数名无关

      public void T1(int a){}
      public void T1(int b){return  "方法重载"}
      
    • 与返回值类型无关

      public void T1(int a){}
      public String T1(double b){return  "方法重载"}
      
    • 与修饰符无关

      public void T1(int a){}
      private void T1(double b){}
      
    • 父子类方法也可以重载

      public class Person{public void T1(int a){}
      }public class Student extends Person{ public void T1(double b){ }
      }
      
  3. 构造方法是一种特殊的方法重载

    public class Student{private String name;private int age;private String gender;public Student() {}public Student(String name) {this.name = name;}public Student(String name,int age) {this.name = name;this.age = age;}public Student(String name, int age, String gender) {this.name = name;this.age = age;this.gender = gender;}
    }
    

8.2 多态

  1. 多态可以理解为“多种形态”的意思
  2. 多态:同一个物体(实例)在不同的情况下,表现出来的不同的状态
  3. 多态在代码中表现为调用同样的方法,每次调用条件不一样,所实现的功能就不一样
  4. 多态一般用方法重载方法重写来实现的
    • 方法重载:在一个类中将其它类表示成方法的参数,在使用时当传递不同的参数(对象)就会调用该类中对应的方法。
      1class  T2class  A;
      类3class  B;
      类4class  C;
      类5class  Run;类1中的方法:方法1public void method() { };方法2public void method(A  a){ };方法3public void method(B  b){ };方法4public void method(C  c){ };5中的代码:T  t = new  T();t.method(new A());//调用的是类1中的方法2
      
    • 方法重写:一般让父类装载子类创建子类的空间,用父类来接),调用父类的方法,实现子类重写后的功能
      父类:class H2o;
      子类1class GuTaiShui extends H2o;
      子类2class Water extends H2o;
      子类3class YeTaiShui extends H2o;父类方法:public void showType() { };
      子类1方法:public void showType() { };
      子类2方法:public void showType() { };
      子类3方法:public void showType() { };测试类:class  Run;
      测试类代码:H2o  h2o  =  null;h2o  =  new Water();h2o.showType();//调用的是子类2中的方法
      

8.3 StaticFinal修饰符

  1. static修饰符
    • 静态属性
      • static修饰的属性叫做静态属性
    • 静态方法
      • static修饰的方法叫做静态方法
      • 任何方法都不开空间
      • 特性
        • 特性一:静态方法跟类绑定,可以用类名 + “ . ” 直接调用,不需要new出来(类编译通过了,static方法就有了,但是不开空间
        • 特性二:静态方法只能调用静态成员,不能调用非静态成员(在调用静态方法时,非静态的东西还不存在)
        • 特性三:在静态方法中,不能有this和superthis和super是成员化的东西,指的是单独的,而static是和类绑定的,指的是共有的
      • static静态强调只有一份
      • static只能修饰属性和方法,不能修饰变量和类
  2. final修饰符
    • final强调最终的,不可改变
    • 特点
      • 特点一:final修饰变量,变量就变成常量(C语言中的符号常量在Java中用final充当)
        public final int NUMBER = 10;
        
      • 特点二:final修饰方法,方法就不能被重写
      • 特点三:final修饰类,类就不能被继承(一旦类被final修饰,里面的所有方法都会变成隐式的final方法
  3. static和final联合修饰属性
    • 因为属性是final,所以加个static
    • 因为属性是final,不能变的值,如果让每一个实例都来一遍这个值,又不能变,就会浪费空间,所以加个static,让所有的实例都共享这一片空间
      public static final int NUMBER = 10;
      

8.4 程序的内存分配

程序的本质:正在运行的一片内存空间

8.4.1 C语言开空间
  • C语言程序直接向硬盘要空间
  • 通过指针开空间
8.4.2 Java开空间
  • Java程序问JVM(虚拟机)要空间,JVM再问硬盘要空间
  • JVM开空间的过程:只要虚拟机一启动,不管运行没运行,JVM都会向硬盘请求一部分空间(初始空间
    1. 初始内存分配:当程序准备执行时,虚拟机会向操作系统申请分配内存,操作系统会返回内存(初始内存)给JVM,然后JVM会在初始内存中分配内存给程序
      在这里插入图片描述
      在这里插入图片描述
    2. 分配更多内存:当初始内存用完时,程序向JVM请求需要更多的内存,JVM向操作系统申请内存,操作系统分配内存返回给JVM,JVM会在初始内存+后续分配的内存中进行内存分配后,返回给程序
      在这里插入图片描述
      在这里插入图片描述
    3. 分配内存达到上限:程序接着向JVM请求需要更多内存,JVM发现内存已经达到设置的上限(JVM默认为64M),不再向操作系统请求,而是直接通知内存溢出,返回给程序
      在这里插入图片描述 在这里插入图片描述
8.4.3 谁在占用空间?
  1. 类的结构
    • 方法区在JVM启动时就有了
    • 类的结构定义时就在方法区开空间。(并没有单独给类里面的属性和方法开空间,是给类的整体开的空间,相当于是个模子)
    • 如果类里面也有静态成员,静态成员也在静态池中开空间。(静态池位于方法区中
    • 所有的方法都只开一份空间(在方法区中),所有的成员共享方法区里该方法的模子
  2. 变量的名字(实例名、基本数据类型变量名、引用数据类型变量名)
    • 变量的名字在里面开空间
  3. new出来的对象(实例
    • new的东西在里面开空间

8.5 引用

  • 在Java中,引用是指一个对象的内存地址,它可以用来访问对象的属性和方法
  • 在Java中,所有的对象都是通过引用来操作的
  • 当你创建一个对象时,实际上是在内存中分配了一块空间,并返回了该空间的引用。这个引用可以被赋值给一个变量,然后通过该变量来操作对象
  • 在Java中,引用对象是分开的,对象(new出来的)存在于堆内存中,而引用则存在于栈内存中

9. 抽象和接口

9.1 传递和交换

9.1.1 传递
  1. 值传递:拷贝的是
    • 值传递:直接在里面值的拷贝,改变新的值,旧的值不变(方法里面变了,方法外面不变)
    • 基本数据类型:直接在栈里面拷贝值,做不到方法里面改变,外面值就改变(因为在栈里面做的是值的拷贝
  2. 引用传递:拷贝的是里面的引用
    • 传递是让栈里面的多个引用指向了堆里面同一片空间(方法里面的引用指向的空间改了,方法外面的引用指向的空间也改了)
    • 在栈里面拷贝的是引用的地址,这些地址指向堆里面同一片空间,通过改变栈里面新的引用指向的空间,也能改变原来的那片空间
    • 数组
      public class  Text1 {public void method(int[]  arr){for(int i = 0; i < arr.length; i++) {arr[i]++;}}
      }
      public class  Run {public static void main(String[] args) {int[] num = {1, 2, 3};Test1 text = new Test1();text.method(num);for(int i = 0; i < num.length; i++) {System.out.print(num[i] + " ");//2,3,4}}
      }
      
      • 在测试类中定义了个数组num;将num传递给方法method的参数arr,使得arr的地址=num的地址
      • method方法中将arr数组遍历并+1
      • 在测试类中遍历输出数组num的值发现每个都+1了。
      • 改变了method方法里arr数组的值,测试类中num数组的值跟着改变。
      • arr=numarr拷贝的是num的地址,使得numarr指向同一片空间,改变方法里arr指向的那一片空间,方法外num指向的那一片空间也发生了改变
    • 对象
      public class  Person{ public String name = null;public int age = -1;public void showMe() {System.out.println(this.name + "//" + this.age);}
      }
      public class Text1 { public void method(Person  person){person.name = "改变";person.age++;}
      }
      public class  Run { public static void main(String[] args) {Person p = new Person("張飛", 10);Test1 text = new Test1();text.method( p);p.showMe();//改变,11}
      }
      
      • 在测试类中创建了个Person的对象;将person对象p传递给方法method的参数person,使得person的地址=p的地址
      • method方法中将person所指向空间的名字改为“改变”,年龄+1
      • 在测试类中调用Person类的showMe方法,发现原来空间名字改为“改变”,年龄+1了。
      • 改变了method方法里person所指向空间的名字和年龄,测试类中原来的对象p所指向空间的值跟着改变。
      • person=pperson拷贝的是p的地址,使得pperson指向同一片空间,改变方法里person指向的那一片空间,方法外p指向的那一片空间也发生了改变
  3. Java在运算的时候,始终在里面进行操作(Java虚拟机在底层设计时,栈的操作速度快)
9.1.2 交换
  • Java的交换是在里面将引用进行交换,引用所指向的空间没有变(方法运行结束,栈里面的空间就被释放)
  • Java可以通过引用改变引用所指向空间()的值
    • 引用是指向该堆内存空间的地址
    • 当我们通过引用修改对象或数据时,实际上是在修改堆内存空间中的内容
    • 这种方式可以实现数据的修改,但不能实现引用的交换。
  • Java不能通过引用交换引用所指向空间()的值
    • 在Java中,引用是指向对象或数据的地址,而不是对象或数据本身
    • 当我们将两个引用进行交换时,实际上是交换了两个引用在栈中的存储位置,而不是交换了引用所指向的堆内存空间的内容
    • 因此,在Java中,通过交换引用来交换堆内存空间的值是不可行的。

9.2 抽象(abstract)

9.2.1 抽象方法
  • 抽象方法:用abstract修饰的方法
  • 性质
    • 抽象方法不能有方法的实现(不能有花括号),只能有声明
    • 抽象方法只能写在抽象类
      public abstract void draw();
      
9.2.2 抽象类
  • 抽象类:用abstract修饰的类
  • 性质
    • 抽象类里面可以有一般的属性和方法
    • 抽象类里面可以有抽象方法,也可以没有抽象方法
    • 抽象类不能被实例化(new),只能被继承
    • 如果一个类继承了一个抽象类,那么子类就必须要重写抽象类里所有的抽象方法(如果抽象方法没有重写完,那么将子类也变成抽象类)
      public abstract class Shape {}
      
9.2.3 抽象的作用
  • 作用:强制父子类之间的语法关系
    • 对于子类:子类想要继承父类(抽象类),就必须完成父类的中规定的方法
    • 对于父类:有些类是概念性的,不应该被new出来,只能被继承,如:人,人是抽象出现的,概念性的东西,不应该new出来
  • 构造方法、static方法、final方法不能是抽象的
    // 定义一个抽象类
    public abstract class Shape {// 定义一个抽象方法public abstract void draw();
    }// 具体实现类
    public class Circle extends Shape {@Overridepublic void draw() {System.out.println("画一个圆形");}
    }// 测试类
    public class Main {public static void main(String[] args) {Shape circle = new Circle();circle.draw();}
    }
    

9.3 接口

9.3.1 什么是接口?
  1. 为什么要有接口?
    • Java里面只有单继承,没有多继承
    • Java用接口来模拟多继承,达到多继承的效果,使子类的功能更丰富
  2. 什么是接口?
    • 接口就是用interface来定义的Java文件(Java对象),类就是class定义的Java文件
    • 接口从本质上来讲是个纯虚的抽象类
      • 接口里面可以定义属性,但是所有的属性都是常量(隐式的添加了static final
      • 接口里面可以定义方法,但是所有方法都是隐式的抽象方法(只能有方法声明,不能有方法实现)
    • 接口就是功能(接口里面放的一般都是方法)
      • 面向对象不关心方法的体,只关心方法原型
      • 只要在调用时能调到接口里的方法,就表明这个接口有这个功能
9.3.2 接口的使用
  1. 定义接口(interface

    public interface StudentService{void add();void delete();void find();
    }
    
  2. 类可以实现接口(implements

    • 类实现接口可以多实现
    • 当一个类实现了一个接口,就必须重写这个接口里所有的方法(如果方法没有重写完,那么将该类也变成抽象类)
    • 接口不能实例化,但是可以声明一个接口让它指向一个实现自己的类
    • 可以使用这个实现了接口的类,这时候此类的实例已经具备了接口中的属性和方法
      public class doService implements StudentService, TeacherService, WorkService {}
      
  3. 接口可以继承接口(extends

    • 接口可以多继承
      public interface StudentService extends StudentDao, StudentUtil {}
      
9.3.3 面向接口编程
  • 面向接口编程就是面向功能编程
  • 实现某个接口所定义的功能
  • 在工程开发过程中合理的使用接口可以提高程序的开发效率,使程序更易于维护
  • 接口往往用来完成一些功能,可以把它当作半个类使用
9.3.4 接口实现多态
  • 接口的引用指向实现类的实例
  • 拿谁的引用就调谁里面的属性和方法

10. Java.lang包

10.1 API

  1. 什么是API?
    • API:Application Programming Interface,应用程序编程接口(入口)
  2. 什么是API文档?
    • 所有的java类对象的说明书
  3. 什么是java包
    • 将API里的对象以功能的不同,分门别类的放到不同的包里面
  4. 什么是lang包
    • 利用java进行程序设计的基础类(默认类)
    • lang包
      • lang包:java的基础包(默认包)
      • lang包里有java最基础的类(对象)
      • lang包不需要导包就可以用
  5. 标准包
    • java.lang包:包含java最基础的类,可以直接在程序中使用这些类,不需要引入包
    • java.io包:包含支持输入/输出操作的类
    • java.awt包:支持java图形化用户界面的类(GUI)
    • java.util包:包含一系列标准操作以管理数据集、访问日期以及分析字符串的类
    • java.util.zip包:包含支持生成 .jar 文件的类
    • java.sql包:包含支持使用标准sql的数据库访问功能的类
    • javax.swing包:(Java扩展包)提供支持GUI组件的类,推荐使用

10.2 包装类

10.2.1 数据包装类
  1. java的不纯洁性
    • java不是纯粹的面向对象的语言
    • java里有两个地方不面向对象
      • main()方法不面向对象
      • java里的8个基本数据类型不面向对象
  2. 为什么要使用数据包装类
    • java为了解决8个基本数据类型的不纯粹性,java就给每一个数据类型设计了一个对应的包装类
    • 为了把不是对象的基本数据类当做对象来用
      void getAge(Object  o){ }
      
10.2.2 分类
  1. 数值型
    • byte(字节):Byte
    • int(整型):Interger
    • long(长整型):Long
    • short(短整型):Short
    • float(浮点型):Float
    • double(双精度):Double
  2. 非数值型
    • char(字符型):Character
    • boolean(布尔型):Boolean
10.2.3 装箱和拆箱

以后所有的强制类型转换都用包装类来实现

double num = 10.01;
Double num1  = new Double(num);
int num2 = num1.intValue();
  1. 装箱
    • 基本数据类型变成对象型
    • 方法一:一般用构造方法来装箱
      包装类型 实例名 = new 包装类型 (基类型数据)
      int a1 = 1;
      Integer num1 = new Integer(a1);
      
    • 方法二:包装类型 实例名 = 包装类型 . valueOf(基类型)
      int a = 10;
      Interger aa = Interger.valueOf(a);
      
  2. 拆箱
    • 对象型变成基本数据类型
    • 对象名 . 基类型Value()方法
      Integer num1 = new Integer(10);
      int a2 = num1.intValue();
      
10.2.4 数值型的常用方法
  1. 基类型变成包类型(基类型一般为String):包装类型 实例名 = 包装类型 . valueOf(基类型)

    静态方法,返回值是包类型

    Interger aa = Interger.valueOf("10");
    
  2. 基类型转换成另一个基类型包装类型 . parse基类型(String)

    静态方法,返回值是基类型

    int i = Interger.parseInt("10");
    
  3. 包类型String实例名 . toString()

    返回值是String

    Interger i =  new Interger(10);
    String s = i.toString();
    
10.2.5 字符型Character常用方法

都是静态方法,返回值是boolean

  • isDigit():确定字符是否为0~9之间的数字
    boolean b1 = Character.isDigit('1');
    
  • isLetter():确定字符是否为字母
    boolean b2 = Character.isLetter('c');
    
  • isLowerCase():确定字符是否为小写形式
    boolean b3 = Character.isLowerCase('c');
    
  • isUpperCase():确定字符是否为大写形式
    boolean b4 = Character.isUpperCase('A');
    
  • isSpace():确定字符是否为空格换行符
    boolean b5 = Character.isSpace('\n');
    

10.3 String类

String类final修饰,不能被继承

10.3.1 字符串面量和对象
  1. 字符串面量(字面量)(字符串池
    • 没有new的String变量
      String s = "OK";
      
    • 任何时候创建字符串字面量,系统都会搜素字符串池,查看是否存在该字符串字面量
  2. 对象
    • 见到new的String
      String str = new String("OK");
      
  3. 区别
    • 字符串对象new出来的就是里面的空间,然后用里面的引用去引。(每一次new出来的对象所指向的空间都不同
    • 不带new的变量在面量池中开空间(如果两个变量的值相同,那么这两个变量指向面量池中同一片空间
    • 如果引用相等,那么值一定相等;但是值相等,引用却不一定相等
    • 如果是面量就是多个引用指向同一片空间,如果是对象就是不同的引用指向不同的空间
10.3.2 String常用的构造方法
  1. String():创建一个空字符串
  2. String(String value):创建一个字符串作为指定字符串的副本
  3. String(char[] value):根据字符串数组构造一个新字符串
  4. String(byte[] value):通过转换指定的字节数组新建一个字符串
10.3.3 String常用方法
  1. 字符串的长度:字符串 . length()
    int a = "akfhakfn".length();
    
  2. 字符串比较
    • == ”:恒等比的是引用
      s1 == s2
      
    • equals()方法:equals比的是具体的值(大小写敏感)
      s1.equals(s2)
      
    • compareTo()方法:一样的返回0,不一样的返回第一个不一样的先后顺序
      "abc".compareTo("abc")//返回0
      "abc".compareTo("abd")//返回-1
      
    • startsWith()方法:检查是否以该字符串开头
      "abcd".startsWith("a")
      
    • endsWith()方法:检查是否以该字符串结尾
      "abcd".endsWith("cd")
      
  3. 字符串提取
    • charAt()方法:在字符串里面根据索引提取字符(索引从0开始)
      "abcdefg".charAt(0)//返回值是a
      
    • substring()方法:根据索引截取字符串前要后不要)(索引从0开始)
      "abcdefg".substring(0, 5) // 返回值是abcde
      
    • replace()方法:字符串替换(替换的是字符
      "abcdecfg".replace('c', 'o') //返回值是abodeofg
      
    • replaceAll()方法:字符串替换(替换的是字符串
      "abcdefg".replaceAll("abc", "wxo") //返回值是wxodefg
      
    • trim()方法:去除空格(只去除开头和结尾的空格)
      "   a b c".trim() //返回值是a b c
      
    • concat()方法:字符串拼接
      "abc".concat("def")//返回值是abcdef
      
  4. 更改字符串的大小写
    • toUpperCase()方法:将小写字符转换成大写字符
      "Hello".toUpperCase()//返回值是HELLO
      
    • toLowerCase()方法:将大写字符转换成小写字符
      "HELLO".toLowerCase() //返回值是hello
      
  5. 字符串分割
    • split()方法:字符串根据方法的参数分割开
      String s5 = "ab,cd,ef";
      String[] arr = s5.split(",");
      
10.3.4 String不变性
  1. String:不可变的字符序列
    • String的空间一旦开好了无论发生什么都不变了
    • 缺点:效率低、浪费空间
  2. StringBuffer
    • String的对等类
    • 表示可增加和可编写字符的可变序列
    • 将字符插入到字符串中间或附加到字符串末尾
    • StringBuffer的常用方法
      • append()方法:向StringBuffer里添加字符串
        StringBuffer sb = new StringBuffer(“ok“);
        sb.append("ok");
        
      • toString()方法:将StringBuffer转换成String
        StringBuffer sb = new StringBuffer(“ok”);
        sb.append("ok");
        System.out.println(sb.toString()); //返回值是okok
        

10.4 Math类

Math类final修饰,不能被继承

  • Math常用方法:(静态方法)
    • double sqrt (double x):计算x的平方根
    • double pow (double x, double y):计算x的y次方根
    • double ceil( double x):求不小于x的最小整数,并以double的形式显示(进一法)
    • double floor (double x ):求不大于x的最大整数,并以double的形式显示(退一法)

10.5 Object类

10.5.1 Object类
  1. Object类是所有类的父类(老祖宗类)(超类)
  2. 所有的java类都会拥有Object类里面所有的方法
10.5.2 Object常用方法
  1. toString()方法

    • 未重写的toString显示的是类名+@+类的空间地址
    • 重写后的toString显示的是重写的内容,而不是地址
  2. equrse()方法

    • 未重写的equrse()方法比较的是引用
    • 重写的equrse()方法比较的是内容
    • 重写了equrse()方法,就必须重写hashCode()方法
      @Override
      public boolean equals(Object obj) {if(obj == null) {return false;}if(!(obj instanceof Student)) {return false;}Student temp = (Student)obj;if(!(temp.name.equals(this.name))) {return false;}return true;
      }
      
      • instanceof用于判断obj是不是Student的实例
  3. hashCode()方法

    • hashCode:拿地址根据哈希值进行运算
    • 未重写的hashCode比较的是引用
    • 重写后的hashCode比较的是内容
  4. finalize()方法(析构方法

    具体请看 Java基础的12.垃圾回收机制

    • 如果存在finalize()方法,它将在垃圾收集之前被执行一次,而且每个对象仅执行一次,用于执行最终消亡之前的一些操作
    • 消亡就调用finalize()方法
    • 不推荐使用,因为它的执行时机是不确定的,不能保证对象何时会被垃圾回收
      public class FinalizeExample {@Overrideprotected void finalize() throws Throwable {try {// 执行清理操作System.out.println("Finalizing object...");} finally {super.finalize();}}public static void main(String[] args) {FinalizeExample obj = new FinalizeExample();// 让对象变成垃圾obj = null;// 强制执行垃圾回收System.gc();}
      }
      

10.6 Class类

  • Class类:类的描述器,类的类
  • Class类包装正在运行类的运行状态及信息,可用来动态加载类,得到类的实例

11. 异常

11.1 异常处理

  1. 定义
    • 异常就是不同寻常的事情。
    • 一切不寻常的事情都是异常(包括错误)
    • 错误是异常,但是异常不一定都是错误
  2. 分类
    • Error类(错误)(不可控的)
    • Exception类(异常)(可控的)
      • 编译时异常
        • 必须处理,不处理代码就无法运行
        • Ecxeption下面除了RuntimeException以外的直接子类都是编译时异常
      • RuntimeException类运行时异常):写代码时可以忽略
  3. Error类对象Java虚拟机生成并输出,Exception类对象应用程序处理或抛出

11.2 常见异常

  1. Java中的常见异常
    • Throwable类:所有异常类型都是内置类Throwable的子类
    • Error类:用于Java运行时系统来显示与运行时系统本身有关的错误
    • Exception类:用于用户程序可能捕获的异常,也是用来创建用户类子类的类
  2. 类层次结构图
    在这里插入图片描述
  3. 常见的异常
异常类型描述
RuntimeException异常Java.lang包中多数异常的基类
ArithmeticException异常算术错误,例如除以0
IllegalArgumentException异常方法收到非法参数
ArrayIndexOutOfBoundsException异常数组下标出界
NullPointerException异常空指针异常
ClassNotFoundException异常不能加载请求的类
AWTException异常AWT中的异常
IOException异常I/O异常的根类
FileNotFoundException异常不能找到文件
EOFException异常文件结束
NoSuchMethodException异常请求的方法不存在
InterruptedException异常线程中断

11.3 异常处理机制

11.3.1 异常处理
  • 异常处理是方法级别的东西
  • 异常处理指的是能够进行处理的异常(Exception异常)
11.3.2 直接处理

关键字:trycatchfinal

  1. try代码块

    • 包含可能引起一个或多个异常的代码
    • try块中遇到第一次错误时,try块中错误以后的代码就不执行了,直接跳转到catch块中寻找与之对应的异常
    • try代码块里面必须有能发生异常的语句
      String s1 = null;
      try {System.out.println(s1.toString());
      } catch(NullPointerException e){System.out.println("发生了异常");
      }
      
    • 把将要发生异常的一个整体的业务逻辑放在try块里,然后跟对应数目的catch块
      try {String s1 = null;System.out.println(s1.toString());System.out.println(10 / 0);int[] num = { 1, 2, 3 };System.out.println(num[3]);
      } 
      
  2. catch代码块

    • 包含计划用于处理一个特定异常类型的代码
    • catch块的数目要与try块中异常的数目相对应,位置可以互换
      try {String s1 = null;System.out.println(s1.toString());System.out.println(10 / 0);int[] num = { 1, 2, 3 };System.out.println(num[3]);
      } catch (NullPointerException e) {System.out.println("发生了异常");
      } catch (ArithmeticException e) {System.out.println("发生了异常");
      } catch (ArrayIndexOutOfBoundsException e) {System.out.println("发生了异常");
      }
      
    • catch块可以是try块中所有异常的父类
      try {String s1 = null;System.out.println(s1.toString());System.out.println(10 / 0);int[] num = { 1, 2, 3 };System.out.println(num[3]);
      } catch (Exception e) {System.out.println("发生了Exception");
      }
      
    • try块里面有多个异常时,catch块中可以有与try块异常对应的catch块,也可以有try块中其他异常的父类,但是父类的catch块必须在子类的后面
      try {String s1 = null;System.out.println(s1.toString());System.out.println(10 / 0);int[] num = { 1, 2, 3 };System.out.println(num[3]);
      } catch(NullPointerException e) {System.out.println("发生了异常");
      } catch (Exception e) {System.out.println("发生了Exception");
      }
      
  3. finally代码块

    • 在方法结束之前必须执行的代码
    • 无论如何都会执行的代码
    • finally块try块一起使用
    • 一个try、catch结构只能带一个finally
      try {Class.forName("com.k10.ccc");System.out.println("com.k10.ccc");
      } catch (ClassNotFoundException e) {throw e;
      } finally {System.out.println("必须执行的代码");
      }
      
11.3.3 向上抛出
  1. 注意点
    • 方法后面写不写throwscatch块里写不写throw没有关系,而是和catch块中异常的种类有关编译时异常必须写throws,运行时异常可写可不写
    • 调用处写不写try、catch与方法处写不写throws没有关系,而是与方法处throws异常的种类有关编译时异常,外面必须捕获,运行时异常可以捕获可以不捕获
    • 对于方法内写不写throw、throws,调用处要不要捕获,只与异常的种类有关编译时异常,都必须写;运行时异常,都可写可不写
    • 判断的不是写没写关键字,而是看上一次是什么类型的异常
  2. 关键字
    • 关键字:throwthrows(但是向上抛出前必须先try、catch捕获异常)
    • throw关键字
      • 使用throw语句可以在catch块中将异常抛出给调用处
      • throw前面的代码可以执行,后面的代码都不执行了
    • throws关键字
      • 使用throws可以在方法声明部分添加异常类型,表明该方法可能出现的异常
  3. 标准规范:throw了什么异常,方法就应该throws该异常,表明该方法可能会抛出该异常,调用处应该对异常进行捕获并处理(有throw,有throws,调用处有捕获
    public void t1() throws ClassNotFoundException {try {Class.forName("com.k10.ccc");System.out.println("com.k10.ccc");} catch (ClassNotFoundException e) {throw e;}	
    }
    

11.4 抛出异常的种类

11.4.1 编译时异常
  • 如果catch块中是编译时异常,则应该throw编译时异常,方法处必须throws该异常,调用处必须进行捕获
11.4.2 运行时异常
  • 如果catch块中是运行时异常,则应该throw运行时异常,方法处可以throws该异常,也可以不throws,调用处可以进行捕获,也可以不进行捕获
  • 不规范情况
    1. 情况一:有throw,没throws,调用处有捕获
      • throw后面的代码不执行,直接调转到调用处,由于调用处进行了捕获,调用处处后面的代码依次照常执行
        public class Text01 {public void t1() {System.out.println("t1开始了");try {System.out.println(10 / 0);} catch (ArithmeticException e) {throw e;}System.out.println("t1结束了");}
        }public class Main01 {public static void main(String[] args) {System.out.println("main开始了");Text01 text01 = new Text01();try {text01.t1();} catch (ArithmeticException e) {System.out.println("main捕获到了ArithmeticException");}System.out.println("main结束了");}
        }
        //输出结果
        //main开始了
        //t1开始了
        //main捕获到了ArithmeticException
        //main结束了
        
    2. 情况二:有throw,没throws,调用处没捕获
      • throw后面的代码不执行,直接调转到调用处,由于调用处没有捕获,直接调转到编译器,由编译器控制
        public class Text02 {public void t2() {System.out.println("t2开始了");try {System.out.println(10 / 0);} catch (ArithmeticException e) {throw e;}System.out.println("t2结束了");}
        }public class Main02 {public static void main(String[] args) {System.out.println("main开始了");Text02 text02 = new Text02();text02.t2();System.out.println("main结束了");}
        }
        //输出结果
        //main开始了
        //t2开始了
        //Exception in thread "main" java.lang.ArithmeticException: / by zero
        //at com.k11.text02.Text02.t2(Text02.java:9)
        //at com.k11.text02.Main02.main(Main02.java:10)
        
    3. 情况三:没throw,有throws,调用处有捕获(相当于直接处理,无论有没有捕获,代码依次照常运行)
      public class Text01 {public void t1() throws ArithmeticException{System.out.println("t1开始了");try {System.out.println(10 / 0);} catch (ArithmeticException e) {}System.out.println("t1结束了");}
      }public class Main01 {public static void main(String[] args) {System.out.println("main开始了");Text01 text01 = new Text01();try {text01.t1();} catch (ArithmeticException e) {System.out.println("main捕获到了ArithmeticException");}System.out.println("main结束了");}
      }
      //输出结果
      //main开始了
      //t1开始了
      //t1结束了
      //main结束了
      
    4. 情况四:没throw,有throws,调用处没捕获(相当于直接处理,无论有没有捕获,代码依次照常运行)
      public class Text02 {public void t2() throws ArithmeticException{System.out.println("t2开始了");try {System.out.println(10 / 0);} catch (ArithmeticException e) {}System.out.println("t2结束了");}
      }public class Main02 {public static void main(String[] args) {System.out.println("main开始了");Text02 text02 = new Text02();text02.t2();System.out.println("main结束了");}
      }
      //输出结果
      //main开始了
      //t2开始了
      //t2结束了
      //main结束了
      
    5. 情况五:没throw,没throws,调用处有捕获(相当于直接处理,无论有没有捕获,代码依次照常运行)
      public class Text01 {public void t1() {System.out.println("t1方法开始了");try {System.out.println(10 / 0);} catch (ArithmeticException e) {}System.out.println("t1方法结束了");}
      }public class Main01 {public static void main(String[] args) {System.out.println("main开始了");Text01 text01 = new Text01();try {text01.t1();} catch (ArithmeticException e) {System.out.println("main捕获到了ArithmeticException");}System.out.println("main结束了");}
      }
      //输出结果
      //main开始了
      //t1开始了
      //t1结束了
      //main结束了
      
    6. 情况六:没throw,没throws,调用处没捕获(相当于直接处理,无论有没有捕获,代码依次照常运行)
      public class Text02 {public void t2() {System.out.println("t2开始了");try {System.out.println(10 / 0);} catch (ArithmeticException e) {}System.out.println("t2结束了");}
      }public class Main02 {public static void main(String[] args) {System.out.println("main开始了");Text02 text02 = new Text02();text02.t2();System.out.println("main结束了");}
      }
      //输出结果
      //main开始了
      //t2开始了
      //t2结束了
      //main结束了
      
    7. 情况七:没try、catch块,有throws,调用处没捕获
      • 在有问题的代码处直接就跳转到编译器,编译器进行控制
        public class Text01 {public void t1() {System.out.println("t1方法开始了");System.out.println(10 / 0);System.out.println("t1方法结束了");}
        }public class Main01 {public static void main(String[] args) {System.out.println("main开始了");Text01 text01 = new Text01();text01.t1();System.out.println("main结束了");}
        }
        //输出结果
        //main开始了
        //t1开始了
        //Exception in thread "main" java.lang.ArithmeticException: / by zero
        //at com.k11.text05.Text01.t1(Text01.java:8)
        //at com.k11.text05.Main01.main(Main01.java:9)
        
    8. 情况八:没try、catch块,有throws,调用处有捕获
      • 在有问题的代码处直接跳转到方法调用处,由于调用处进行了捕获,调用处后面的代码依次照常执行
        public class Text02 {public void t2() {System.out.println("t2开始了");System.out.println(10 / 0);System.out.println("t2结束了");}
        }public class Main02 {public static void main(String[] args) {System.out.println("main开始了");Text02 text02 = new Text02();try {text02.t2();} catch (ArithmeticException e) {System.out.println("main方法捕获了ArithmeticException");}System.out.println("main结束了");}
        }
        //输出结果
        //main开始了
        //t2开始了
        //main方法捕获了ArithmeticException
        //main结束了
        

11.5 自定义异常

  • 定义自己的异常:可以根据自己的业务逻辑定义我们认为异常的地方,并为这些地方定义自己异常
  • 想要定义编译时异常的类就继承Exception;想要定义运行时异常的类就继承RuntimeException
  • 异常对象的常用方法
    1. toString():返回异常的信息
    2. getMessage():返回消息的内容,说明当前的异常
    3. printStackTrace():把消息和栈跟踪记录输出到标准输出流,对于控制台程序,这个输出流就是屏幕

12. 垃圾回收机制

  1. 垃圾收集

    • 垃圾回收机制是Java健壮性体现的一部分
    • 垃圾
      • 对于所有程序而言:长时间没有被使用的空间
      • 对于Java而言:长时间没有被引用的里面的空间
    • 垃圾收集是将分配给对象但不再使用的内存回收或释放的过程
    • Java自动释放不再使用的内存(Java有垃圾回收车
    • 如果一个对象没有指向它的引用或将其赋值为null,则此对象将适于进行垃圾收集
  2. 内存泄露

    • 将一个引用指向一个空间后,又将该引用重新指向另一个空间,之前的那个空间没有被释放,这就容易造成内存泄露
      String s1 = new String("OK");
      s1 = new String("aaa");
      s1 = new String("bbb");
      s1 = new String("ccc");
      
  3. finalize()

    • 如果存在finalize()方法,它将在垃圾收集之前被执行一次,而且每个对象仅执行一次,用于执行最终消亡之前的一些操作
    • 消亡就调用finalize()方法
    • 不推荐使用,因为它的执行时机是不确定的,不能保证对象何时会被垃圾回收
      public class FinalizeExample {@Overrideprotected void finalize() throws Throwable {try {// 执行清理操作System.out.println("Finalizing object...");} finally {super.finalize();}}public static void main(String[] args) {FinalizeExample obj = new FinalizeExample();// 让对象变成垃圾obj = null;// 强制执行垃圾回收System.gc();}
      }
      
  4. System.gc()

    • 建议现在回收,不一定现在立马回收

13. ODBCJDBC

ODBC与JDBC都不是技术,两者都是数据库连接的规范(标准)

13.1 ODBC

  • 一句话概括
    • ODBC不是技术,是微软制定的数据库连接的一种规范。
    • 如果某一种数据库想要在Windows平台上被语言连上,该数据库就得符合ODBC的标准;
    • 如果某一种语言想要在Windows上连接某一种数据库,该语言就得符合ODBC的标准
  • ODBC(Open Database Connection):开放式数据库连接
  • 由Microsoft(MS)(微软)制定的数据库连接标准
    在这里插入图片描述

13.2 JDBC

  • 一句话概括:JDBC不是技术,是SUN公司制定的Java连接数据库的一种规范,如果某一种数据库想让Java连接,就得符合JDBC的标准
  • JDBC(Java Database Connection):Java数据库连接
  • 由SUN公司制定的Java连接数据库的规范
  • JDBC是一些接口的集合(jar包
    • 压缩包:本质意思是打包
      • 如果在打包之前是密度比较大的东西,一打包该东西容量就会变小
      • 如果在打包之前是压缩文件,打包之后容量不会变小
    • ar:指的是压缩包
    • .ear:企业级压缩包
    • .jar:Java压缩包,存放的都是Java文件(类和接口)
    • .rar:操作系统压缩包
    • .war:web压缩包
  • Javabean
    • 从广义的角度:所有的文件都是Javabean
    • 从狭义的角度:通常所说的Javabean指的是实体类

13.3 三方关系

  • SUN公司提供统一的接口(存放在jar包中)以及制定JDBC(Java连接数据库的规范)
  • DB生产商学习接口,提供接口的实现类(存放在jar包中),提供JDBC驱动程序(jar包)
  • 开发人员:学习JDBC(接口)(规范),使用jar编写程序(DB生产商提供的接口的实现类)(只学习一种规范,使用所有数据库)
    在这里插入图片描述

13.4 JDBC驱动程序

  1. 数据库驱动程序的JAR包:指的是数据库生产商提供的实现类存放在jar包中

    • SUN公司制定的JDBC,大多是接口,打包在jar包中;
    • db生厂商提供的实现了这些接口的实现类,也打包在jar包中,这两个jar包是两个不同的jar包
    • 我们需要在项目中导入的jar包是数据库生厂商提供的jar包,SUN公司提供的jar包已经在Java中内置存在了
    • 在使用之前需要将对应的jar包导入到对应的项目下
    • sqlServer
      • msbase.jar; mssqlserver.jar; msutil.jar
      • sqljdbc.jar:4.0版本之后三个合为一个了
    • mysql:mm.mysql-2.0.14-bin.jar
    • oracle:classes12.jar
  2. JDBC驱动程序的种类

    • JDBC-ODBC桥连(JDBC-ODBC桥驱动程序):数据源特指Access,如果要使用Access数据库,就必须符合ODBC规范(微软的)
      在这里插入图片描述
    • 本地API部分Java驱动程序:Java要求如果某一种数据库要使用Java语言就得符合JDBC的规范;数据库要求某一种语言想要连接某一种数据库,就必须符合该数据库规范;于是开发人员自己写了个JDBC驱动程序
      在这里插入图片描述
    • JDBC-Net 纯Java驱动程序:将开发人员自己写的驱动程序单独放到一个服务器上
      在这里插入图片描述
    • JDBC直连(纯Java驱动程序):所有数据库(除了Access)都实现了JDBC规范
      在这里插入图片描述

13.5 JDBC访问数据库的步骤

13.5.1 访问步骤

在这里插入图片描述

  1. 使用Class.forName(驱动程序类)加载数据库驱动
    //加载SqlServer数据库驱动
    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    
  2. 使用DriverManager.getConnerction(String url,String user,String pwd)连接数据库
    //连接SQLServer数据库中mybatisdb库
    conn = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;DatabaseName=mybatisdb", "sa", "sa");
    
  3. 调用方法,创建Statement数据库执行载体对象
    //创建Statement对象
    sta = conn.createStatement();
    
  4. 调用方法执行SQL语句
    • 调用Statement接口中的方法执行SQL语句
      //返回受sql语句影响的条数
      int sum = sta.executeUpdate(sql);
      //返回查询结果的ResultSet对象
      ResultSet rs = sta.executeQuery(sql);
      
    • 调用PreparedStatement接口中的方法执行SQL语句
      //创建预处理的sql语句
      String sql = "insert into course (id_course, course_name, course_time, course_teacher_id) values (?, ?, ?, ?)";
      //创建PreparedStatement对象
      psta = conn.prepareStatement(sql);
      //为sql语句赋值
      psta.setString(1, "c07");
      psta.setString(2, "php");
      psta.setInt(3, 50);
      psta.setString(4, "t04");
      //返回受sql语句影响的条数
      int sum = psta.executeUpdate();
      //返回查询结果的ResultSet对象
      ResultSet rs = psta.executeQuery();
      
  5. 获取返回ResultSet的结果
    rs = sta.executeQuery(sql);
    while(rs.next()) {String id_course = rs.getString("id_course");String course_name = rs.getString("course_name");int course_time = rs.getInt("course_time");String course_teacher_id = rs.getString("course_teacher_id");System.out.println(id_course + " " + course_name + " " + course_time + " " + course_teacher_id);
    }
    
  6. 释放资源
    if(rs != null) {rs.close();rs = null;
    }if(sta != null) {sta.close();sta = null;
    }if(conn != null) {conn.close();conn = null;
    }
    
  • 完整举例
    package com.k12.text04;import java.sql.Connection;
    import java.sql.DriverManager;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.sql.Statement;public class JDBCText01 {public static void main(String[] args) {Connection conn = null;Statement sta = null;ResultSet rs = null;try {Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");conn = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;DatabaseName=xa202403db", "sa", "sa");System.out.println("数据库连接成功");sta = conn.createStatement();String sql = "select * from course where course_teacher_id = 't01'";rs = sta.executeQuery(sql);while(rs.next()) {String id_course = rs.getString("id_course");String course_name = rs.getString("course_name");int course_time = rs.getInt("course_time");String course_teacher_id = rs.getString("course_teacher_id");System.out.println(id_course + " " + course_name + " " + course_time + " " + course_teacher_id);}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (SQLException e) {e.printStackTrace();} finally {try {if(rs != null) {rs.close();rs = null;}if(sta != null) {sta.close();sta = null;}if(conn != null) {conn.close();conn = null;}} catch (SQLException e) {e.printStackTrace();}}}
    }
    //输出结果:
    //数据库连接成功
    //c01 C语言程序设计 30 t01
    //c02 Java与面向对象 30 t01
    
13.5.2 加载驱动程序
  • 使用Class.forName (驱动程序类) 来加载驱动程序(决定要连哪一种数据库)
  • 驱动程序类
    1. JDBC-ODBC桥:sun.jdbc.odbc.JdbcOdbcDriver
    2. SQLSERVER
      • com.microsoft.jdbc.sqlserver.SQLServerDriver
      • com.microsoft.sqlserver.jdbc.SQLServerDriver
    3. MYSQL:org.gjt.mm.mysql.Driver
    4. ORACLE:oracle.jdbc.driver.OracleDriver
13.5.3 各种数据库的URL

localhost:指的是数据库所在主机的ip;(127.0.0.1无论什么地方都指的是自己的ip)
1433/3306/1521:指的是数据库安装时候的默认端口
DBName:指的是数据库名字

  1. JDBC-ODBC:jdbc:odbc:datasourceName
  2. SQLSERVER:jdbc:sqlserver://localhost:1433;DatabaseName=DBName
  3. MYSQL:jdbc:mysql://localhost:3306/DBName?user=root&password=pass
  4. ORACLE:jdbc:oracle:thin:@localhost:1521:DBname
13.5.4 Driver接口
  • 驱动程序类型接口,主要功能是决定连接哪一种数据库
  • 使用Class.forName(驱动程序类)加载数据库驱动
    //加载SqlServer数据库驱动
    Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
    
  • DriverManager类
    • DriverManager类是Driver的实现类
    • 使用DriverManager.getConnerction(String url,String user,String pwd)连接数据库
      • 返回值是个Connection类型
      • url:连接的哪种数据库就对应该数据库的url路径名
      • user:之前连接的数据库的用户名
      • pwd:之前连接的数据库的密码
      //连接SQLServer数据库中xa202403db库
      conn = DriverManager.getConnection("jdbc:sqlserver://localhost:1433;DatabaseName=xa202403db", "sa", "sa");
      
13.5.5 Connection接口(coon)
  • Connection数据库连接对象
  • 此接口表示与数据库建立连接,只有获得该对象才能访问数据库
  • 调用方法,创建数据库执行载体对象
    • 使用Connection.createStatement()方法创建Statement对象,该方法创建的Statement对象对应具体sql语句(在调用该方法时并没有传递sql语句,说明并没有编译sql语句)
      • 优点是灵活,缺点是编译慢,效率低
      //创建Statement对象
      sta = conn.createStatement();
      
    • 调用Connection.prepareStatement(sql)获取PreparedStatement对象,在获取PreparedStatement时就将sql添加进去,将该PreparedStatement与该sql进行绑定(在调用该方法时就对sql语句进行了编译),该PreparedStatement只能执行该类型的sql语句
      • 在调用该方法之前,sql语句必须得有
      //创建预处理的sql语句
      String sql = "insert into course (id_course, course_name, course_time, course_teacher_id) values (?, ?, ?, ?)";
      //创建PreparedStatement对象
      psta = conn.prepareStatement(sql);
      
13.5.6 Statement接口和PreparedStatement接口
13.5.6.1 Statement接口(sta)
  • Statement数据库执行载体(对象),用于执行SQL语句
  • 此接口用于执行SQL语句并将数据检索到ResultSet
  • 调用方法执行SQL语句
    • Statement.execute(String sql):用于执行各种SQL语句

    • Statement.executeUpdate(String sql):用于执行SQL中的操作,返回一个int类型的值,表示数据库中受SQL语句影响的条数

      //返回受sql语句影响的条数
      int sum = sta.executeUpdate(sql);
      
    • Statement.executeQuery(String sql):用于执行SQL中的查询操作,返回表示查询结果的ResultSet对象

      //返回查询结果的ResultSet对象
      ResultSet rs = sta.executeQuery(sql);
      
13.5.6.2 PreparedStatement接口(psta)
  • 此接口用于执行预编译的 SQL 语句
  • 在调用Connection.prepareStatement(sql)时,sql语句就已经被编译了,以后再无论在执行多少遍,该sql就不会再编译了,只需要用setter()方法对sql语句里面的 给重新赋值就可以
  • 在调用Connection.prepareStatement(sql)获取PreparedStatement对象之前,sql语句必须得有
    String sql = "insert into course (id_course, course_name, course_time, course_teacher_id) values (?, ?, ?, ?)";
    //用setter()方法给对应sql语句中的  ?  进行赋值
    psta.setString(1, "c07");
    psta.setString(2, "php");
    psta.setInt(3, 50);
    psta.setString(4, "t04");
    
  • 调用方法执行SQL语句
    • 调用PreparedStatement.excuteUpdate()方法:用于执行SQL中的操作,返回一个int类型的值,表示数据库中受SQL语句影响的条数
      int num = psta.executeUpdate();
      
    • 调用PreparedStatement.excuteQuery()方法:用于执行SQL中的查询操作,返回表示查询结果的ResultSet对象
      ResultSet  rs = psta.executeQuery();
      
13.5.6.3 Statement和PreparedStatement的区别
  1. Statement接口
    • Statement接口在调用Connection.createStatement()方法创建Statement对象时,可以没有sql语句,该句对sql语句没有编译
    • 一个Statement对象对应一条具体的sql语句
  2. PreparedStatement接口
    • PreparedStatement接口在调用Connection.prepareStatement(sql)时,sql语句就已经被编译了,在调用该方法之前sql语句必须存在
    • 一个PreparedStatement对象对应一种类型的sql语句
13.5.7 ResultSet接口(rs)
  • ResultSet:结果集对象
  • 此接口表示了查询出来的数据库数据结果集
  • 一般只有查询数据库时才会返回ResultSet对象
  • 获取返回ResultSet的结果
    • 无论有没有查询到东西,返回ResultSet的结果都不会为null
    • 调用next()方法作为while循环的条件来迭代ResultSet结果集
      • 在Resultset接口内部有一个指向表格数据行的游标(标记),ResultSet对象初始化的时候游标在表格第一行之前,调用next()方法可将游标移动到下一行。如果下一行没有数据,则返回false。
    • 通过getter()方法获取数据
      • ResultSet接口定义了大量的getter()方法,采用哪种getter()方法,取决于数据库中该字段的数据类型
      rs = sta.executeQuery(sql);
      while(rs.next()) {String id_course = rs.getString("id_course");String course_name = rs.getString("course_name");int course_time = rs.getInt("course_time");String course_teacher_id = rs.getString("course_teacher_id");System.out.println(id_course + " " + course_name + " " + course_time + " " + course_teacher_id);
      }
      
13.5.8 释放资源
  • StatementResultSetConnection等需要释放资源
  • 后开的资源,先释放
  • close()方法
    if(rs != null) {rs.close();rs = null;
    }
    if(sta != null) {sta.close();sta = null;
    }
    if(conn != null) {conn.close();conn = null;
    }
    

14. Util包日期时间类

14.1 Date类

14.1.1 Date类

已过时:有时候用可以,有时候用就会出问题

  1. Date类:日期类
    • 表示时间轴上的一个瞬时
    • 获取的当前时间是Date类的一个实例
    • 用法:获取当前的系统时间(代码运行服务器的时间)
  2. 时区(CST):每个经度都是一个时区
    • 中国是北京时间,东八区
  3. 时间分量:Date的每一个字段(年、月、日等等)
    • 得到时间分量:get()方法获取(已过时)
      date1.getMonth()
      
    • 设置时间分量:set()方法设置(已过时)
      date2.setMonth(0);
      
    • 注意:月份是从0开始的
      • 即获取到月份是4,表示当前是5月
      • 即设置的月份是0,表示当前是1月
14.1.2 构造方法
  1. 空参构造:Date date = new Date();
  2. 带参构造(指定年月日):Date date = new Date(int year,int month, int day);
    • 已过时,由 Calendar.set(year ,month,day)方法取代
    //得到的是1908年的1月1日
    Date date2 = new Date(8, 0, 1);
    
14.1.3 常用方法
  • after(Object when):测试此日期是否在指定日期之后
    date1.after(date2)
    
  • before(Object when):测试此日期是否在指定日期之前
    date2.before(date3)
    

14.2 Calender类

14.2.1 Calendar类
  • Calendar类:日历类
  • Calendar类是个抽象类,不能new,只能被继承
  • getInstance()方法
    • 可以用Calendar.getInstance()方法获取Calendar对象(实际上该方法返回的是Calendar子类的实例(GregorianCalendar),以Calendar的形式返回的)
      Calendar c1 = Calendar.getInstance();
      
  • 注意:月份是从0开始的
    • 即获取到月份是4,表示当前是5月
    • 即设置的月份是0,表示当前是1月
14.2.2 常用方法
  • set(int field, int value):设置时间分量的值
    • field指的是时间分量
    • value指的是值
    c1.set(Calendar.MONTH, 0);
    
  • get(int field):返回时间分量的值
    c1.get(Calendar.DATE)
    
  • after(Object when):测试此日期是否在指定日期之后
    c1.after(c2)
    
  • before(Object when):测试此日期是否在指定日期之前
    c1.before(c2)
    
  • add(int field, int amount):日期的计算,计算时间分量的值
    • field指的是时间分量
    • value指的是值
      • 值为正数表示加
        c1.add(Calendar.YEAR, 2);
        
      • 值为负数表示减
        c1.add(Calendar.YEAR, -2);
        
  • setTime(Date date):将当前的Date设置成Calendar
    GregorianCalendar gc = new GregorianCalendar();
    gc.setTime(date);
    
  • getTime():把Calender转换成一个Date对象
    GregorianCalendar gc = new GregorianCalendar();
    Date date = gc.getTime();
    
14.2.3 GregorianCalendar类
  • GregorianCalendar类:标准的日历类
  • GregorianCalendar类是Calendar的实现类
  • 构造方法
    • 无参构造:GregorianCalendar gc1 = new GregorianCalendar();
    • 带参构造:GregorianCalendar gc2 = new GregorianCalendar(int year, int month, int day);
  • 常用方法
    • isLeapYear(int year) :判断给定的年份是否为闰年
      gc.isLeapYear(2000)
      

14.3 SimpleDateFormat类

  • SimpleDateFormat类:日期的格式化类
  • SimpleDateFormat类不在java.util包中,而是在java.text包
符号描述
Y
M
d
H小时(24小时制)
h小时(12小时制)
a上午/下午
m分钟
s
E星期
  • 常用方法
    • format(Date date):将给定的Date格式化为字符串
      SimpleDateFormat sdf = new SimpleDateFormat("YYYY:MM:dd HH:mm:ss");
      Date date = new Date();
      String str = sdf.format(date);
      
    • parse(String str):将给定的字符串转换成Date对象
      String str1 = "2024:10:5 12:25:23";
      SimpleDateFormat sdf1 = new SimpleDateFormat("YYYY:MM:dd HH:mm:ss");
      Date date1 = sdf1.parse(str1);
      

15. Util包集合类

具体可看 集合类

15.1 集合框架

  1. 集合框架
    • 集合框架:Java中所有的集合
    • 集合:把多个元素变成一个元素的统一结构体
    • 集合用于存储、检索和操纵数据
  2. 集合的根
    • Collection接口(单列集合):将多个元素组成一个单元的对象
    • Map接口(双列集合):键值对存储的集合
  3. 掌握的集合对象 在这里插入图片描述
  4. 泛型

具体请看 泛型

  • 优点一:规定集合中存储的对象类型
  • 优点二:从集合中取出时就是该对象
  1. 集合框架的组成
    • 接口:是表现集合的抽象数据类型
    • 实现类:是接口的实际实现
    • 算法:是对实现接口的对象执行计算的方法
  2. 集合框架的优点
    • 提供有用的数据结构和算法,从而减少编程工作
    • 提供了程序速度和质量,因为它提供了高性能的数据结构和算法
    • 可以方便的扩展或改写集合

15.2 Collection接口

  1. Collection接口
    • 单列集合接口、单列集合的根
    • 单对象的、无序的、可重复的、可重复为null的单列集合
  2. 常用方法
    • add(E e):向Collection中添加元素
      collection1.add(s1);
      
    • addAll(Coiiection c):向Collection中添加另一个Collection
      • 注意:是将另外一个Collection中的元素复制了一份,改变另一个Collection中的元素,该添加后的Collection中元素不变
      collection1.addAll(collection2);
      
    • clear():清空Collection中的元素
      collection3.clear();
      
    • contains(Object o):判断该Collection中是否包含该元素
      • 注意:比较的是具体的值
      collection1.contains(s1)
      
    • `containsAll(Collection c):判断该Collection中是否包含该Collection中的所有元素
      • 注意:比较的是具体的值
      collection1.containsAll(collection2)
      
    • equals(Object o):比较该Collection是否与指定对象相等
      • 注意:比较的是两个Collection中具体的值
      collection2.equals(collection3)
      
    • isEmpty():判断该Collection是否为空
      collection1.isEmpty()
      
    • remove(Object o):在该Collection中删除第一次出现的该元素
      • 注意:删除的是该指定元素的单个实例,且每次只能删除一个实例
      collection1.remove(s2);
      
    • removeAll(Collection c):删除这两个Collection中共有的元素(删除交集)
      • 注意:比较的是具体的值
      collection1.removeAll(collection2);
      
    • retainAll(Collection c):保留这两个Collection中共有的元素(保留交集)
      • 注意:比较的是具体的值
      collection2.retainAll(collection3);
      
    • size():返回Collection中的元素数目
      collection2.size()
    • toArray():返回包含此 collection 中所有元素的数组
      Object[] arr = collection2.toArray();
      

15.3 List接口

15.3.1 List接口
  • 有序的、值可重复的单列集合
  • Collection接口的子接口
  • 有序的、值可以重复的、可以重复为null的单列集合
15.3.2 常用方法

List接口可以使用Collection父接口的所有方法

  1. 特有方法

    • add(int index, E element):在指定索引位置添加元素
      List<Student> list1 = new ArrayList<Student>();
      list1.add(1, s3);
      
    • addAll(int index, Collection c):在指定索引位置添加指定的Collection
      • 注意:是将另外一个List中的元素复制了一份,改变另一个List中的元素,该添加后的List中元素不变
      List<Student> list1 = new ArrayList<Student>();
      List<Student> list2 = new ArrayList<Student>();
      list1.addAll(0, list2);
      
    • get(int index):得到该索引位置的元素
      List<Student> list1 = new ArrayList<Student>();
      list1.get(2);
      
    • lastIndexOf(Object o):返回该List中最后出现该元素的索引位置
      List<Student> list1 = new ArrayList<Student>();
      list1.lastIndexOf(s3);
      
    • remove(int index):删除该索引位置上的元素
      List<Student> list1 = new ArrayList<Student>();
      list1.remove(2);
      
    • set(int index, E element):替换指定索引位置上的元素
      List<Student> list1 = new ArrayList<Student>();
      list1.set(1, s5);
      
    • subList(int fromIndex, int toIndex):返回索引为fromIndex(包括)toIndex(不包括)之间的元素
      List<Student> list1 = new ArrayList<Student>();
      List<Student> list = list1.subList(0, 3);
      
  2. 特有遍历方法

    • 调用get(int index)方法结合for循环进行遍历
    • 由于List集合有索引,因此可以调用get(int index)获取其中的元素
      List<Student> list1 = new ArrayList<Student>();
      for (int i = 0; i < list1.size(); i++) {Student temp = list1.get(i);System.out.println(temp.toString());
      }
      
15.3.3 实现类
15.3.3.1 Vector类
  • Vector类:向量表
    • 线程是安全的
    • elements()
      • Vector类中特有的线程方法
      • 返回该Vertor集合中的枚举
15.3.3.2 ArrayList类

具体可看 ArrayList集合

  • 线程不安全
15.3.3.3 LinkedList类

具体可看LinkedList集合

  • 用链表的形式来实现动态数组
  • 非线程程序中效率最高
  • 线程不安全

15.4 Set接口

具体请看 Set接口

  1. Set接口
    • 无序的、值不能重复的单列集合)
    • Collection接口的子接口
    • List:无序的、值不可以重复的、可以为null的单列集合
      • 值不可以重复是指后面的值会覆盖前面存在的值
    • Set接口可以使用Collection父接口的所有方法
  2. 实现类
    • HashSet类:线程不安全

15.5 Map接口

具体请看 Map集合

15.5.1 Map接口
  • Map:无序的、键不能重复可以为null、值可以重复可以为null的键值对集合
    • 键不可以重复是指后面的键对应的值会覆盖前面存在的值
  • 键值对都可以为null
15.5.2 常用方法
  • 常用方法
    • put(K key, V value): 添加键值对元素

      Map<String, Student> map1 = new HashMap<String, Student>();
      Student s1 = new Student("悟空", 500);
      map1.put("悟空", s1);
      
    • putAll(Map m): 将该map集合中添加指定的map集合

      • 注意:是将另外一个map中的元素复制了一份,改变另一个map中的元素,该添加后的map中元素不变
      Map<String, Student> map1 = new HashMap<String, Student>();
      Map<String, Student> map2 = new HashMap<String, Student>();
      map1.putAll(map2);
      
    • clear(): 清空map集合

      Map<String, Student> map2 = new HashMap<String, Student>();
      map2.clear();
      
    • containsKey(Object key): 判断该map集合是否含有key

      • 注意:比较的是具体的值
      Map<String, Student> map1 = new HashMap<String, Student>();
      map1.containsKey("悟空");
      
    • containsValue(Object value): 判断该map集合是否含有value

      • 注意:比较的是具体的值
      Map<String, Student> map2 = new HashMap<String, Student>();
      map1.containsValue(s1);
      
    • equals(Object o): 比较指定对象与该集合是否相等

      • 注意:比较的是两个集合中具体的值
      Map<String, Student> map1 = new HashMap<String, Student>();
      Map<String, Student> map2 = new HashMap<String, Student>();
      map1.equals(map2);
      
    • isEmpty(): 判断该集合是否为空

      Map<String, Student> map1 = new HashMap<String, Student>();
      map1.isEmpty();
      
    • remove(Object key): 删除指定key的值

      Map<String, Student> map1 = new HashMap<String, Student>();
      map1.remove("白龙");
      
    • size(): 返回集合中元素的数量

      Map<String, Student> map1 = new HashMap<String, Student>();
      map1.size();
      ```1. 特有方法
      
    • put(K key, V value): 添加键值对元素

      Map<String, Student> map1 = new HashMap<String, Student>();
      Student s1 = new Student("悟空", 500);
      map1.put("悟空", s1);
      
    • putAll(Map m): 将该map集合中添加指定的map集合

      • 注意:是将另外一个map中的元素复制了一份,改变另一个map中的元素,该添加后的map中元素不变
      Map<String, Student> map1 = new HashMap<String, Student>();
      Map<String, Student> map2 = new HashMap<String, Student>();
      map1.putAll(map2);
      
    • clear(): 清空map集合

      Map<String, Student> map2 = new HashMap<String, Student>();
      map2.clear();
      
    • containsKey(Object key): 判断该map集合是否含有key

      • 注意:比较的是具体的值
      Map<String, Student> map1 = new HashMap<String, Student>();
      map1.containsKey("悟空");
      
    • containsValue(Object value): 判断该map集合是否含有value

      • 注意:比较的是具体的值
      Map<String, Student> map2 = new HashMap<String, Student>();
      map1.containsValue(s1);
      
    • equals(Object o): 比较指定对象与该集合是否相等

      • 注意:比较的是两个集合中具体的值
      Map<String, Student> map1 = new HashMap<String, Student>();
      Map<String, Student> map2 = new HashMap<String, Student>();
      map1.equals(map2);
      
    • isEmpty(): 判断该集合是否为空

      Map<String, Student> map1 = new HashMap<String, Student>();
      map1.isEmpty();
      
    • remove(Object key): 删除指定key的值

      Map<String, Student> map1 = new HashMap<String, Student>();
      map1.remove("白龙");
      
    • size(): 返回集合中元素的数量

      Map<String, Student> map1 = new HashMap<String, Student>();
      map1.size();
      
15.5.3 实现类
  1. HashMap类

    具体请看 HashMap类

    • 线程不安全
    • 键和值可以存储null
  2. HashTable类
    • 线程安全
    • 键不能为null
    • 值不能为null

15.6 集合的遍历

具体请看 集合的遍历

15.6.1 双列集合的遍历
15.6.1 键遍历
  • keySet():返回该双列集合中所有的key,返回值是Set类型
    Map<String, Student> map1 = new HashMap<String, Student>();
    Set<String> set = map1.keySet();
    Iterator<String> it = set.iterator();
    while(it.hasNext()) {String key = it.next();Student value = map1.get(key);System.out.println(key + value.toString());
    }
    
15.6.2 值遍历
  • values() :返回该双列集合中所有的value,返回值是Collection类型
    Map<String, Student> map1 = new HashMap<String, Student>();
    Collection<Student> values = map1.values();
    for (Student temp : values) {System.out.println(temp.toString());
    }
    
15.6.3 键值对遍历
  • entrySet() :返回该双列集合中所有的键值对,返回值是Set类型(Set<Map.Entry<K,V>>)
    • getKey():获取key
    • getValue():获取value
    Map<String, Student> map1 = new HashMap<String, Student>();
    Set<Entry<String, Student>> entries = map1.entrySet();
    for (Entry<String, Student> entry : entries) {String key = entry.getKey();Student value = entry.getValue();System.out.println(key + value.toString());
    }
    
15.6.2 单列集合的遍历
15.6.1 迭代器遍历
  • iterator() :返回值是Iterator类型
    • hasNext():判断有没有下一个
    • next():获取下一个元素
    Iterator it3 = collection3.iterator();
    while (it3.hasNext()) {Student temp = (Student) it3.next();System.out.println(temp.toString());
    }
    
15.6.2 变成数组遍历
  • 调用toArray()生成Object[ ],遍历该数组
    Object[] arr = collection2.toArray();
    for(int i = 0; i < arr.length; i++) {System.out.println(arr[i].toString());
    }
    
15.6.3 foreach遍历
for (Student temp : collection) {System.out.println(temp.toString());
}
15.6.3 枚举遍历
  • 只针对线程安全的集合
  • elements():获取该集合元素,返回值是Enumeration枚举类型
    • hasMoreElements():判断有没有下一个元素,返回值是boolean类型
    • nextElement():获取下一个元素,返回值是获取到元素的类型
    Hashtable<String, Student> ht = new Hashtable<String, Student>();
    Enumeration<Student> em = ht.elements();
    while(em.hasMoreElements()) {Student temp = em.nextElement();System.out.println(temp.toString());
    }
    

16. I/O流

具体请看 I/O流

16.1 Java I/O流

  1. 为什么使用I/O流?
    • I/O流用来完成Java的输入输出
    • 输入输出的位置:源头、目的地
      • 网络上别的机器
      • 本地的硬盘
      • 别的程序、内存(不是JVM里面的)
    • 所有的流都使用相同的模型来编写程序
      1. 选取想要使用的流
      2. 正确的方式将要使用的流new出来
      3. 根据业务逻辑进行读写
      4. 关闭资源
  2. 什么是I/O流?
    • I/OInput/Output(输入/输出)
    • Input
      • Input:从JVM的外面进到JVM的里面来
      • 代码里面没有的数据
      • 从数据源读取数据到程序中
      • 源头(数据源):进来的地方
    • Output
      • Output:从JVM的里面出去到JVM的外面
      • 代码里面有的数据
      • 从程序中输出数据到外部目的地
      • 目的地:出去的地方
    • 什么是流?
      • 生活中的流是一种连续的有序的物质形态
      • 程序中的流是一种连续的有序的数据形态
      • 特征:连续的、有序的
    • 什么是I/O流?
      • Java完成输入输出的不间断的、连续的、有序的数据形态
  3. I/O流分类
    • 本质上分
      • 字节流:在传输数据的时候,搬运的最小单元就是字节
      • 字符流:在传输数据的时候,搬运的最小单元就是字符
    • 功能上分(操作什么就是什么流)
      • 文件流:专门操作文件
      • 对象流:专门操作对象
      • 数据流:专门操作数据
      • 转换流:专门用来转换数据
      • 标准流:专门用来操作控制台
      • 缓冲流:专门操作缓冲区
    • 本质上和功能上的联系
      • 按照功能上分的流,有的既基于字节的又基于字符的,有的只基于字节
      • 没有只基于字符,不基于字节的流
  4. I/O流作用
    • 主要是用来传输数据
    • 顺便还可以操作或格式化数据

16.2 字节流

16.2.1 字节流
  • 字节流可以直接操作二进制数据(字节数据)
  • 在传输数据的时候,搬运的最小单元就是字节
  • 节点流:能够直接给定源头和目的地的流
  • 处理流:不能直接给定源头和目的地的,要用另外一个流来new该流的流
16.2.2 分类
  1. 输入字节流
    • InputStream是输入字节流的根
    • 类层次结构图(加粗的是节点流,没加粗的是处理流) 在这里插入图片描述
  2. 输出字节流
    • OutputStream是输出字节流的根
    • 类层次结构图(加粗的是节点流,没加粗的是处理流) 在这里插入图片描述
16.2.3 常用方法
16.2.3.1 不带缓冲区的字节流的读写数据
  • InputStream.read():读取数据
    • 读取数据时,最开始在文件的Bof,当数据读取完了,就在文件的Eof(-1)处
    • 每次read时,读取的是个byte(8位),返回的是int(32位),将读取到的数据(byte)放到int的最后一位,前面空的24位用于底层JVM处理别的事情
    int  data = in.read();
    
  • OutputStream.write(int data):写出数据
    out.write(data);
    
    int data = -2;
    while((data = in.read()) != -1) {System.out.print((char)data);out.write(data);out.flush();
    }
    
16.2.3.2 带缓冲区的字节流的读写数据
  • InputStream.read(byte[ ], off, len):带缓冲区的读取数据
    • byte[ ]:缓冲区数组
    • off:偏移量,即从哪个位置开始装(一般为0)
    • len:装多少(一般为数组长度)
    while((in.read(pool, 0, pool.length)) != -1) {}
    
  • OutputStream.write(byte[ ], off, len):带缓冲区的写入数据
    • byte[ ]:缓冲区数组
    • off:偏移量,即从哪个位置开始装(一般为0)
    • len:装多少(一般为数组长度)
    out.write(pool, 0, pool.length);
    
15.2.3.3 flush()
  • OutputStream.flush():将缓冲的数据立即写出,而不是等到缓冲区满或关闭流时才写出
    out.flush();
    
15.2.3.4 close()
  • close():关闭资源
    in.close();
    out.close();
    

16.3 字符流

16.3.1 字符流
  • 流里面(数据源、目的地)有可能包含文本就要使用字符流
  • 在传输数据的时候,搬运的最小单元就是字符
  • 作用:解决流里面可能出现的中文乱码问题
16.3.2 分类
  1. 输入字符流
    • Reader是输入字符流的根
    • 类层次结构图(加粗的是节点流,没加粗的是处理流)在这里插入图片描述
  2. 输出字符流
    • Writer是输出字符流的根
    • 类层次结构图(加粗的是节点流,没加粗的是处理流)
      在这里插入图片描述
16.3.3 常用方法
16.3.3.1 不带缓冲区的字符流的读写数据
  • Reader.read():读取数据

    • 读取数据时,最开始在文件的Bof,当数据读取完了,就在文件的Eof(-1)处
    • 每次read时,读取的是个char(16位),返回的是int(32位),将读取到的数据(char)放到int的最后两位,前面空的12位用于底层JVM处理别的事情
      int  data = Reader.read();
      
  • Writer.write(int data):写出数据

    writer.write(data);
    
    int data = -2;
    while((data = reader.read()) != -1) {System.out.print((char)data);writer.write(data);writer.flush();
    }
    
16.3.3.2 带缓冲区的字符流的读写数据
  • 字符缓冲流
    • 缓冲流:操作缓冲区的流
    • 分类
      • 字符缓冲输入流:BufferedReader
      • 字符缓冲输出流:BufferedWriter
    • 缓冲原理:一次读取一行,只要不换行就放到一个缓冲区
  • 常用方法
    • 读取数据:readLine()
    • 写出数据:write()
    • 关闭资源:close()
    • 推出缓冲区数据:flush()
16.3.3.3 flush()
  • 将缓冲的数据立即写出,而不是等到缓冲区满或关闭流时才写出
    writer.flush();
    
16.3.3.4 close()
  • 关闭资源
    Reader.close();
    Writer.close();
    

16.4 常见I/O流

16.4.1 转换流
  • 转换流:用来转换数据的流,将字节转换成字符,或将字符转换成字节
  • 字节转换流
    • 字节输入转换流:InputStreamReader
    • 字节输出转换流:OutputStreamWriter
16.4.2 数据流
  • 数据流:能够操作数据的流
  • 数据流只有基于字节的,没有基于字符
  • 字节数据流
    • 字节输入数据流:DataInputStream
    • 字节输出数据流:DataOutputStream
  • 常用方法
    • 读取数据:readXxx()
    • 写出数据:writeXxx()
    • 关闭资源:close()
    • 推出缓冲区数据:flush()
16.4.3 对象流
  • 对象流:能够操作对象的流
  • 对象流只有基于字节的,没有基于字符
  • 在使用对象流时,传输的对象必须实现实现序列化接口(Serializable)
  • 字节对象流
    • 字节输入对象流:ObjectInputStream
    • 字节输出对象流:ObjectOutputStream
  • 常用方法
    • 读取数据:readObject()
    • 写出数据:writeObject()
    • 关闭资源:close()
    • 推出缓冲区数据:flush()
  • 接口
    • 功能接口:实现时要重写该接口里所有的方法的接口
    • 标识接口:不用完成功能的接口,该接口没有功能(方法),只起到标识作用
16.4.4 标准流
  • 标准流:用来操作控制台的流
  • 为什么叫标准流?
    • 数据源和目的地都不能改变,都是控制台
    • 标准流不需要new,在JVM启动时就自动new好了
  • 分类
    • 输入流:System.in(字节流,无字符流对象,为了把它变成字符流可以把System.in包装到InputStreamReader(转换流)中)
    • 输出流
      • System.out
      • System.err
  • 常用方法
    • 读取数据:read()
    • 写出数据:write()
    • 关闭资源:close()
    • 推出缓冲区数据:flush()

16.5 文件操作

16.5.1 File
  1. 文件操作
    • 文件操作:操作文件的本身
    • Java不区分文件和文件夹
  2. File
    • File:帮助编写对文件、目录进行操作的依赖于平台的代码
    • File位于io包中
    • 构造方法
      • File f1 = new File(String pathname)
      • 注意:new出来的文件,在运行时只存在于Java中,当运行结束时,该文件就被释放了,与硬盘没有关系,如果想存在硬盘中,可以使用createNewFile()方法
    • 常用方法
      • File.exists():判断该文件是否存在
        boolean b = f1.exists()
        
      • File.createNewFile():在硬盘中创建该文件
        f1.createNewFile();
        
      • File.delete():删除该文件
        f1.delete();
        
      • File.isDirectory():判断该文件是不是文件夹
        boolean b = files[i].isDirectory()
        
      • File.isFile():判断该文件是不是文件
        boolean b = files[i].isFile()
        
      • File.listFiles():前提该文件是文件夹,将该文件夹里的文件以文件数组的形式返回
        File[] files = f2.listFiles();
        
      • File.getAbsolutePath():获取该文件的绝对路径
        System.out.println(f1.getAbsolutePath());
        
      • File.getPath():获取该文件的路径
        System.out.println(f1.getPath());
        
      • File.getName():获取该文件的名字
        System.out.println(f1.getName());
        
      • File.getParent():获取该文件的父文件夹
        System.out.println(f1.getParent());
        
16.5.2 遍历文件夹
  • files数组可能为null
    • listFiles() 方法返回一个 File[]数组,如果目录为空或者发生I/O错误,它可能返回null
  • 递归调用中的空对象可能导致空指针异常
    • 在递归调用 each(files[i]) 时,如果 files[i] null(是一个文件(非文件夹)),就会导致空指针异常。
    File f2 = new File("C:");
    each(f2);
    public static void each(File f2) {File[] files = f2.listFiles();if (files == null) {//判断文件夹是否为空System.out.println("文件夹或目录为空或无法访问");return;}for (int i = 0; i < files.length; i++) {if (files[i].isFile()) {System.out.println(files[i].getName());continue;}each(files[i]);}
    }
    
16.5.3 RandomAccessFiles
  • RandomAccessFiles:支持随机访问磁盘文件
  • RandomAccessFiles:操作文件里面的东西,底层也是IO
  • 构造方法
    • RandomAccessFiles accessFile = new RandomAccessFiles(File file,String mode)
    • RandomAccessFiles accessFile = new RandomAccessFiles(String name,String mode)
      • mode:只读、只写、又读又写
  • 常用方法
    • RandomAccessFiles.seek(int i):将游标挪到i号位置
      • RandomAccessFiles对象有个像游标一样的东西,数据读取或写入时,每读(写)一个,游标就移一位
      accessFile.seek(0);//将游标移到开始处
      
    • RandomAccessFiles.writeXx():数据写入
      accessFile.write("你好,文件".getBytes());
      
    • RandomAccessFiles.readXx():数据读取
      String line = accessFile.readLine();
      
    • RandomAccessFiles.getFilePointer():获取该游标的位置
      int  i =  accessFile.getFilePointer()
    • RandomAccessFiles.close():关闭资源
      accessFile.close();
      
  • 数据转码:String str = new String(RandomAccessFiles.readXx().getBytes("iso-8859-1"), "GBK");
    String line = accessFile.readLine();
    //数据转码
    String info = new String(line.getBytes("iso-8859-1"), "GBK");
    

17. 多线程

17.1 进程和线程

17.1.1 进程和线程
  1. 多任务和单任务
    • 多任务(并发):多进程和多线程就是多任务
    • 单任务(独占):只能有一个线程在运行
  2. 重量级和轻量级
    • 重量级:相对而言,两个资源在一起,占用资源多,开辟和消亡的慢,不太稳定的叫做重量级
    • 轻量级:相对而言,两个资源在一起,占用资源少,开辟和消亡的快,较稳定的叫做轻量级
  3. 进程
    • 进程:一个进程就是操作系统里的一个正在运行的应用程序
    • 单进程和多进程
      • 单进程:操作系统里的单任务(独占
      • 多进程:操作系统里面的多任务(并发),操作系统是基于进程在做并发
    • 进程是“自包容”的运行程序,有自己的地址空间
    • 自包容:自己管自己,应用程序一旦启动后,操作系统就不管了,剩下的就是应用程序自己管自己
    • 进程是重量级的多任务
  4. 线程
    • 线程:进程(正在运行的应用程序)里的任务
    • 单线程和多线程
      • 单线程:一个应用程序里面的一个任务
      • 多线程:进程(正在运行的应用程序)里的多任务(并发)
    • 线程是轻量级的多任务,是CPU使用的基本单元
    • 线程属于某一个进程,一个进程中拥有一个或多个线程,多个线程共享同一个进程资源
    • 操作系统是基于进程(应用程序)工作的,然而处理程序的是CPU,但是CPU不认识程序,CPU是基于线程工作的
17.1.2 多任务处理
  1. 分类
    • 基于进程:计算机同时运行多个进程
    • 基于线程:一个进程包含多个线程
  2. 特点
    • 各个进程需要分配他们自己独立的地址空间
    • 进程间调用涉及的开销比线程间通信多
    • 多个线程可共享相同的地址空间并且共同分享同一个进程
    • 线程间的切换成本比进程间切换成本低
    • 进程是重量级的,线程是轻量级的

17.2 线程

17.2.1 多线程优点
  1. 模拟同步动作:线程同步
  2. 利用多处理器
    • CPU的工作是基于线程的,如果同时有20个CPU,只有一个线程,那么CPU就浪费了
    • 多线程允许程序在多个CPU上同时执行不同的线程,从而实现真正的并行处理。
  3. 等待缓慢IO操作(堵塞操作)时完成其他任务
    • 堵塞操作:调用了,但是堵在那里不动(不死但是也不反馈),就给该堵塞行为开个线程,从而不影响其他线程
  4. 与用户交互更佳
  5. 简化对象模型
17.2.2 JVM中的线程和进程
  1. JVM中的线程
    • 当操作系统启动JVM(javacjavajavaw等命令)时就创建了一个进程
    • JVM线程至少包含两种线程
      • main方法
      • 垃圾回收线程
    • main方法垃圾回收线程称为主线程,有时他们会启动其他线程,他们必须最后完成执行,执行各种关闭、释放动作
  2. JVM进程
    在这里插入图片描述
17.2.3 创建线程两种方法
17.2.3.1 继承Thread类
  • 声明一个Thread类的子类,并覆盖run()方法
  • 该类继承了Thread类,那么该类就是线程类,重写线程类的run方法,run方法是线程的核心方法,当开始线程时就会自动调用run方法
  • 语法:
    public class SampleThread extends Thread {public void run(){ };
    }
    
  • 举例:
    public class MyThread extends Thread {public void run() {System.out.println("线程正在运行...");}public static void main(String[] args) {MyThread thread = new MyThread();thread.start();}
    } 
    
17.2.3.2 实现Runnable接口
  • 声明一个实现Runnable接口(共伴接口)的类,并实现run()方法
  • 该类实现Runnable接口,实现里面的run方法,但是该类不是线程类,只是个普通类,且run方法不是线程里的核心方法,只是Runnable里的run方法,和线程没有关系
  • new一个空的Thread,将实现Runnable接口的类作为参数给Thread,从而将空白线程Thread里的空的run方法按照传进来的实现Runnable接口类的run方法来run
    Thread t1 = new Thread(new Text01());
    
  • 语法:
    public class SampleThread implements Runnable{public void run{};
    }
    
  • 举例:
    public class Text01 implements Runnable {@Overridepublic void run() {System.out.println("这是一个实现了runnable的run方法.");}
    }public class Main {public static void main(String[] args) {Thread t1 = new Thread(new Text01());t1.start(); // 启动线程,会执行Text01类中实现的run方法}
    } 
    
17.2.4 线程状态
  1. 新建态(new):线程new出来了,还没有运行
  2. 运行态(runnable):正在运行的状态(调用start的状态)
  3. 等代态
    • 锁定态(blocked):受堵塞线程的线程状态
    • 定时等待态(timed waiting):具有指定时间的某一等待状态的线程状态
    • 不定时等待态(waiting):调用不带超时值的Object.wait()、Thread.join()之一而处于等待状态
  4. 终止态(terminatrd):线程已经运行完毕的状态
17.2.5 常用方法
  • Thread.currentThread():获取当前正在运行线程

    Thread t = Thread.currentThread();
    
  • Thread.sleep(long millis):线程睡眠

    • 参数:millis毫秒
    Thread.currentThread().sleep(1000);
    
  • Thread.start():线程启动,线程一开启就不管了,该咋运行就咋运行

    t1.start();
    
  • Thread.getName():获取线程名称

    String name = Thread.currentThread().getName();
    
  • Thread.isAlive():判断线程是否是运行状态

    boolean b = Thread.currentThread().isAlive();
    
  • Thread.setName(String name):设置线程名称

    Thread.currentThread().setName("main线程");
    
  • Thread.join():等待线程结束

    try {Thread.currentThread().join();
    } catch (InterruptedException e) {e.printStackTrace();
    }
    
  • Thread.isDaemon():判断该线程是否是守护线程

    boolean b1 = Thread.currentThread().isDaemon();
    
  • Thread.setDaemon(boolean b):设置该线程是否为守护线程

    Thread.currentThread().setDaemon(true);
    
  • Thread.activeCount():返回正在运行的线程数

    int i = Thread.currentThread().activeCount();
    
  • Thread.yield():使正在运行的线程暂停,并让其他线程执行

    Thread.currentThread().yield();
    ```- Thread.currentThread():获取当前正在运行线程
    ```java
    Thread t = Thread.currentThread();
    
17.2.6 线程优先级
  • 线程优先级:线程抢占CPU资源(令牌)的能力
  • 获得CPU的资源是一样的,只是优先级高的先获取的快
  • java中的线程优先级是在Thread类中定义的常量
    • NOEM_PRIORTY:5
    • MAX_PRIORITY:10
    • MIN_PRIORITY:1
  • 常用方法
    • Thread.setPriority():修改线程的当前优先级
    • Thread.getPriority():返回线程的优先级
17.2.7 线程同步
  • 同步:独占,排除并发
  • 线程同步:当多个线程同时访问同一资源时,就要使用同步
  • 线程同步的两种方法
    • 同步方法:将需要同步的方法前添加synchronized修饰词

      public synchronized void print(String name) {try {System.out.print("[");System.out.print(name);Thread.currentThread().sleep(1000);System.out.println("]");} catch (InterruptedException e) {e.printStackTrace();}
      }
      
    • 同步块:使用同步块,把要同步的代码写在同步块里

      synchronized(object){
      //要同步的语句
      }
      
      • object指的是同步的资源,在代码块中调用的该资源的所有东西都是同步的
      synchronized (this.pm) {this.pm.print(name);
      }
      

17.3 wait-notify机制

  1. wait-notify机制
    • wait-notify机制(通信机制):两个线程之间等待和唤醒的关系
    • Java提供了一个精心设计的线程间通信机制,使用wait()notify()notifyAll()方法
  2. 三个方法(都是Object中的final方法(不能重写的方法))
    • wait():等待方法
    • notify():唤醒方法,一次只唤醒一个离我最近的等待线程
    • notifyAll():唤醒所有等待的线程
      • 唤醒的线程会抢占cpu资源,抢占到的资源运行,没有抢占到的继续等待,等待下次唤醒
    • 这三个方法必须在synchronized方法(同步方法)中使用

18. 网络编程

18.1 网络编程

  • 网络编程
    • Java网络编程:套接字编程、socket编程、网络编程、net编程
    • Java网络编程:用Java从网络上取东西
  • 什么是网络?
    • 网络:用某一种媒介(介质)把终端设备连接起来实现资源共享和通信

18.2 ISO/OSI参考模型

18.2.1 ISO和OSI
  • ISO(International Standard Organization ):国际标准组织(制定标准)
  • OSI(Open System Interconnection):开放系统连接
18.2.2 OSI参考模型
  1. 为了解决四个问题
    • 怎么连
    • 怎么找
    • 怎么传
    • 传什么
  2. 七层 在这里插入图片描述
  3. OSI参考模型图 在这里插入图片描述
18.2.3 TCP/IP参考模型
  • TCP是传输层,IP是网络层
  • TCP/IP参考模型图 在这里插入图片描述

18.3 IP、DNS、端口、协议

18.3.1 IP
  • IP
    • IP:计算机主机在网络上的唯一标识
    • 连接至网络的每台计算机的IP都是唯一
  • IP表示
    • 32 位数字,四个用点号分隔的数字
    • 范围:0~255 . 0~255 . 0~255.0~255
      186.156.23.23
      
  • 网络类别:A、B、C、D
    • A.B类一般都是一些独有的特有的在使用
    • 我们平时使用的都是C、B类
  • 一个主机(Host)只能有一个IP
18.3.2 DNS
  • 域名:IP的映射(别名)
    www.baidu.com
    
  • DNS(Domain Name System):域名系统(目录(IP)名字(域名)服务),当输入域名时,DNS服务器就会将域名解析成IP
  • DNS服务器:做DNS服务的主机
18.3.3 端口
  • 端口(Port):代表一个应用程序,用于实现程序间通信
  • 端口是在传输层使用的
  • 常用端口
    • TeInet协议:23
    • 简单邮件传输协议:25
    • 文件传输协议:21
    • 超文本传输协议:80
  • 一个机子可以有成千上万个端口,自己一般设置5w以后的端口
18.3.4 协议
  • 协议:网络中计算机之间通信的规则(约定)
  • 常用协议
    • 超文本传输协议(HTTP)
    • 文件传输协议(FTP)
    • 简单邮件传输协议(SMTP)
    • 网络新闻传输协议(NNTP)

18.4 B/S模式和C/S模式

18.4.1 B/S模式

在这里插入图片描述

18.4.2 C/S模式

在这里插入图片描述

18.4.3 B/S模式的演变
  1. 基于web的0客户端
    • 浏览器运行不了Java程序,只有服务器才能运行java程序,所以应用程序不能到浏览器中,都得在服务器上,从而每次操作都得请求服务器,导致速度太慢了
  2. 基于web的负客户端
    • 浏览器虽然可以运行Java程序,但是写不了Java代码,只能写JavaScript代码,将程序从服务器运行到浏览器的技术实现是Ajax、JQurey
    • 浏览器只能识别html(构建浏览器)、css(美化浏览器)、js(负责浏览器动作)
    • Ajax、JQurey:在浏览器上写应用,将重要的东西放在服务器上,将一些合理的东西就放在本地
  3. 基于web的前后端分离
    • js框架:使用JavaScript框架(如React、Angular、Vue.js)构建前端
    • Java框架:使用Java框架(如Spring MVC、Spring Boot)构建后端
18.4.4 完整开发的四个程序

在这里插入图片描述

18.5 套接字(socket)

18.5.1 套接字(socket)
  • 套接字(socket):操作系统用于网络通讯的端点
  • socket不是Java的东西,而是操作系统的东西
  • socket与主机地址和端口地址相关联
  • 客户端和服务器通过套接字建立连接和进行通信
18.5.2 socket图解

在这里插入图片描述

  • 运行过程
    • 操作系统A将程序A给socket,socket给驱动程序,驱动程序给操作系统外的网卡,网卡通过网线给另一个网卡,该网卡通过操作系统B中的驱动程序给与之对应的socket,该socket又给程序B
      在这里插入图片描述

19. Java.net包

19.1 InetAddress

19.1.1 InetAddress对象
  • InetAddress对象:包装网络上的一台主机(Host)
19.1.2 获取方法
  • InetAddress.getByAddress(byte[] addr):通过地址获取该主机
    byte[] bytes = {127, 0, 0, 1};
    InetAddress address1 = InetAddress.getByAddress(bytes);	
    
  • InetAddress.getByAddress(String host, byte[] addr):通过地址获取该主机
    byte[] bytes = {127, 0, 0, 1};
    InetAddress address2 = InetAddress.getByAddress("127.0.0.1", bytes);
    
  • InetAddress.getByName(String host):通过主机名(域名、IP)获取该主机
    InetAddress address3 = InetAddress.getByName("www.baidu.com");
    
  • InetAddress.getLocalHost():通过本地主机名(域名、IP)获取该主机
    • 127 . 0 . 0 . 1:永远代表本机IP
    InetAddress address4 = InetAddress.getLocalHost();
    
  • 参数
    • host:用于指定主机名或者 IP 地址
      • 如果传入 IP 地址,会直接解析该地址
      • 如果传入主机名(域名),则解析该主机名对应的 IP 地址
    • addr:用于指定 IP 地址的字节表示形式
      • IPv4 地址通常是一个 4 字节的数组
      • IPv6 地址通常是一个 16 字节的数组
19.1.3 常用方法
  • InetAddress.getHostAddress():获取InetAddress的IP
    InetAddress address3 = InetAddress.getByName("www.baidu.com");
    System.out.println(address3.getHostAddress());//36.155.132.76
    
  • InetAddress.getHostName()
    • 如果该InetAddress是getByAddress获取的,则该方法是获取InetAddress的IP
      byte[] bytes = {127, 0, 0, 1};
      InetAddress address1 = InetAddress.getByAddress(bytes);
      System.out.println(address1.getHostName());//127.0.0.1
      
    • 如果该InetAddress是getByName获取的,则该方法是获取InetAddress的域名
      InetAddress address3 = InetAddress.getByName("www.baidu.com");
      System.out.println(address3.getHostName());//www.baidu.com
      
    • 如果该InetAddress是getLocalHost获取的,则该方法是获取InetAddress的电脑名
      InetAddress address4 = InetAddress.getLocalHost();
      System.out.println(address4.getHostName());//电脑名
      

19.2 TCP的网络通讯

19.2.1 TCP的网络通讯
  • 在通讯时,是Socket与Socket进行通讯,ServerSocket负责侦听(当ServerSocket侦听到Socket1时会创建个Socket,与之通讯)
  • TCP的网络通讯是基于数据流
19.2.2 对象
19.2.2.1 ServerSocket
  • ServerSocket:服务器的TCP套接字对象
  • 构造方法:ServerSocket serverSocket = new ServerSocket(int port)
    • port:端口号,判断当前程序用哪个端口进行通讯
      ServerSocket serverSocket = new ServerSocket(50088);
      
  • 常用方法
    • ServerSocket.accept():返回值是Socket
      • 侦听方法,用于接受Socket的请求并返回一个已经连接了Socket请求的新Socket对象
      • 阻塞方法,只要没有侦听到Socket,就一直卡在这,也不进行后面的事
      Socket socket = serverSocket.accept();
      
19.2.2.2 Socket
  • Socket:客户端的TCP套接字对象
  • 构造方法
    • Socket socket = new Socket(InetAddress address,int port)
    • Socket socket = new Socket(String hostName,int port)
      • address:包装主机(Host)的InetAddress对象
      • hostName:主机(域名、IP)
      • port:端口号
  • 常用方法
    • Socket.getInputStream():获取输入字节流对象,返回值是InputStream
      writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
      
    • Socket.getOutputStream():获取输出字节流对象,返回值是OutputStream()
      writer = new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
      
    • Socket.getPort():获取远程的端口号
    • Socket.getLocalPort():获取本地的端口号
    • Socket.getInetAddress():获取主机,返回值是InetAddress
19.2.3 SocketException异常
  • SocketException:Connection reset(连接重置异常)
  • 两边的Socket正在正常通讯,一边的Socket正在读取,另一边的Socket无辜掉线了,就会报该异常
  • 解决方法:让两边的Socket都正常掉线

19.3 UDP的网络通讯

19.3.1 UDP的网络通讯
  • 数据报:通信的一种报文类型,是单向传输的,可能会丢数据
  • UDP的网络通讯是基于数据报
19.3.2 对象
19.3.2.1 DatagramPacket

DatagramPacket:数据容器

  1. 接收数据
    • 接受数据的构造方法:
      • DatagramPacket rPacket = new DatagramPacket(byte[] buf,int offset,int length):创建个带缓冲区的用于接受数据的DatagramPacket对象
        rPacket = new DatagramPacket(bytes, 0, bytes.length);
        
    • 常用方法
      • packet.getData():获取该数据容器里的数据,返回值是byte[]
        String str = new String(rPacket.getData());
        
  2. 发送数据
    • 发送数据的构造方法
      • DatagramPacket sPacket = new DatagramPacket(byte[] buf,int offset,int length,InetAddress address,int port):创建个带缓冲区的用于发送数据的DatagramPacket对象
        sPacket = new DatagramPacket(pool, 0, pool.length, InetAddress.getByName("127.0.0.1"), 50066);
        
    • 常用方法
      • packet.setData(byte[] bytes):给该数据容器发送数据
        sPacket.setData("知道了".getBytes());
        
19.3.2.2 DatagramSocket
  • DatagramSocket:发送或接受DatagramPacket
  • 构造方法
    • DatagramSocket socket = new DatagramSocket():系统会随机分配个端口号,然后根据这个端口号发送或接受数据
    • DatagramSocket socket = new DatagramSocket(int port):指定端口号,然后根据这个端口号发送或接受数据
  • 常用方法
    • DatagramSocket.receive(DatagramPacket):将接收到的数据放到DatagramPacket数据容器中
      • DatagramPacket指的是接受数据的数据容器
      • 阻塞方法,只要没有DatagramPacket,就一直卡在这
      socket.receive(rPacket);
      
    • DatagramSocket.send(DatagramPacket):将存放数据的DatagramPacket数据容器发送出去
      • DatagramPacket指的是发送数据的数据容器
      • 阻塞方法,只要没有DatagramPacket,就一直卡在这
      socket.send(sPacket);
      
    • DatagramSocket.close():释放资源
      socket.close();
      

20. 案例:类似于QQ的即时通信系统

20.1 两个项目包

20.1.1 Client包(客户端)

在这里插入图片描述

20.1.2 server包(服务端)
  • 服务端:给每个客户端提供服务的,该程序永远不关机
    在这里插入图片描述
20.1.3 分布式部署
  • 分布式部署:有很多套代码,分别部署在不同的机子上,但是运行起来,我们从逻辑上认为是一套代码(一台机子)

20.2 通信原理

20.2.1 TCP通讯
  1. server端和client端之间的通讯是基于TCP进行通讯的
  2. 数据通信
    • client端没有DB(没有完整的Model层),client端只有实体
    • client端拿到数据后传给server端,server端进行处理(到数据库中进行验证),然后将处理的结果直接返回给client端
  3. 做事原理
    • server端:操作数据库
    • client端:收集数据打包上送,拿到结果拆包显示结果
  4. TCP通讯做的事:登录、注册、找好友、删好友等等
  5. severe端和client会有个持久的TCP通道
20.2.3 UDP通讯
  1. client端和client端之间的通讯是基于UDP进行通讯的
  2. UDP通讯
    • client端第一次上线时会将自己的IP和ServerSocket的port发给server端,server端将其存放在数据库中
    • 同时,server端也会将该client端所有好友的IP和ServerSocket的port发给该client端
  3. UDP通讯做的事
    • client端与client端之间发消息
    • 广播信息:server端对所有客户端点对点的群发消息

20.3 TCP通讯层次

20.3.1 Box布局管理器
  1. Box布局管理器:既能做布局管理器,也能做容器
  2. 获取方法
    • 静态方法获取Box对象
    • Box布局
      • Box.createHorizontalBox():横着布局(水平),水平方向一直放,返回值是Box
      • Box.createVerticalBox():竖着布局(竖直),竖直方向一直放,返回值是Box
  3. 常用方法
    • Box.add(组件/容器):向Box布局管理器中添加组件
    • Box.createVerticalBox(int height):设置竖直方向的空白区域
    • Box.createHorizontalBox(int width):设置水平方向的空白区域
20.3.2 数据库连接
  1. 配置文件
    • 将数据库的驱动信息、数据库、用户名、密码放在配置文件中,利用IO读取数据文件
      在这里插入图片描述
  2. Java配置对象
    • Java配置文件对象:Properties对象,用于加载配置文件(后缀名必须是.properties
    • 写法
      1. 将配置文件对象new出来:Properties properties = new Properties();
      2. 加载配置文件
        properties.load(DBUtil1.class.getResourceAsStream("/db.properties"));
        DBUtil1.class.getResourceAsStream():加载该类所在的src路径
      3. 调用Properties.getProperty(键):从而获取与键对应的值 在这里插入图片描述
20.3.3 报文
  • 报文:只要通讯双方涉及的业务是多种的就要用到报文(例如注册、登录两个不同的业务)
  • 报文用处:识别业务、传输数据
  • 报文形式
    • 报文头:识别业务
    • 报文体:要操作的资源
      在这里插入图片描述
http://www.xdnf.cn/news/2906.html

相关文章:

  • 1.6二重积分
  • 浅谈人工智能发展现状
  • Python-pandas-DataFrame取值--.loc[]、.iloc[] 具体的操作及详细语义和语法说明
  • Linux文件传输:FTP服务器配置全攻略
  • Foupk3systemX5OS系统产品设备
  • 扩散模型与正弦位置编码
  • datasets 数据处理封装后,统一处理流程以避免Dataset Map顺序依赖问题
  • 《算法吞噬幻想乡:GPT-4o引发的艺术平权运动与版权核爆》
  • 数据库Mysql学习——day7(多表查询(JOIN)进阶)
  • 软件测试深度解析:从“用户登录“看测试用例设计的艺术
  • 什么是 Web 标准?为什么它们对 SEO 和开发很重要?
  • TRex 控制台命令解析
  • 【计算机视觉】三种图像质量评价指标详解:PSNR、SSIM与SAM
  • 【MySQL数据库】表的连接
  • OpenGL学习笔记(HDR、泛光)
  • ros2_不同ROS_DOMAIN_ID环境变量之间通信
  • vuex与vuex-persistedstate 插件固化数据
  • Spring框架allow-bean-definition-overriding详细解释
  • terraform隐藏云账号ak/sk信息
  • Linux系统中的静态库和动态库
  • 《无刷空心杯电机减速机选型及行业发展趋势》
  • 解密面试高频题:加权轮询负载均衡算法 (Java 实现)
  • 量子算法调试:Grover算法搜索空间压缩过程可视化方案
  • 算法笔记.kruskal算法求最小生成树
  • 汤晓鸥:计算机视觉的开拓者与AI产业化的先行者
  • 深入理解 Spring 类型转换核心接口 ConversionService
  • emqx部署
  • 厚铜板的镀前处理差异:工艺参数与成本影响
  • C22-作业练习之最大公约数与最小公倍数
  • idea启动springboot方式及web调用