提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 常用快捷键
  • IDEA IJ 的一些使用
  • 注释
  • 字面量
  • 变量
  • 强制类型转换
  • 运算符
    • 连接运算符 ‘+’
    • 自增自减运算符 ‘++’ ‘--’
    • 赋值运算符
    • 关系运算符
    • 逻辑运算符
      • 短路逻辑运算符
    • 三元运算符
    • 运算符优先等级
  • 键盘录入技术
  • 分支
    • if分支
    • switch分支
      • switch的穿透性
  • 循环结构
    • for循环
    • while循环
    • do-while循环
    • 死循环
    • 嵌套循环
  • 跳转关键字
  • 随机数
  • 数组
    • 静态初始化数组
    • 动态初始化数组
    • 数组的遍历
      • 数组中的元素交换
  • 方法
    • 方法定义技巧
    • 返回数组的方法的定义与调用
    • 方法参数的传递机制:值传递
    • 方法重载
    • return 关键字
  • 算法----信号位思想flag
  • 面向对象(oop)
    • 设计对象并使用
    • 对象在内存中的运行机制
    • 构造器
    • this关键字
    • 封装----private
    • 标准JavaBean
      • 快捷键
    • 成员变量和局部变量的区别
  • API
  • String
    • 概述
    • 创建字符串对象的2种方式
    • String类常用API
      • 遍历
      • 截取----substring
      • 替换----replace
      • 分割----split
      • String字符串的内容比较----equals
  • ArrayList
    • 概述
    • ArrayList添加元素的API
    • ArrayList的泛型使用
    • ArrayList的常用API
      • 遍历
    • ArrayList边遍历边删除元素
  • static
    • static关键字----可以在任何地方被访问
      • 修饰成员变量
      • 修饰成员方法
      • 注意事项
    • static-工具类
    • static-代码块----面向对象
    • static-单例设计模式
      • 饿汉单例
      • 懒汉单例
  • 面向对象----继承----extends
    • 继承特点
    • 成员变量、成员方法访问特点
    • 方法重写----@Override
    • 构造器特点
    • this、super 总结
  • 面向对象----语法
    • 权限修饰符----public等
    • final
    • 常量----public static final
    • 枚举--enum
    • 抽象类--abstract
      • 特征和注意事项
      • 模块方法模式
    • 接口--interface
      • 接口多实现--implement
      • 接口多继承
      • 接口新增方法
      • 注意事项
  • 面向对象----多态
    • 优势
    • 多态下引用数据类型的类型转换
      • 子类对象转为父类类型----自动类型转换
      • 父类对象转为子类类型----强制类型转换
      • instanceof----判断当前对象的真实类型
  • 内部类----面向对象
    • 静态内部类
    • 成员内部类
    • 局部内部类
    • 匿名内部类
      • 使用形式
  • 常用API
    • Object
      • toString----返回对象内容,而不是返回地址
      • equals----比较内容是否相同,而不是地址
    • Objects----new对象进行内容比较时使用
      • Objects.equals----避免空指针异常
    • StringBuilder----拼接数组里的字符
    • Math
    • System
    • BigDecimal----解决浮点型运算失真的问题
  • 日期与时间
    • Data----getTime
    • SimpleDataFormat----format 、 parse
      • format----将Data对象格式成时间格式
      • parse----将字符串时间格式解析成Data对象
    • Calendar
    • JDK8开始新增日期API----日期
      • LocalDate、LocalTime、LocalDateTime
      • Instant
      • DateTimeFormatter
      • Duration/Period
      • ChronoUnit
  • 包装类----toString、valueOf
    • toString----把基本类型数据转成字符串类型数据
    • valueOf----把字符串类型数据转成基本类型数据
  • 正则表达式
    • 匹配规则----matches
    • 爬取信息
  • Arrays----数组排序
    • 自定义类的排序----Comparator
  • 常见算法
    • 选择排序
    • 二分查找
  • Lambda----简化 重写方法
  • 集合
    • Collection集合体系
    • Collection常用API
    • Collection的遍历方式
      • 迭代器----Iterator
      • foreach/增强for循环----也可遍历数组
      • lambda表达式----forEach
    • Collection存储自定义类型的对象
    • Collection集合体系小结
  • 常见数据结构
    • 队列
    • 数组
    • 链表
    • 二叉树
      • 二叉查找树
      • 平衡二叉树
      • 红黑树
  • List
    • List特有API
    • List的遍历方式
    • ArraysList集合底层原理
    • LinkedList集合底层原理
    • 集合的并发修改异常问题----边遍历边删除
  • 泛型
    • 概述
    • 自定义泛型类
    • 自定义泛型方法
    • 自定义泛型接口
    • 泛型通配符、上下限
  • Set
    • HashSet元素无序的底层原理:哈希表
    • HashSet元素去重复的底层原理
    • LinkedHashSet
    • TreeSet
      • 自定义排序规则----Comparable
  • 可变参数----"int...nums"
  • 集合Collections工具类
    • API----addAll、shuffle
    • List集合自定义排序规则----Collections.sort
  • Map
    • 概述
    • 体系特点
    • 常用API
    • 遍历方式
      • 键找值----keySet、get
      • 键值对----entrySet、getKey、getValue
      • lambda表达式----forEach
    • 案例
    • Map集合的实现类----与Set集合差不多
      • HashMap
      • LinkedHashMap
      • TreeMap----自定义排序规则
  • 嵌套集合
  • 创建不可变集合----少用
  • Stream流
    • 概述
    • 集合、数组获取Stream流
    • Stream常用API
    • 综合应用
    • 收集Stream流
  • 异常
    • 概述
    • 常见运行时异常
    • 常见编译时异常
    • 异常的默认处理流程
    • 编译时异常的处理机制
      • try...catch...——出现异常可以使程序正常运行
    • 运行时异常的处理机制
    • 异常处理使代码更稳健
    • 自定义异常
  • 日志框架
    • 概述
    • 技术体系
    • Logback
      • 概述
      • 快速入门
      • 配置详情
        • 输出位置、格式设置
        • 日志级别设置
  • File
    • 概述
    • 常用API
      • 判断文件类型、获取文件信息
      • 创建、删除文件
      • 遍历
  • 方法递归
    • 概述
    • 算法流程
    • 案例
    • 非规律化递归
      • 文件搜索
      • 啤酒问题
  • 字符级
    • 概述
    • 解码、编码操作
  • IO流
    • 概述
    • 字节流的使用
      • 文件字节输入流:每次读取一个字节
      • 文件字节输入流:每次读取一个字节数组
      • 文件字节输入流:一次读完全部字节
      • 文件字节输出流:写字节数据到文件
      • 文件拷贝
    • 资源释放的方式
      • try-catch-finally
      • try-with-resource
    • 字符流的使用
      • 文件字符输入流:一次读取一个字符
      • 文件字符输入流:一次读取一个字符数组
      • 文件字符输出流
  • 缓冲流
    • 概述
    • 字节缓冲流
    • 字节缓冲流的性能分析
    • 字符缓冲流
      • 输入流
      • 输出流
    • 案例
  • 转换流
    • 字符输入转换流
    • 字符输出转换流
  • 序列化对象
    • 对象序列化
    • 对象反序列化
  • 打印流
    • PrintStream、PrintWriter
    • 输出语句的重定向
  • Properties
  • IO流框架
  • 线程
    • 概述
    • 多线程的创建
      • 方式一:继承Thread类
      • 方式二:实现Runnable接口
      • 方式三:实现Callable接口----可返回线程的执行结果
    • Thread的常用方法
    • 线程安全
    • 线程同步
      • 概述
      • 方式一:同步代码块
      • 方式二:同步方法
      • 方式三:Lock锁
    • 线程通信
      • 案例
    • 线程池
      • 概述
      • 线程池实现的API,参数说明
      • 线程池处理Runnable任务
      • 线程池处理Callable任务
      • Executors工具类实现线程池
    • 定时器
      • 方式一:Timer
      • 方式二:ScheduledExecutorService----更常用
    • 线程并发、并行
    • 线程的生命周期
  • 网络编程
    • 网络通信三要素
      • IP地址
      • IP地址操作类--InetAddress
      • 端口号
      • 协议
    • UDP通信
      • 快速入门----一发一收
      • 多发多收
      • 广播、组播
        • 广播
        • 组播
    • TCP通信
      • 快速入门
        • 客户端
        • 服务端
      • 多发多收
      • 同时接收多个客户端消息
      • 使用线程池优化
      • 及时通信
      • 模拟BS系统
  • 单元测试
    • 概述
    • 快速入门
    • 常用注解
  • 反射
    • 概述
    • 获取类对象
    • 获取构造器对象
    • 获取成员变量对象
    • 获取方法对象
    • 反射的作用
      • 绕过编译阶段为集合添加数据
      • 通用框架的底层原理
  • 注解
    • 概述
    • 自定义注解
    • 元注解
    • 注解解析
    • junit框架
  • 动态代理
    • 概述
    • 快速入门
    • 动态代理的应用案例:性能分析
  • XML
    • 概述
    • XML的创建和语法规则
    • XML文档约束
      • 方式一:DTD约束
      • 方式二:schema约束
  • XML解析技术
    • 概述
    • Dom4J解析XML文件
    • Dom4J解析XML文件中的各种节点
    • 案例
  • XML检索技术:Xpath
    • 绝对路径
    • 相对路径
    • 全文搜索
    • 属性查找
  • 设计模式
    • 工厂模式
    • 装饰模式
  • 完结

常用快捷键

Ctrl + D 复制本行代码
Ctrl + X 剪切本行代码
Alt + Shift + 方向键 移动本行代码
Ctrl + Alt + T 在选定代码上,外加代码(分支或循环等等)
Ctrl + Alt + V 补全代码
Shift + F6 直接一次性改名称
Ctrl + Alt + L 格式化数组

IDEA IJ 的一些使用

File–Project Structure–可以修改Module JDK版本

注释

快捷键:Ctrl + / 或 Ctrl + Shift +/

字面量

System.out.println(‘\n’); 代表换行
System.out.println(‘\t’); 代表一个tab

String 接字符串
char 接字符

变量

格式:数据类型 变量名称 = 初始值;

      数据类型 变量名称; 这是在定义一个变量。     int a;变量名称 = 初始值; 这是在赋值。               a = 10;

强制类型转换

数据类型 变量1 = (数据类型)变量2;
int a = 20;
byte b = (byte) a;

运算符

取余:%

在Java中,两整数相除结果还是整数,想要有小数位要在变量后*1.0。

连接运算符 ‘+’

优先从左算起

自增自减运算符 ‘++’ ‘–’

运算符在变量前:先对变量进行运算,再使用变量。
运算符在变量后:先使用变量,再对变量进行运算。

赋值运算符

关系运算符

逻辑运算符

短路逻辑运算符

三元运算符

运算符优先等级

键盘录入技术

分支

if分支

switch分支


表达式类型只能是:byte、short、int、char
case给出的值不允许重复,且只能是字面量,不能是变量。

switch的穿透性


循环结构

知道循环几次用for,不知道循环几次用while。
for循环定义的变量只能在for循环内使用,while循环需要在循环外定义变量。

for循环


快捷写法:for+i 。

while循环

do-while循环

死循环

嵌套循环


跳转关键字

如果是嵌套循环,想要结束外部循环,要使用break OUT;

随机数



数组

静态初始化数组


动态初始化数组


数组的遍历


快捷键:a.for+i

数组中的元素交换

要定义临时变量

方法



方法定义技巧

1.分析方法是否需要申明返回值类型。
2.分析方法是否需要接收参数。

返回数组的方法的定义与调用

方法参数的传递机制:值传递

基本类型传递的是数据值,如果使用方法时方法改变变量值,但方法使用后,变量值不变。

引用类型传递的是地址值,如果使用方法时方法改变数组数值,方法使用后,数组数值将会改变。

方法重载

同一个类中,出现多个方法名称相同,但是形参列表是不同的,那么这些方法就是重载方法。
形参列表不同指的是形参的个数、类型、顺序不同。

return 关键字


算法----信号位思想flag

案例:使随机数不重复的方法

案例:找素数

面向对象(oop)

设计对象并使用


对象在内存中的运行机制


对象储存在堆内存中
变量名称 c1 储存的是对象在堆内存中的地址
成员变量的数据储存在堆内存中

构造器

this关键字

this出现在有参数构造器中的用法

封装----private


封装private

调用

标准JavaBean

JavaBean:也可以称为实体类,其对象可以用于在程序中封装数据。

快捷键

为成员变量提供getter 和setter方法时,快捷写法为直接鼠标右键选中Generate,然后选择Getter and Setter 。
写有参数构造器时,快捷写法为鼠标右键选中Generate,然后选择 Constructor 。
写无参数构造器时,快捷写法为鼠标右键选中Generate,然后选择 Constructor ,再选择 Select None 。

成员变量和局部变量的区别

API

String

概述

创建字符串对象的2种方式

方式二中常用第三、四种:(如下)

两种方式的区别

方式一原理

方式二原理

String类常用API

遍历

方法一:获取某个索引位置处的字符

方法二:将当前字符串转换成字符数组返回

截取----substring

方式一:根据开始和结束索引进行截取(包前不包后)。

方式二:从传入的索引处截取,截取到末尾。

替换----replace

分割----split

String字符串的内容比较----equals

字符串内容比较不能用“==”,因为它比较的是字符串的地址,无法比较内容。

ArrayList

概述

ArrayList添加元素的API

ArrayList的泛型使用

一般使用ArrayList都要使用泛型,这样才更规范。

ArrayList的常用API

遍历

使用 get 和 size 。

ArrayList边遍历边删除元素


static

static关键字----可以在任何地方被访问

修饰成员变量

修饰成员方法

注意事项

static-工具类

private 类名(){//工具类私有方法,私有后无法使用该类new对象}

static-代码块----面向对象

static-单例设计模式


单例第一步先将构造器私有化

private 类名 (){}

饿汉单例

先提前创建一个对象

步骤:

懒汉单例

在真正需要对象的时候,才去创建一个对象(延迟加载对象)

private 私有静态成员变量,就无法直接调用成员变量。

面向对象----继承----extends

继承特点

子类不可以直接使用父类的私有方法
子类可以使用父类的静态成员变量

成员变量、成员方法访问特点

方法重写----@Override

构造器特点


public 子类 (){super();}





子类调用父类有参数构造器:

public 子类 (){super(父类成员变量,父类成员变量,);
}


this、super 总结

面向对象----语法

权限修饰符----public等


final


常量----public static final


枚举–enum


抽象类–abstract

特征和注意事项

模块方法模式


接口–interface


接口会默认公开,所以常量可以省略public static final 不写,抽象方法可以省略public abstract不写。

接口多实现–implement


接口多继承


接口新增方法

注意事项

面向对象----多态

优势

多态下引用数据类型的类型转换

//父类
public class User {}//子类
public class Customer extends User{}//子类
public class Business extends User {}
//创建几个对象
User user;
Customer customer;
Business business;

子类对象转为父类类型----自动类型转换

User user = business;
User user = customer;

父类对象转为子类类型----强制类型转换

Customer customer = (Customer)user;
Business business = (Business)user;

instanceof----判断当前对象的真实类型

//判断当前父类对象是哪个子类类型
user instanceof Customer

内部类----面向对象

静态内部类

成员内部类

局部内部类

匿名内部类


使用形式

常用API

Object

toString----返回对象内容,而不是返回地址

快捷键:子类重写直接用Genenrate–toString() 。

@Overridepublic String toString() {return "Movie{" +"name='" + name + '\'' +", score=" + score +", actor='" + actor + '\'' +'}';}

equals----比较内容是否相同,而不是地址


子类重写直接用Generate–equals() and hashCode() , 然后去掉hashCode() 。

@Overridepublic boolean equals(Object o) {if (this == o) return true;if (o == null || getClass() != o.getClass()) return false;Movie movie = (Movie) o;return Double.compare(movie.score, score) == 0 && Objects.equals(name, movie.name)&& Objects.equals(actor, movie.actor);}

Objects----new对象进行内容比较时使用

Objects.equals----避免空指针异常

Objects.equals(s1, s2)

StringBuilder----拼接数组里的字符

StringBuilder sb = new StringBuilder();


可以使用链式结构

变量.append().append().append().reverse();
//拼接数组里的字符
StringBuilder sb = new StringBuilder("[");for (int i = 0; i < arr.length; i++) {sb.append(i == arr.length-1 ? arr[i] : arr[i] + ", ");}sb.append("]");System.out.println(sb);
拿出StringBuilder里的字符
//遍历拿出所以字符
for (int i = 0; i < sb.length(); i++) {char ch = sb.charAt(i);
}

Math

System

BigDecimal----解决浮点型运算失真的问题

//获取BigDecima对象
double a = 12;
double b = 5;
BigDecimal a = BigDecimal.valueOf(a);//将数据a封装到BigDecimal中。
BigDecimal b = BigDecimal.valueOf(b);
double c = a.divide(b);
double c = BigDecimal.valueOf(a).divide(BigDecimal.valueOf(b)).doubleValue();

日期与时间

Data----getTime

SimpleDataFormat----format 、 parse

format----将Data对象格式成时间格式

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日 HH:mm:ss EEE a ");//EEE 代表 星期几 , a 代表 上下午 。

parse----将字符串时间格式解析成Data对象


字符串日期格式必须与SimpleDataFormat的格式相同。

Calendar

        Calendar cal = Calendar.getInstance();//直接调方法,不是new对象。

JDK8开始新增日期API----日期

LocalDate、LocalTime、LocalDateTime


Instant

DateTimeFormatter

Duration/Period

ChronoUnit

包装类----toString、valueOf


toString----把基本类型数据转成字符串类型数据

//把数组内容转成集合,可以直接输出
Arrays.toString();

valueOf----把字符串类型数据转成基本类型数据

 //直接调用valueOf,不用记的麻烦。String s = Integer.valueOf();String s = Double.valueOf();

正则表达式

匹配规则----matches

matches("\\d") \\要求字符串内容为一个,且范围为0-9。
matches("\\d{4}") \\要求字符串内容要大于4个,且范围为0-9。
matches("\\d{4,20}") \\要求字符串内容要大于4个,且小于20个,且范围为0-9。
matches("1[3-9]\\d{9}") \\要求字符串第一个字符为1,第二个字符范围为3-9,其余的字符个数为9且范围为0-9。
matches("\\.") \\要求字符为"."  。
matches("1?") \\要求1出现一次或者不出现。 //以此类推*、+ 。

爬取信息

Arrays----数组排序

使用binarySearch时,必须让数组排好序,否则会出bug 。

Arrays.toString()  //打印数组内容

自定义类的排序----Comparator

自定义类排序:
Arrays.sort(Student, new Comparator<Student>() {//如果是自定义的学生类,想要按照年龄、身高来排序,方法如下:@Overridepublic int compare(Student o1, Student o2) {    return o1.getAge() - o2.getAge();return Double.compare(o1.getHeight() , o2.getHeight());//小数的比较。因为return返回的是int类型。}});

常见算法

选择排序

for (int i = 0; i < arr.length - 1; i++) {for (int j = i+1 ; j < arr.length; j++) {if (arr[i] > arr[j]){int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}}System.out.println(Arrays.toString(arr));

二分查找


 public static int search(int [] arr , int data){int left = 0;int right = arr.length-1;while (left <= right){int middle = (left + right)/2;if (data > arr[middle]){left = middle +1;}else if (data < arr[middle]){right = middle -1;}else {return middle;}}return -1;}

Lambda----简化 重写方法

Swimming s = new Swimming() {@Overridepublic void swim() {System.out.println("");}};
Swimming s1 = () ->{System.out.println("");};go(new Swimming() {@Overridepublic void swim() {System.out.println("");}});
go(() ->{System.out.println("");});

集合


Collection集合体系


Collection常用API

Collection的遍历方式

迭代器----Iterator

//遍历方式
Iterator<Integer> it = list.iterator();while (it.hasNext()){System.out.println(it.next());}

foreach/增强for循环----也可遍历数组

//快捷键
数组或集合名.for 回车

lambda表达式----forEach

//代码简化
list.forEach(new Consumer<String>() {@Overridepublic void accept(String s) {System.out.println(s);}});list.forEach( s ->{System.out.println(s);});list.forEach( s -> System.out.println(s));list.forEach(System.out::println);

Collection存储自定义类型的对象

//定义一个电影类
Collection<Movie> movies = new ArrayList<>();movies.add(new Movie("肖申克",9.9,"小李子"));movies.add(new Movie("成立",9.3,"陈列"));movies.add(new Movie("肖克",9.6,"李子"));//遍历----foreachfor (Movie movie : movies) {System.out.println(movie.getName());System.out.println(movie.getScore());System.out.println(movie.getActor());}

Collection集合体系小结

常见数据结构

队列

数组

链表


二叉树

特点:

二叉查找树

平衡二叉树





红黑树


List

List<String> list = new ArrayList<>();

List特有API


List<String> list = new ArrayList();
list.indexOf(输入字符);//根据输入字符,提取字符所在的索引
list.substring(输入索引);//根据输入的索引,提取相对应的字符串

List的遍历方式

1.迭代器
2.foreach
3.lambda

4.for循环

for (int i = 0; i < list.size(); i++) {System.out.println(list.get(i));}

ArraysList集合底层原理

LinkedList集合底层原理

集合的并发修改异常问题----边遍历边删除

Iterator<String> it = list.iterator();while (it.hasNext()){String ele = it.next();if (ele.equals("要删除的对象")){it.remove(); //迭代器自己的方法}}
for (int i = 0; i < list.size(); i++) {String s = list.get(i);if (s.equals("1")){list.remove(i);i--;}}for (int i = list.size()-1; i >=0 ; i--) {String s = list.get(i);if (s.equals("1")){list.remove(i);}}

泛型

概述


自定义泛型类


自定义泛型方法


自定义泛型接口


泛型通配符、上下限


Set

Set<String> set = new HashSet<>();

HashSet元素无序的底层原理:哈希表


HashSet元素去重复的底层原理

LinkedHashSet

TreeSet


自定义排序规则----Comparable


方式一:类自定义比较规则。
//接口Comparable
public class Student implements Comparable<Student> {private String name;private int age;private double height;//重写排序规则@Overridepublic int compareTo(Student o) {return this.age - o.age;//相同的元素会去掉return this.age - o.age >= 0 ? 1 :-1 ; //相同的元素可以保留。}
}
方式二:集合自带比较器对象进行规则自定。
Set<Student> set = new TreeSet<>(new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return o1.getAge() - o2.getAge();return Double.compare(o1.getHeight() , o2.getHeight());//浮点型比较}});简化:
Set<Student> set = new TreeSet<>(( o1,  o2) ->
Double.compare(o1.getHeight() , o2.getHeight())  );Set<Student> set = new TreeSet<>(( o1,  o2) -> o1.getAge() - o2.getAge()  );

可变参数----“int…nums”

 public static void sum(int...nums){}

集合Collections工具类

API----addAll、shuffle

Collections.addAll(list,"");Collections.shuffle(list);

List集合自定义排序规则----Collections.sort

方式一:
Collections.sort(list);//在自定义类中要先重写比较规则,然后可以直接调用。//使用接口Comparable
public class Student implements Comparable<Student> {//重写排序规则@Overridepublic int compareTo(Student o) {return this.age - o.age;}
}
方式二:
List<> list =new Arrayslist<>();Collections.sort(list, new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return Double.compare(o1.getHeight(),o2.getHeight());//浮点型return o1.getAge() - o2.getAge();}});简化:
Collections.sort(list,( o1,  o2) -> Double.compare(o1.getAge(),o2.getAge()) );

Map

概述

体系特点

Map<String,Integer> map = new HashMap<>();

常用API

遍历方式

键找值----keySet、get

Map<String,Integer> map = new HashMap<>();//先拿到全部键
Set<String> keys = map.keySet();
//再遍历得每个键的值for (String key : keys) {int value = map.get(key);//获取值System.out.println(key +"===>" + value);}

键值对----entrySet、getKey、getValue

Map<String,Integer> map = new HashMap<>();Set<Map.Entry<String, Integer>> entries = map.entrySet();for (Map.Entry<String, Integer> entry : entries) {String key =entry.getKey();int value = entry.getValue();System.out.println(keys +"===>" + value);}

lambda表达式----forEach

map.forEach(new BiConsumer<String, Integer>() {@Overridepublic void accept(String s, Integer integer) {System.out.println(s + "---->" + integer);}});简化:
map.forEach(( s,  integer) -> {System.out.println(s + "---->" + integer);});

案例

//随机输出定义的4个数据0
String[] s = {"A","B","C","D"};StringBuilder stringBuilder = new StringBuilder();Random r = new Random();for (int i = 0; i < 80; i++) {stringBuilder.append(s[r.nextInt(4)]);}System.out.println(stringBuilder);Map<Character,Integer> map = new HashMap<>();//for (int i = 0; i < stringBuilder.length(); i++) {char ch = stringBuilder.charAt(i);if (map.containsKey(ch)) {map.put(ch,map.get(ch) + 1);}else {map.put(ch,1);}}System.out.println(map);

Map集合的实现类----与Set集合差不多

HashMap

LinkedHashMap

TreeMap----自定义排序规则

方式一:类自定义比较规则。
//接口Comparable
public class Student implements Comparable<Student> {private String name;private int age;private double height;//重写排序规则@Overridepublic int compareTo(Student o) {return this.age - o.age;//相同的元素会覆盖}
}//main方法中直接输出
Map<Student , Integer> map = new TreeMap<>();
System.out.println(map);
方式二:集合自带比较器
Map<Student , Integer> map = new TreeMap<>(new Comparator<Student>() {@Overridepublic int compare(Student o1, Student o2) {return Double.compare(o1.getHeight(),o2.getHeight());//浮点型}});

嵌套集合

//嵌套集合格式:
Map<String, List<String>> map = new HashMap<>();List<String> list = new ArrayList<>();Collections.addAll(list,"A","B");map.put("小米",list);System.out.println(map);
        Map<String, List<String>> map = new HashMap<>();//创建集合,将list集合中的元素添加到Map集合中List<String> list1 = new ArrayList<>();Collections.addAll(list1,"A","C");//直接添加多个数据map.put("小米",list1);List<String> list2 = new ArrayList<>();Collections.addAll(list2,"A","D");map.put("小蓝",list2);List<String> list3 = new ArrayList<>();Collections.addAll(list3,"A","B","C");map.put("小新",list3);System.out.println(map);//统计数据,算出map中值重复了多少Map<String,Integer> infos = new HashMap<>();//创建集合储存map中的值Collection<List<String>> values = map.values();//拿到map中的所有值,将它储存在Collection集合中。System.out.println(values); //values = [[A, D], [A, B, C], [A, C]]//遍历集合,把集合中的元素遍历出来for (List<String> value : values) {//这个是遍历Collection集合中所有的list集合for (String s : value) {//这是遍历list集合里的每个元素//判断infos集合中是否有这个元素if (infos.containsKey(s)){infos.put(s,infos.get(s) + 1);}else {infos.put(s,1);}}}System.out.println(infos);

创建不可变集合----少用



JDK8不可用
List<Double> list = List.of(12.1,34.5,67.8);

Stream流

概述

     //名字分类,传统办法:List<String> name = new ArrayList<>();Collections.addAll(name,"张倩", "张强前","张作者","周中");//添加多个元素//按姓氏分List<String> zhangName = new ArrayList<>();for (String s : name) {if (s.startsWith("张")){zhangName.add(s);}}System.out.println(zhangName);//按姓名长度分List<String> zhangThereName = new ArrayList<>();for (String s : zhangName) {if (s.length()==3){zhangThereName.add(s);}}System.out.println(zhangThereName);//stream流一步完成//可以支持链式结构name.stream().filter(s-> s.startsWith("张")).filter(s-> s.length()==3).forEach(s -> System.out.println(s));

集合、数组获取Stream流

        //Collection集合获取流List<String> list = new ArrayList<>();Stream<String> s = list.stream();//Map集合获取流Map<String,Integer> map = new HashMap<>();Stream<String> keyStream = map.keySet().stream();//键获取流Stream<Integer> valueStream = map.values().stream();//值获取流Stream<Map.Entry<String,Integer>> keyAndKeyStream = map.entrySet().stream();//键值对获取流//数组获取流String[] names = {"小米","小红","小新"};Stream<String> nameStream = Arrays.stream(names);Stream<String> nameStream1 = Stream.of(names);

Stream常用API

        name.stream().filter(new Predicate<String>() {@Overridepublic boolean test(String s) {return s.startsWith("张");}});简化:name.stream().filter(s-> s.startsWith("张")).
//遍历
).forEach(s -> System.out.println(s));简化:
).forEach(System.out::println);
//返回流长度
long size = list.stream().count();
//map加工方法
//给集合元素前加上字符串
list.stream().map(s -> "" + s).//把集合所有的元素都加工成Student对象
list.stream().map(s -> new Student(s)).forEach(s -> System.out.println(s));简化:
list.stream().map(Student::new).forEach(System.out::println);
//合并两个流
Stream<String> = Stream.concat(stream1,stream2);

综合应用

one.stream().max((e1,e2) -> Double.compare(e1.getSalary()+e1.getBonus() ,e2.getSalary()+e2.getBonus())).map(e -> new Top(e.getName(),e.getSalary()+e.getBonus())).get();
//max方法自定义类比较方法,直接取出最大值对象,map方法将对象储存到新的类对象中。
one.stream().sorted((e1,e2) -> Double.compare(e1.getSalary()+e1.getBonus() ,e2.getSalary()+e2.getBonus())).skip(1).limit(one.size()-2).forEach(s -> {allMoney += s.getBonus() + s.getSalary();//要在main方法外定义一个公开静态成员变量});
//sorted方法自定义类比较规则, 将集合中的对象排序,

收集Stream流

     //List集合Stream<String> s1 = name.stream().filter(s -> s.startsWith("张"));List<String> list = s1.collect(Collectors.toList());System.out.println(list);//stream流只能使用一次,再次使用时要重写stream() 。//Set集合Stream<String> s2 = name.stream().filter(s -> s.startsWith("张"));Set<String> set = s2.collect(Collectors.toSet());System.out.println(set);//数组Stream<String> s3 = name.stream().filter(s -> s.startsWith("张"));Object[] arr =s3.toArray();System.out.println(Arrays.toString(arr));

异常

概述

常见运行时异常

常见编译时异常

异常的默认处理流程

编译时异常的处理机制

try…catch…——出现异常可以使程序正常运行


快捷键:Ctrl + Alt + T ----try/catch

运行时异常的处理机制

异常处理使代码更稳健

     //使异常出现后代码可以继续运行,而不会程序死亡。Scanner sc = new Scanner(System.in);while (true){try {//可能出现异常的代码行System.out.println("请输入定价:");String priceStr = sc.nextLine(); //只能输入一行代码。double price = Double.valueOf(priceStr);//转换成double类型if (price > 0){System.out.println("定价:"+price);break;}else {System.out.println("输入有误");}} catch (Exception e) {//处理异常,使出现异常后代码可以继续运行System.out.println("重写输入");}}

自定义异常

编译时异常
//定义一个异常类继承Exception
public class Text extends Exception{//重写构造器public Text(String message) {super(message);}public Text() {}
}public static void main(String[] args) {try {checkAge(-34);} catch (Text e) {throw new RuntimeException(e);}}public static void checkAge(int age) throws Text {if (age < 0 || age >200){//抛出一个异常对象给调用者//throw:在方法内部直接创建一个异常对象,并从此点抛出//throws:用在方法申明上的,抛出方法内部的异常。throw new Text(age + " is false");}else {System.out.println("合法");}}
运行时异常
//定义一个类继承RuntimeException
public class Text extends RuntimeException{public Text(String message) {super(message);}public Text() {}
}public static void main(String[] args) {try {checkAge(-34);} catch (Text e) {throw new RuntimeException(e);}}public static void checkAge(int age) throws Text {if (age < 0 || age >200){//抛出一个异常对象给调用者//throw:在方法内部直接创建一个异常对象,并从此点抛出//throws:用在方法申明上的,抛出方法内部的异常。throw new Text(age + " is false");}else {System.out.println("合法");}}

日志框架

概述

技术体系

Logback

概述

快速入门

public static final Logger LOGGER = LoggerFactory.getLogger("MovieSystem.class");
//logback.xml 文件代码
//<file>和<fileNamePattern>文件要自己改变路径
<?xml version="1.0" encoding="UTF-8"?>
<configuration><!--CONSOLE :表示当前的日志信息是可以输出到控制台的。--><appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"><!--输出流对象 默认 System.out 改为 System.err--><target>System.out</target><encoder><!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符--><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level]  %c [%thread] : %msg%n</pattern></encoder></appender><!-- File是输出的方向通向文件的 --><appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"><encoder><pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern><charset>utf-8</charset></encoder><!--日志输出路径--><file>D:\Logback\data.log</file><!--指定日志文件拆分和压缩规则--><rollingPolicyclass="ch.qos.logback.core.rolling.SizeAndTimeBasedRollingPolicy"><!--通过指定压缩文件名称,来确定分割文件方式--><fileNamePattern>D:\Logback\data-%d{yyyy-MM-dd}.log%i.gz</fileNamePattern><!--文件拆分大小--><maxFileSize>1MB</maxFileSize></rollingPolicy></appender><!--level:用来设置打印级别,大小写无关:TRACE, DEBUG, INFO, WARN, ERROR    |    ALL 和 OFF, 默认debug<root>可以包含零个或多个<appender-ref>元素,标识这个输出位置将会被本日志级别控制。--><root level="ALL"><!-- 注意:如果这里不配置关联打印位置,该位置将不会记录日志--><appender-ref ref = "CONSOLE"/><appender-ref ref="FILE" /></root>
</configuration>
 //记录系统的日志信息,会在路径生成TXT文档public static final Logger LOGGER =  LoggerFactory.getLogger("Text");public static void main(String[] args) {try {LOGGER.debug("开始运行");LOGGER.info("开始记录日志");int a = 10;int b = 0;LOGGER.trace("a:" + a);LOGGER.trace("b:" + b);System.out.println(a/b);} catch (Exception e) {e.printStackTrace();LOGGER.error("功能出现异常" + e);}}

配置详情

输出位置、格式设置

<appender-ref ref = "CONSOLE"/> //会打印在控制台中,不打就不会影响运行流程。
<appender-ref ref="FILE" /> //会打印在生产文件中
     <!--输出流对象 默认 System.out 改为 System.err-->//改完后打印内容会变红<target>System.out</target>
//符号代表的意思
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%-5level]  %c [%thread] : %msg%n</pattern>

日志级别设置

<root level="ALL">

File

概述


//绝对路径
//路径的三种写法
File file = new File("D:\\Logback\\data.log");
File file = new File("D:/Logback/data.log");
File file = new File("D:" +File.separator+ "Logback"+ File.separator+"data.log");//相对路径
//创建一个New Project,而不是Empty Module。
//从src目录开始查找就行
File f = new File("src/data.txt");

常用API

判断文件类型、获取文件信息

创建、删除文件

遍历

方法递归

概述

算法流程

 public static void main(String[] args) {System.out.println(f(5));//f(4)*5//f(3)*4*5//f(2)*3*4*5//f(1)*2*3*4*5}//阶乘计算public static int f(int n){if (n == 1){return 1;}else {return f(n-1)*n;}}
 public static void main(String[] args) {System.out.println(f(100));}//求和计算public static int f(int n){if (n == 1){return 1;}else {return f(n-1)+n;}}

案例

 //公式:f(x) - f(x)/2 - 1 = f(x-1)//      f(x) = 2*f(x) + 2  public static void main(String[] args) {System.out.println(f(1));}public static int f (int n){if (n == 10){return 1;}else {return 2*f(n+1) + 2;}}

非规律化递归

文件搜索

 public static void main(String[] args) {search(new File("D:/"),"#ib_redo6");}//文件搜索方法public static void search (File dir , String fileName){//判断源dir是否是目录if (dir != null && dir.isDirectory()){//提取一级文件File [] files = dir.listFiles();//判断一级文件对象集合是否存在if (files != null && files.length > 0 ){//遍历所有一级文件对象for (File file : files) {//判断一级文件对象是文件还是目录if (file.isFile()){//为文件的话,判断是否为要查找的文件if (file.getName().contains(fileName)){System.out.println("找到了" + file.getAbsolutePath());}}else {//为目录,流程重复search(file , fileName);}}}}else {System.out.println("目录不存在");}}

啤酒问题

 public static void main(String[] args) {buy(10);}//定义一个变量来储存总共买酒的数量public static int totalNumber;//定一个义变量储存每次用酒瓶换完酒后酒瓶剩余的数量public static int lastBottleNumber;//定一个义变量储存每次用瓶盖换完酒后瓶盖剩余的数量public static int lastCoverNumber;//买酒方法public static void buy(int money){//直接计算钱可以买多少酒int buyNumber = money / 2;totalNumber += buyNumber;//统计本轮瓶子数和盖子数,要加上上次换酒后剩的。int BottleNumber =lastBottleNumber + buyNumber;int CoverNumber = lastCoverNumber + buyNumber;//拿酒瓶换钱int allMoney = 0;if (BottleNumber >= 2){allMoney += (BottleNumber/2) * 2;}lastBottleNumber = BottleNumber%2;//拿瓶盖换钱if (CoverNumber >= 4){allMoney += (CoverNumber/4) * 2;}lastCoverNumber = CoverNumber%4;//判断是否可以继续买酒if (allMoney >= 2){buy(allMoney);}else {System.out.println("酒的总数" + totalNumber);System.out.println("剩余瓶子数" + lastBottleNumber);System.out.println("剩余盖子数" + lastCoverNumber);}}

字符级

概述

解码、编码操作

     String name = "abc我爱你";byte [] bytes = name.getBytes();//将字符串默认编码成字节System.out.println(bytes.length);System.out.println(Arrays.toString(bytes));//输出字节编码String rs = new String(bytes);//默认解码System.out.println(rs);String name = "abc我爱你";byte [] bytes = name.getBytes("GBK");//指定编码System.out.println(bytes.length);System.out.println(Arrays.toString(bytes));String rs = new String(bytes,"GBK");//指定解码System.out.println(rs);

IO流

概述

字节流的使用

文件字节输入流:每次读取一个字节

     //创建字节输入流管道与源文件路径接通InputStream is = new FileInputStream(new File("src/data"));InputStream is = new FileInputStream("src/data");//简化写法//读取一个字符int b1 = is.read();System.out.println((char) b1);int b2 = is.read();System.out.println((char) b2);int b3 = is.read();System.out.println((char) b3);//循环读取所有字符//但是不能读取中文,因为read每次只能读取一个字节,而中文包含三个字节,会出现bugint b;while ((b = is.read()) != -1){System.out.print((char) b);}

文件字节输入流:每次读取一个字节数组

        InputStream is = new FileInputStream("src/data");//定义一个字节数组,用来储存读取的字节byte[] buffer = new byte[3];int len = is.read(buffer);//读取字节到数组中,返回字节个数System.out.println(len);//输出读取字节个数//编译字节数组//但是当字节数组个数不满足3个时,会出现bugString rs = new String(buffer);//解码System.out.println(rs);//读取多少字节就从数组中输出多少个字节,不会出bugString rs = new String(buffer,0,len);//解码,把字节转成字符串System.out.println(rs);
        InputStream is = new FileInputStream("src/data");//循环读取所有字符byte [] buffer = new byte[3];int len;//记录每次读取的字节数while ((len = is.read(buffer)) != -1){System.out.print(new String(buffer, 0, len));//解码}//但是此种方式还是会出现bug,当字符形式为“ab我”时,为了读取3个字符,会把中文的三个字符拆出来读取一个。

文件字节输入流:一次读完全部字节

        //创建一个文件储存所有字节File f = new File("src/data");InputStream is = new FileInputStream(f);//定义一个字节数组,大小和文件一样byte [] buffer = new byte[(int) f.length()];int len = is.read(buffer);//读取字节到数组中//编码System.out.println(len);System.out.println(f.length());System.out.println(new String(buffer));//解码//读取全部字节的API//但是这个API是从JDK9才开始支持byte [] buffer = is.readAllBytes();System.out.println(new String(buffer));

文件字节输出流:写字节数据到文件

     //创建一个文件字节输出流管道与目标文件接通OutputStream os = new FileOutputStream("src/date.txt");//每次输出前,会先清空文件之前的数据OutputStream os = new FileOutputStream("src/date.txt",true);//每次输出可以叠加之前的数据//写一个字节出去os.write('a');os.write(97);os.write('徐');//无法输出,因为每次只能输出一个字节os.write("\r\n".getBytes());//换行//写一个数组出去byte [] buffer = {98,'a','b'};os.write(buffer);os.write("\r\n".getBytes());//换行//将一个字符串转成字节储存到数组byte [] buffers = "abc我是中国人".getBytes();os.write(buffers);//输出数组os.write("\r\n".getBytes());//输出数组的一部分byte [] buffer1 = {'a',97,98};os.write(buffer1,0,1);//就会输出“a、97”//写完数据,一定要刷新或释放数据//写完数据,必须刷新数据,把缓存的数据到输出。//使用后可以继续使用流os.flush();//释放资源,包含刷新数据。//使用后不可以继续使用流os.close();

文件拷贝

         //拷贝视频、文件、图片try {//输入流InputStream is = new FileInputStream("");//输出流OutputStream os = new FileOutputStream("");//数组储存字节byte[] buffer = new byte[1024];int len;//每次读取长度//循环输出字节数组while ((len = is.read(buffer)) != -1) {os.write(buffer, 0, len);}System.out.println("完成");//关闭流os.close();is.close();} catch (Exception e) {e.printStackTrace();}

资源释放的方式

try-catch-finally

     //定义在try外,finall才能执行InputStream is = null;OutputStream os = null;//拷贝视频、文件、图片try {//输入流is = new FileInputStream("");//输出流os = new FileOutputStream("");//数组储存字节byte[] buffer = new byte[1024];int len;//每次读取长度//循环输出字节数组while ((len = is.read(buffer)) != -1) {os.write(buffer, 0, len);}System.out.println("完成");} catch (Exception e) {e.printStackTrace();//无论代码是正常还是出现异常都会执行这里} finally {//关闭流try {//非空判断if (os != null)os.close();} catch (Exception e) {e.printStackTrace();}try {//非空判断if (os != null)is.close();} catch (Exception e) {e.printStackTrace();}}

try-with-resource

     try (//这里面只能放置资源对象,用完会自动关闭//自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)//输入流InputStream is = new FileInputStream("");//输出流OutputStream os = new FileOutputStream("");){//数组储存字节byte[] buffer = new byte[1024];int len;//每次读取长度//循环输出字节数组while ((len = is.read(buffer)) != -1) {os.write(buffer, 0, len);}System.out.println("完成");} catch (Exception e) {e.printStackTrace();}

字符流的使用


文件字符输入流:一次读取一个字符

     //创建一个字符输入流管道与源文件相接Reader fr = new FileReader("src/data.txt");//读取一个字符int code = fr.read();System.out.println((char) code);//循环读取所有字符int code;while ((code = fr.read()) != -1){System.out.print((char) code);}

文件字符输入流:一次读取一个字符数组

     //创建一个字符输入流管道与源文件相接Reader fr = new FileReader("src/data.txt");//用循环读取一个字符数组数据char [] buffer = new char[1024];int len;while ((len = fr.read(buffer)) != -1){String rs = new String(buffer,0,len);System.out.println(rs);}

文件字符输出流

     //创建一个字符输出流管道与目标文件接通Writer fw = new FileWriter("src/data");//覆盖管道,会清空之前文件的数据Writer fw = new FileWriter("src/data",true);//追加数据,不会清空之前文件的数据//写一个字符出去fw.write('a');fw.write(97);fw.write('徐');//不会出bugfw.write("\r\n");//换行//写一个字符串出去fw.write("abc我是中国人");fw.write("\r\n");//换行//写一个字符数组出去char [] chars = "abc我是中国人".toCharArray();//把字符串转成字符fw.write(chars);fw.write("\r\n");//换行//写字符串的一部分出去fw.write("abc我是中国人",0,3);fw.write("\r\n");//换行//写字符数组的一部分出去fw.write(chars,3,5);fw.write("\r\n");//换行fw.flush();//刷新流fw.close();//关闭流

缓冲流

概述

字节缓冲流

     //拷贝视频、文件、图片try (//这里面只能放置资源对象,用完会自动关闭//自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)//输入流InputStream is = new FileInputStream("");//把原始的字节输入流包装成高级的缓冲字节输入流InputStream bis = new BufferedInputStream(is);//输出流OutputStream os = new FileOutputStream("");//把原始的字节输出流包装成高级的缓冲字节输出流OutputStream bos = new BufferedOutputStream(os);){//数组储存字节byte[] buffer = new byte[1024];int len;//每次读取长度//循环输出字节数组while ((len = bis.read(buffer)) != -1) {bos.write(buffer, 0, len);}System.out.println("完成");} catch (Exception e) {e.printStackTrace();}

字节缓冲流的性能分析

原始流加上8kb的桶,效果和高级流一样

     //高级流拷贝//拷贝视频、文件、图片try (//这里面只能放置资源对象,用完会自动关闭//自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)//输入流InputStream is = new FileInputStream("");//把原始的字节输入流包装成高级的缓冲字节输入流InputStream bis = new BufferedInputStream(is);//输出流OutputStream os = new FileOutputStream("");//把原始的字节输出流包装成高级的缓冲字节输出流OutputStream bos = new BufferedOutputStream(os);){//数组储存字节byte[] buffer = new byte[1024];int len;//每次读取长度//循环输出字节数组while ((len = bis.read(buffer)) != -1) {bos.write(buffer, 0, len);}System.out.println("完成");} catch (Exception e) {e.printStackTrace();}//原始流加上8kb的桶,效果和高级流一样//原始流拷贝//拷贝视频、文件、图片try (//这里面只能放置资源对象,用完会自动关闭//自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)//输入流InputStream is = new FileInputStream("");//输出流OutputStream os = new FileOutputStream("");){//数组储存字节byte[] buffer = new byte[1024 * 8];int len;//每次读取长度//循环输出字节数组while ((len = bis.read(buffer)) != -1) {bos.write(buffer, 0, len);}System.out.println("完成");} catch (Exception e) {e.printStackTrace();}

字符缓冲流

输入流

     try (//这里面只能放置资源对象,用完会自动关闭//自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)//输入流Reader fr = new FileReader("src/data");//把原始的字符输入流包装成高级的缓冲字符输入流BufferedReader br = new BufferedReader(fr);){//数组储存字符char[] buffer = new char[1024];int len;//每次读取长度//循环输出字符数组while ((len =br.read(buffer)) != -1) {String rs = new String(buffer,0,len);System.out.print(rs);}} catch (Exception e) {e.printStackTrace();}
     //经典代码try (//这里面只能放置资源对象,用完会自动关闭//自动调用资源对象close方法关闭资源(即使出现异常也会关闭操作)//输入流Reader fr = new FileReader("src/data");//把原始的字符输入流包装成高级的缓冲字符输入流BufferedReader br = new BufferedReader(fr);){String line;while ((line = br.readLine()) != null){System.out.println(line);}} catch (Exception e) {e.printStackTrace();}

输出流

     //创建一个字符输出流管道与目标文件接通Writer fw = new FileWriter("src/data");//覆盖管道,会清空之前文件的数据Writer fw = new FileWriter("src/data01",true);//追加数据,不会清空之前文件的数据//把低级字符输出流包装成缓冲字符输出流BufferedWriter bw = new BufferedWriter(fw);//写一个字符出去bw.write('a');bw.write(97);bw.write('徐');//不会出bugbw.newLine();//bw.write("\r\n");//换行//写一个字符串出去bw.write("abc我是中国人");bw.write("\r\n");//换行//写一个字符数组出去char [] chars = "abc我是中国人".toCharArray();bw.write(chars);bw.newLine();//bw.write("\r\n");//换行//写字符串的一部分出去bw.write("abc我是中国人",0,3);bw.newLine();//bw.write("\r\n");//换行//写字符数组的一部分出去bw.write(chars,3,5);bw.newLine();//bw.write("\r\n");//换行fw.flush();//刷新流bw.close();//关闭流

案例

     try (//创建字符缓冲输入流BufferedReader br = new BufferedReader(new FileReader("src/data.txt"));//创建一个字符缓冲输出流BufferedWriter bw = new BufferedWriter(new FileWriter("src/date"));){//创建一个集合储存读取文件所有数据List<String> data = new ArrayList<>();//循环读取数据String line;while ((line = br.readLine()) != null){data.add(line);}System.out.println(data);//自定义排序规则List<String> sizes = new ArrayList<>();Collections.addAll(sizes,"一","二","三","四","五","六","七");Collections.sort(data, new Comparator<String>() {@Overridepublic int compare(String o1, String o2) {//indexOf是根据字符所在的位置返回集合的索引//根据字符提取索引//substring是根据开始索引和最终索引提取这一段的字符//根据索引提前字符return sizes.indexOf(o1.substring(0,o1.indexOf("、"))) -sizes.indexOf(o2.substring(0,o2.indexOf("、")));}});System.out.println(data);//循环遍历集合for (String datum : data) {bw.write(datum);bw.newLine();//换行}} catch (Exception e) {e.printStackTrace();}

转换流


字符输入转换流

     //字节输入流InputStream is = new FileInputStream("src/");//字节输入流转换成字符输入流Reader isr = new InputStreamReader(is);//默认以UTF-8的方式转成字符Reader isr = new InputStreamReader(is, "GBK");//以指定GBK编码方式转成字符//把字符输入流包装成缓冲字符输入流BufferedReader br = new BufferedReader(isr);String line;while ((line = br.readLine()) != null){System.out.println(line);}

字符输出转换流

        //字节输出流OutputStream os = new FileOutputStream("src");//把字节输出流转成字符输出流Writer bos = new OutputStreamWriter(os);//以默认UTF-8发生输出字符Writer bos = new OutputStreamWriter(os,"GBK");//以指定GBK方式输出字符//把字符输出流包装成缓冲字符输出流BufferedWriter bw = new BufferedWriter(bos);bw.write();bw.close();

序列化对象

对象序列化

     //创建学生对象Student s = new Student("阿康","ak","123",20);//对象序列化:使用对象字节输出流包装字节输出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("src/dd"));//调用序列化方法oos.writeObject(s);//释放资源oos.close();//对象要实现序列化,必须实现Serializable接口
public class Student implements Serializable {}

对象反序列化

     //创建对象字节输入流管道包装字节输入流ObjectInputStream ois = new ObjectInputStream(new FileInputStream("src/dd"));//调用对象字节反序列化方法Student s = (Student) ois.readObject();System.out.println(s);

对象序列化规则:
//对象要实现序列化,必须实现Serializable接口
//申明序列化的版本号
//序列化的版本号和反序列化的版本号必须一致才不会出错
//transient修饰的成员变量不参与序列化

//对象要实现序列化,必须实现Serializable接口
public class Student implements Serializable {//申明序列化的版本号//序列化的版本号和反序列化的版本号必须一致才不会出错private static final long serialVersionUID = 1;private String name;private String loginName;//transient修饰的成员变量不参与序列化private transient String passWord;private int age;public Student() {}
}

打印流

PrintStream、PrintWriter


     //两种写法PrintStream ps = new PrintStream("src/ps.txt");PrintStream ps = new PrintStream(new FileOutputStream("src/ps.txt"));//要追加数据只能使用低级管道PrintStream ps = new PrintStream(new FileOutputStream("src/ps.txt",true));

输出语句的重定向

     //改变输出语句的位置PrintStream ps = new PrintStream("src/ps");System.setOut(ps);//把系统打印流改成我们自己的打印流System.out.println("锦瑟无端五十闲");System.out.println("一线一柱思华年");

Properties

     //使用Properties把键值对信息存到文件中去Properties pp = new Properties();//信息输入pp.setProperty("heima","123");System.out.println(pp);pp.store(new FileWriter("src/pp"),"i am happy");
     //Properties读取属性文件中的键值对信息Properties properties = new Properties();System.out.println(properties);//加载属性文件中键值对数据到属性对象Properties中去properties.load(new FileReader("src/pp"));System.out.println(properties);//通过键拿到对应的值String rs = properties.getProperty("heima");System.out.println(rs);

IO流框架

     //文件复制IOUtils.copy(new FileInputStream("") , new FileOutputStream(""));//完成文件复制到某个文件夹下FileUtils.copyFileToDirectory(new File(""),new File(""));//完成文件夹复制到某个文件夹下FileUtils.copyDirectoryToDirectory(new File(""),new File(""));//完成删除文件夹FileUtils.deleteDirectory(new File(""));//java自己也有一些一行代码完成复制的操作Files.copy(Paths.get(""),Paths.get(""));

线程

概述


多线程的创建

方式一:继承Thread类

//1、定义一个线程类继承Thread
class MyThread extends Thread {//2、重写run方,里面是定义线程以后干什么@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程启动" + i);}}
}public static void main(String[] args) {//3、new一个线程对象Thread t = new MyThread();//多态//4、调用start方法启动线程,其实是调用run方法t.start();for (int i = 0; i < 5; i++) {System.out.println("主线程启动" + i);}}

方式二:实现Runnable接口

//1、定义一个线程任务类 实现Runnable接口
class MyRunnable implements Runnable {//2、重写run方法,定义线程的执行任务@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程输出" + i);}}
}public static void main(String[] args) {//3、创建一个任务对象Runnable target = new MyRunnable();//多态//4、把任务对象交给Thread处理Thread t = new Thread(target);//5、启动线程t.start();for (int i = 0; i < 5; i++) {System.out.println("主线程输出" + i);}}

 public static void main(String[] args) {//内部类写法Runnable target = new Runnable() {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程1输出" + i);}}};Thread t = new Thread(target);t.start();//简化写法new Thread(new Runnable() {@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程2输出" + i);}}}).start();//再简化new Thread(() -> {for (int i = 0; i < 5; i++) {System.out.println("子线程3输出" + i);}}).start();for (int i = 0; i < 5; i++) {System.out.println("主线程输出" + i);}}

方式三:实现Callable接口----可返回线程的执行结果

//1、定义一个任务类 实现Callable接口
class MyCallable implements Callable<String> {//创建一个有参构造器private int n;public MyCallable(int n) {this.n = n;}//重写call方法(任务方法)@Overridepublic String call() throws Exception {int sum = 0;for (int i = 0; i <=n ; i++) {sum += i;}return "子线程输出结果" + sum;}
}public static void main(String[] args) {//3、创建Callable任务对象Callable<String> call = new MyCallable(100);//没法直接交给Thread//4、把Callable任务对象 交给 FutureTask 对象//FutureTask对象的作用1:使Runnable的对象(实现Runnable接口),可以交给Thread//FutureTask对象的作用2:可以在线程执行完毕之后调用其get方法得到线程执行的结果FutureTask<String> f = new FutureTask<>(call);//5、交给线程处理Thread t = new Thread(f);t.start();//启动try {//如果f任务没有执行完毕,这里的代码会等到线程执行完毕才启动//获取线程执行结果String rs = f.get();System.out.println("结果为" + rs);} catch (Exception e) {e.printStackTrace();}}

Thread的常用方法

 public static void main(String[] args) {Thread t1 = new MyThread();t1.setName("1号");t1.start();System.out.println(t1.getName());Thread t2 = new MyThread();t2.setName("2号");t2.start();System.out.println(t2.getName());Thread m = Thread.currentThread();System.out.println(m.getName());for (int i = 0; i < 5; i++) {System.out.println("main线程输出" + i);}}

     //3、创建一个任务对象Runnable target = new MyRunnable();//4、把任务对象交给Thread处理Thread t = new Thread(target);Thread t = new Thread(target,"1号");
//创建一个线程类
public class MyThread extends Thread{public MyThread() {}//创建一个有参构造器public MyThread(String name) {super(name);}@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "输出" + i);}}
}Thread t1 = new MyThread("1号");
//        t1.setName("1号");t1.start();System.out.println(t1.getName());

 public static void main(String[] args) throws Exception {for (int i = 1; i <= 5; i++) {System.out.println("输出" + i);if (i == 3){//让当前代码进入休眠状态Thread.sleep(3000);}}}

线程安全

public class Account {private double money;public Account() {}public Account(double money) {this.money = money;}public void drawMoney(double money) {//先判断是谁来取钱String name = Thread.currentThread().getName();//判断余额是否充足if (this.money >= money){System.out.println(name + "来取" + money + "元");//更新余额this.money -= money;System.out.println("剩余" + this.money);}else{System.out.println("余额不足");}}public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}
}public class DrawThread extends Thread{private Account acc;public DrawThread(Account acc , String name){super(name);this.acc = acc;}@Overridepublic void run() {//取钱acc.drawMoney(100000);}
}public static void main(String[] args) {//创建一个公共账户对象Account acc = new Account(100000);//创建两个线程new DrawThread(acc,"小明").start();new DrawThread(acc,"小红").start();}

线程同步

概述

方式一:同步代码块

     //同步代码块synchronized ("heima") {//判断余额是否充足if (this.money >= money){System.out.println(name + "来取" + money + "元");//更新余额this.money -= money;System.out.println(name + "取钱后剩余" + this.money);}else{System.out.println(name + "来取,余额不足");}}

     //同步代码块synchronized (this) {//判断余额是否充足if (this.money >= money){System.out.println(name + "来取" + money + "元");//更新余额this.money -= money;System.out.println(name + "取钱后剩余" + this.money);}else{System.out.println(name + "来取,余额不足");}}

方式二:同步方法

public synchronized void drawMoney(double money) {}

方式三:Lock锁

    //使用final修饰:唯一且不可变private final Lock lock = new ReentrantLock();lock.lock();//上锁try {if (this.money >= money) {System.out.println(name + "来取" + money + "元");//更新余额this.money -= money;System.out.println(name + "取钱后剩余" + this.money);} else {System.out.println(name + "来取,余额不足");}} finally {//使用finally,避免上面代码出bug,无法执行解锁操作lock.unlock();//解锁}

线程通信


案例

    public static void main(String[] args) {Account acc = new Account("123",0);new Draw(acc,"小明").start();new Draw(acc,"小红").start();new Deposit(acc,"亲爹").start();new Deposit(acc,"干爹").start();new Deposit(acc,"岳父").start();}
public class Account {private String idName;private double money;public Account() {}public Account(String idName, double money) {this.idName = idName;this.money = money;}//存钱public synchronized void deposit(double money) {try {String name = Thread.currentThread().getName();if (this.money == 0){//存钱this.money += money;System.out.println(name + "存了" + money + "剩余" + this.money);this.notifyAll();//唤醒所有线程this.wait();//锁对象,让当前程序进入等待}else {//不存this.notifyAll();//唤醒所有线程this.wait();//锁对象,让当前程序进入等待}} catch (Exception e) {e.printStackTrace();}}//取钱public synchronized void drawMoney(double money) {try {String name = Thread.currentThread().getName();if (this.money >= money){//取钱this.money -= money;System.out.println(name + "取走了" + money + "剩余" + this.money);//没钱了this.notifyAll();//唤醒所有线程this.wait();//锁对象,让当前程序进入等待}else {this.notifyAll();//唤醒所有线程//唤醒别人,等待自己this.wait();//锁对象,让当前程序进入等待}} catch (Exception e) {e.printStackTrace();}}public String getIdName() {return idName;}public void setIdName(String idName) {this.idName = idName;}public double getMoney() {return money;}public void setMoney(double money) {this.money = money;}}
public class Draw extends Thread{private Account acc;public Draw (Account acc , String name ){super(name);this.acc = acc;}@Overridepublic void run() {//取钱while (true) {acc.drawMoney(100000);try {Thread.sleep(2000);} catch (Exception e) {e.printStackTrace();}}}
}
public class Deposit extends Thread{private Account acc;public Deposit(Account acc , String name ){super(name);this.acc = acc;}@Overridepublic void run() {//取钱while (true) {acc.deposit(100000);try {Thread.sleep(2000);} catch (Exception e) {e.printStackTrace();}}}
}

线程池

概述

线程池实现的API,参数说明

//参数一:主线程个数
//参数二:主线程和临时线程总个数
//参数三:临时线程存在时间
//参数四:时间单位(TimeUnit.SECONDS)
//参数五:队列中线程可以等待的个数new ArrayBlockingQueue<>(2)
//参数六:照写Executors.defaultThreadFactory()
//参数七:新任务拒绝策略,默认new ThreadPoolExecutor.AbortPolicy()
ExecutorService pool = new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS,
new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());

参数七可选择的拒绝策略

线程池处理Runnable任务

//实现Runnable接口
public class MyRunnable implements Runnable{@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println(Thread.currentThread().getName() + "线程输出" + i);}try {System.out.println(Thread.currentThread().getName() + "与任务线程绑定");Thread.sleep(100000);} catch (Exception e) {e.printStackTrace();}}
}
    public static void main(String[] args) {//创建线程池对象/**   int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,RejectedExecutionHandler handler* */ExecutorService pool = new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());//创建Runnable任务对象Runnable target = new MyRunnable();//线程池执行Runnable任务//主线程pool.execute(target);pool.execute(target);pool.execute(target);//队列线程pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);pool.execute(target);//创建临时线程,当线程数量大于主线程和队列线程数量时,临时线程才会被创建pool.execute(target);pool.execute(target);//        //不创建,拒绝策略被触发
//        pool.execute(target);
//        pool.execute(target);//关闭线程池(开发中一般不使用)pool.shutdownNow();//立即关闭,即使任务没有完成。会丢失任务pool.shutdown();//会等任务完成后再关闭(建议使用)}

线程池处理Callable任务

//实现Callable接口,可以返回线程执行结果
public class MyCallable implements Callable {private int n;public MyCallable(int n) {this.n = n;}@Overridepublic String call() throws Exception {int sum = 0;for (int i = 1; i <=n; i++) {sum += i;}return Thread.currentThread().getName() + "和为" + sum;}
}
    public static void main(String[] args) throws Exception {ExecutorService pool = new ThreadPoolExecutor(3,5,6, TimeUnit.SECONDS,new ArrayBlockingQueue<>(5),Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());//把Callable任务交给线程池处理//Callable target = new MyCallable(100);//Future<String> f1 = pool.submit(target);Future<String> f1 = pool.submit(new MyCallable(100));//得到线程执行结果//String rs = f1.get();//System.out.println(rs);System.out.println(f1.get());}

Executors工具类实现线程池

    public static void main(String[] args) {//创建固定线程数量的线程池ExecutorService pool = Executors.newFixedThreadPool(3);//线程池执行Runnable任务pool.execute(new MyRunnable());pool.execute(new MyRunnable());pool.execute(new MyRunnable());pool.execute(new MyRunnable());//已经没有多余线程}

定时器

方式一:Timer

    public static void main(String[] args) {//创建Timer定时器Timer timer = new Timer();//调用方法处理定时任务timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "执行一次");try {Thread.sleep(10000);//如果前一个线程睡眠,会影响后面线程的执行} catch (InterruptedException e) {e.printStackTrace();}                }},3000,2000);//等待多久开始,此后每次间隔多久timer.schedule(new TimerTask() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "执行一次");}},3000,2000);}

方式二:ScheduledExecutorService----更常用

    public static void main(String[] args) {//创建ScheduledExecutorService线程池,做定时器ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);//开启定时任务pool.scheduleAtFixedRate(new TimerTask() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "执行AAA");try {Thread.sleep(10000);//即使前一个线程睡眠,也不会影响后面线程的执行} catch (InterruptedException e) {e.printStackTrace();}}},0,2, TimeUnit.SECONDS);//开始时间,间隔时间,时间单位pool.scheduleAtFixedRate(new TimerTask() {@Overridepublic void run() {System.out.println(Thread.currentThread().getName() + "执行BBB");}},0,2, TimeUnit.SECONDS);}

线程并发、并行

线程的生命周期



网络编程

网络通信三要素

IP地址

IP地址操作类–InetAddress

        //获取本机地址对象InetAddress ip1 = InetAddress.getLocalHost();System.out.println(ip1);System.out.println(ip1.getHostAddress());System.out.println(ip1.getHostName());//根据域名获取ip对象InetAddress ip2 = InetAddress.getByName("www.baidu.com");System.out.println(ip2.getHostAddress());System.out.println(ip2.getHostName());//获取公网ip对象InetAddress ip3 = InetAddress.getByName("39.156.66.14");System.out.println(ip3.getHostAddress());System.out.println(ip3.getHostName());//判断是否联通System.out.println(ip3.isReachable(5000));

端口号

协议

UDP通信

快速入门----一发一收


一发一收

    public static void main(String[] args) throws Exception {System.out.println("============客户端=============");//创建发送端对象,发送端自带端口DatagramSocket socket = new DatagramSocket();//创建一个数据包对象封装数据/*public DatagramPacket(byte buf[], int length,InetAddress address, int port)参数一;要发送的数据字节数组参数二:要发送的数组长度参数三:接收端的主机IP地址参数四:接收端的端口*/byte [] buffer = "我是快乐的小韭菜。".getBytes();DatagramPacket packet = new DatagramPacket(buffer, buffer.length,InetAddress.getLoopbackAddress(),8888);//发送数据socket.send(packet);//关闭管道socket.close();}
    public static void main(String[] args) throws Exception {System.out.println("========服务端=============");//创建一个接收端对象,要自己声明端口DatagramSocket socket = new DatagramSocket(8888);//创建一个数据包对象接收数据byte [] buffer = new byte[1024*64];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);//等待接收数据socket.receive(packet);//取出数据//接到多少,输出多少int len = packet.getLength();String rs = new String(buffer,0,len);System.out.println("输出:"+ rs);//获取发送端的ip和端口String ip = packet.getAddress().toString();System.out.println("发送端的ip:" + ip);int port = packet.getPort();System.out.println("发送端的端口:" + port);//关闭管道socket.close();}

多发多收


在一发一收基础上,增加死循环实现多发多收

    public static void main(String[] args) throws Exception {System.out.println("============客户端=============");//创建发送端对象,发送端自带端口DatagramSocket socket = new DatagramSocket();Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入:");String msg = sc.nextLine();if ("exit".equals(msg)) {System.out.println("离线成功");socket.close();break;}//创建一个数据包对象封装数据byte[] buffer = msg.getBytes();DatagramPacket packet = new DatagramPacket(buffer, buffer.length, InetAddress.getLoopbackAddress(), 8888);//发送数据socket.send(packet);}}
    public static void main(String[] args) throws Exception {System.out.println("========服务端=============");//创建一个接收端对象,要自己声明端口DatagramSocket socket = new DatagramSocket(8888);//创建一个数据包对象接收数据byte[] buffer = new byte[1024 * 64];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);while (true) {//等待接收数据socket.receive(packet);//取出数据//接到多少,输出多少int len = packet.getLength();String rs = new String(buffer, 0, len);System.out.println("收到来自:" + packet.getAddress().toString() + ",对方端口是:" + packet.getPort() + "的消息:" + rs);}}

广播、组播

广播

在多发多收基础上,改变接收端的接收ip地址

    public static void main(String[] args) throws Exception {System.out.println("============客户端=============");//创建发送端对象,发送端自带端口DatagramSocket socket = new DatagramSocket();Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入:");String msg = sc.nextLine();if ("exit".equals(msg)) {System.out.println("离线成功");socket.close();break;}//创建一个数据包对象封装数据byte[] buffer = msg.getBytes();DatagramPacket packet = new DatagramPacket(buffer, buffer.length,InetAddress.getByName("255.255.255.255"), 9999);//发送数据socket.send(packet);}}
    public static void main(String[] args) throws Exception {System.out.println("========服务端=============");//创建一个接收端对象,要自己声明端口DatagramSocket socket = new DatagramSocket(9999);//创建一个数据包对象接收数据byte[] buffer = new byte[1024 * 64];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);while (true) {//等待接收数据socket.receive(packet);//取出数据//接到多少,输出多少int len = packet.getLength();String rs = new String(buffer, 0, len);System.out.println("收到来自:" + packet.getAddress().toString() + ",对方端口是:" + packet.getPort() + "的消息:" + rs);}}

组播

在多发多收基础上,为服务端创建组播ip

        System.out.println("============客户端=============");//创建发送端对象,发送端自带端口DatagramSocket socket = new DatagramSocket();Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入:");String msg = sc.nextLine();if ("exit".equals(msg)) {System.out.println("离线成功");socket.close();break;}//创建一个数据包对象封装数据byte[] buffer = msg.getBytes();DatagramPacket packet = new DatagramPacket(buffer, buffer.length,InetAddress.getByName("224.0.1.1"), 9999);//发送数据socket.send(packet);}}
    public static void main(String[] args) throws Exception {System.out.println("========服务端=============");//创建一个接收端对象,要自己声明端口MulticastSocket socket = new MulticastSocket(9999);//把当前接收端加入到一个组播当中去,绑定对应的组播消息的组播ip
//        socket.joinGroup(InetAddress.getByName("224.0.1.1"));socket.joinGroup(new InetSocketAddress(InetAddress.getByName("224.0.1.1"),9999),NetworkInterface.getByInetAddress(InetAddress.getLocalHost()));//创建一个数据包对象接收数据byte[] buffer = new byte[1024 * 64];DatagramPacket packet = new DatagramPacket(buffer, buffer.length);while (true) {//等待接收数据socket.receive(packet);//取出数据//接到多少,输出多少int len = packet.getLength();String rs = new String(buffer, 0, len);System.out.println("收到来自:" + packet.getAddress().toString() + ",对方端口是:" + packet.getPort() + "的消息:" + rs);}}

TCP通信

快速入门

客户端

    public static void main(String[] args) {System.out.println("==========客户端============");try {//创建Socket通信管道请求服务端的连接// public Socket(String host, int port)//参数一:服务端的ip地址//参数二:服务端的端口Socket socket = new Socket("127.0.0.1" , 7777);//从Socket通信管道中得到一个字节输出流,负责发送消息OutputStream os = socket.getOutputStream();//把低级字节输出流包装成打印流PrintStream ps = new PrintStream(os);ps.print("发送TCP消息");ps.flush();//刷新//一般不用关闭管道,直接关闭会导致通信失败//socket.close();} catch (Exception e) {e.printStackTrace();}}

服务端

    public static void main(String[] args) {System.out.println("==========服务端==============");try {//注册服务端端口ServerSocket serverSocket = new ServerSocket(7777);//调用accept方法,等待客户端发送Socket连接请求,建立连接Socket socket = serverSocket.accept();//从Socket通信管道中得到一个字节输入流,接收信息InputStream is = socket.getInputStream();//把字节输入流包装成缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//按照行读取消息String msg;if ((msg = br.readLine()) != null){System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);}} catch (Exception e) {e.printStackTrace();}}

多发多收

    public static void main(String[] args) {System.out.println("==========客户端============");try {//创建Socket通信管道请求服务端的连接// public Socket(String host, int port)//参数一:服务端的ip地址//参数二:服务端的端口Socket socket = new Socket("10.31.107.20", 7777);//从Socket通信管道中得到一个字节输出流,负责发送消息OutputStream os = socket.getOutputStream();//把低级字节输出流包装成打印流PrintStream ps = new PrintStream(os);Scanner sc = new Scanner(System.in);while (true){System.out.println("请输入:");String msg = sc.nextLine();//发消息ps.println(msg);ps.flush();}//一般不用关闭管道,直接关闭会导致通信失败//socket.close();} catch (Exception e) {e.printStackTrace();}}
    public static void main(String[] args) {System.out.println("==========服务端==============");try {//注册服务端端口ServerSocket serverSocket = new ServerSocket(7777);//调用accept方法,等待客户端发送Socket连接请求,建立连接Socket socket = serverSocket.accept();//从Socket通信管道中得到一个字节输入流,接收信息InputStream is = socket.getInputStream();//把字节输入流包装成缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//按照行读取消息String msg;while ((msg = br.readLine()) != null){System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);}} catch (Exception e) {e.printStackTrace();}}

同时接收多个客户端消息

    public static void main(String[] args) {System.out.println("==========客户端============");try {//创建Socket通信管道请求服务端的连接// public Socket(String host, int port)//参数一:服务端的ip地址//参数二:服务端的端口Socket socket = new Socket("10.31.107.20", 7777);//从Socket通信管道中得到一个字节输出流,负责发送消息OutputStream os = socket.getOutputStream();//把低级字节输出流包装成打印流PrintStream ps = new PrintStream(os);Scanner sc = new Scanner(System.in);while (true){System.out.println("请输入:");String msg = sc.nextLine();//发消息ps.println(msg);ps.flush();}//一般不用关闭管道,直接关闭会导致通信失败//socket.close();} catch (Exception e) {e.printStackTrace();}}
    public static void main(String[] args) {System.out.println("==========服务端==============");try {//注册服务端端口ServerSocket serverSocket = new ServerSocket(7777);//定义一个死循环由主线程负责,不断的接收客户端的Socket管道连接while (true) {//每接收到一个客户端的管道,交给一个独立的子线程负责读取消息Socket socket = serverSocket.accept();//创建独立线程处理socketnew ServerReaderThread(socket).start();}} catch (Exception e) {e.printStackTrace();}}
public class ServerReaderThread extends Thread{private Socket socket;public ServerReaderThread(Socket socket){this.socket = socket;}@Overridepublic void run() {try {//从Socket通信管道中得到一个字节输入流,接收信息InputStream is = socket.getInputStream();//把字节输入流包装成缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//按照行读取消息String msg;while ((msg = br.readLine()) != null){System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);}} catch (Exception e) {System.out.println(socket.getRemoteSocketAddress() + "下线了");}}
}

使用线程池优化

    public static void main(String[] args) {System.out.println("==========客户端============");try {//创建Socket通信管道请求服务端的连接// public Socket(String host, int port)//参数一:服务端的ip地址//参数二:服务端的端口Socket socket = new Socket("10.31.107.20", 7777);//从Socket通信管道中得到一个字节输出流,负责发送消息OutputStream os = socket.getOutputStream();//把低级字节输出流包装成打印流PrintStream ps = new PrintStream(os);Scanner sc = new Scanner(System.in);while (true){System.out.println("请输入:");String msg = sc.nextLine();//发消息ps.println(msg);ps.flush();}//一般不用关闭管道,直接关闭会导致通信失败//socket.close();} catch (Exception e) {e.printStackTrace();}}
    //创建一个静态线程池private static ExecutorService pool = new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) {System.out.println("==========服务端==============");try {//注册服务端端口ServerSocket serverSocket = new ServerSocket(7777);//定义一个死循环由主线程负责,不断的接收客户端的Socket管道连接while (true) {//每接收到一个客户端的管道,交给一个独立的子线程负责读取消息Socket socket = serverSocket.accept();System.out.println(socket.getRemoteSocketAddress() + "上线了");//想要使用线程池,必须封装成任务对象,线程才能执行//把socket管道封装成任务对象Runnable target = new ServerReaderRunnable(socket);//线程池执行任务pool.execute(target);}} catch (Exception e) {e.printStackTrace();}}
public class ServerReaderRunnable implements Runnable{private Socket socket;public ServerReaderRunnable (Socket socket){this.socket = socket;}@Overridepublic void run() {try {//从Socket通信管道中得到一个字节输入流,接收信息InputStream is = socket.getInputStream();//把字节输入流包装成缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//按照行读取消息String msg;while ((msg = br.readLine()) != null){System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);}} catch (Exception e) {System.out.println(socket.getRemoteSocketAddress() + "下线了");}}
}

及时通信

public class Demo1 {public static void main(String[] args) {System.out.println("==========客户端============");try {//创建Socket通信管道请求服务端的连接// public Socket(String host, int port)//参数一:服务端的ip地址//参数二:服务端的端口Socket socket = new Socket("10.31.107.20", 7777);//创建一个独立线程专门负责接收消息new ClientReaderThread(socket).start();//从Socket通信管道中得到一个字节输出流,负责发送消息OutputStream os = socket.getOutputStream();//把低级字节输出流包装成打印流PrintStream ps = new PrintStream(os);Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入:");String msg = sc.nextLine();//发消息ps.println(msg);ps.flush();}//一般不用关闭管道,直接关闭会导致通信失败//socket.close();} catch (Exception e) {e.printStackTrace();}}
}class ClientReaderThread extends Thread {private Socket socket;public ClientReaderThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {//从Socket通信管道中得到一个字节输入流,接收信息InputStream is = socket.getInputStream();//把字节输入流包装成缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//按照行读取消息String msg;while ((msg = br.readLine()) != null) {System.out.println( "收到消息:" + msg);}} catch (Exception e) {System.out.println("服务端把你踢出群聊");}}
}
public class serverDemo {//定义一个静态的集合,储存所有在线的管道public static List<Socket> AllOnlineSockets = new ArrayList<>();//创建一个静态线程池private static ExecutorService pool = new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) {System.out.println("==========服务端==============");try {//注册服务端端口ServerSocket serverSocket = new ServerSocket(7777);//定义一个死循环由主线程负责,不断的接收客户端的Socket管道连接while (true) {//每接收到一个客户端的管道,交给一个独立的子线程负责读取消息Socket socket = serverSocket.accept();System.out.println(socket.getRemoteSocketAddress() + "上线了");AllOnlineSockets.add(socket);//管道上线//把socket管道封装成任务对象Runnable target = new ServerReaderRunnable(socket);pool.execute(target);}} catch (Exception e) {e.printStackTrace();}}
}class ServerReaderRunnable implements Runnable{private Socket socket;public ServerReaderRunnable (Socket socket){this.socket = socket;}@Overridepublic void run() {try {//从Socket通信管道中得到一个字节输入流,接收信息InputStream is = socket.getInputStream();//把字节输入流包装成缓冲字符输入流BufferedReader br = new BufferedReader(new InputStreamReader(is));//按照行读取消息String msg;while ((msg = br.readLine()) != null){System.out.println(socket.getRemoteSocketAddress() + "说了:" + msg);//把消息进行端口转发给全部客户端socket管道sendMsgToAll(msg);}} catch (Exception e) {System.out.println(socket.getRemoteSocketAddress() + "下线了");serverDemo.AllOnlineSockets.remove(socket);}}private void sendMsgToAll(String msg) throws Exception {for (Socket socket : serverDemo.AllOnlineSockets) {PrintStream ps = new PrintStream(socket.getOutputStream());ps.println(msg);ps.flush();}}
}

模拟BS系统

public class BSserverDemo {public static void main(String[] args) {System.out.println("==========服务端==============");try {//注册服务端端口ServerSocket serverSocket = new ServerSocket(8080);//定义一个死循环由主线程负责,不断的接收客户端的Socket管道连接while (true) {//每接收到一个客户端的管道,交给一个独立的子线程负责读取消息Socket socket = serverSocket.accept();//创建独立线程处理socketnew BSserverReaderThread(socket).start();}} catch (Exception e) {e.printStackTrace();}}
}class BSserverReaderThread extends Thread {private Socket socket;public BSserverReaderThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {//浏览器已经与本线程建立Socket管道//响应消息给浏览器显示PrintStream ps = new PrintStream(socket.getOutputStream());//必须响应HTTP协议格式数据,否则浏览器不认识消息ps.println("HTTP/1.1 200 OK");//协议类型和版本 响应成功的消息ps.println("Content-Type:text/html;charset=UTF-8");//响应的数据类型 文本/网页ps.println();//必须发送一个空行//响应数据正文ps.println("<span style='color:red;font-size:90px'> 《傻逼阿康》 </span>");ps.close();} catch (Exception e) {System.out.println(socket.getRemoteSocketAddress() + "下线了");}}
}

//引入线程池优化
public class BSserverDemo {//创建一个静态线程池private static ExecutorService pool = new ThreadPoolExecutor(3,5,6,TimeUnit.SECONDS, new ArrayBlockingQueue<>(2), Executors.defaultThreadFactory(),new ThreadPoolExecutor.AbortPolicy());public static void main(String[] args) {try {//注册服务端端口ServerSocket ss = new ServerSocket(8080);//定义一个死循环由主线程负责,不断接收客户端的Socket管道连接while (true) {//每接收到一个客户端的管道,交给一个独立的子线程负责读取消息Socket socket = ss.accept();//创建独立线程处理socketpool.execute(new ServerReaderRunnable(socket));}} catch (Exception e) {e.printStackTrace();}}
}
class ServerReaderRunnable implements Runnable {private Socket socket;public ServerReaderRunnable(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {//浏览器已经与本线程建立Socket管道//响应消息给浏览器显示PrintStream ps = new PrintStream(socket.getOutputStream());//必须响应HTTP协议格式数据,否则浏览器不认识消息ps.println("HTTP/1.1 200 OK");//协议类型和版本 响应成功的消息ps.println("Content-Type:text/html;charset=UTF-8");//响应的数据类型 文本/网页ps.println();//必须发送一个空行//响应数据正文ps.println("<span style='color:red;font-size:90px'> 《傻逼阿康》 </span>");ps.close();} catch (Exception e) {System.out.println(socket.getRemoteSocketAddress() + "下线了");}}
}

单元测试

概述

快速入门

public class Server {public String loginName(String loginName , String passWord){if("admin".equals(loginName) && "123456".equals(passWord)){return "登录成功";}else {return "有误";}}public void selectName(){System.out.println(10/0);System.out.println("成功");}
}
    /*测试方法:1.必须是公开的 无参数 无返回值的方法2.测试方法必须使用Test注解标记*///有参数方法测试@Testpublic void test(){Server server = new Server();String rs = server.loginName("admin" , "123456");//进行预期结束的正确性测试,断言Assert.assertEquals("业务登录成功" , "登录成功" ,rs);}//无参数方法测试@Testpublic void selectServer(){Server server = new Server();server.selectName();}

常用注解

反射

概述

获取类对象


public class Test {public static void main(String[] args) throws Exception {//1、Class类中的一个静态方法:forName(全限名:包名+类名)Class c = Class.forName("pk1.Test");System.out.println(c);//2、类名.Class//最常用Class c1 = Test.class;System.out.println(c1);//3、对象.getClass() 获取对象对应类的Class对象Test t = new Test();Class c2 = t.getClass();System.out.println(c2);}
}

获取构造器对象

public class Student {private int age ;private String name;public Student() {System.out.println("无参");}public Student(int age, String name) {System.out.println("有参");this.age = age;this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public String getName() {return name;}public void setName(String name) {this.name = name;}@Overridepublic String toString() {return "Student{" +"age=" + age +", name='" + name + '\'' +'}';}
}
    //1、getConstructors()//获取全部构造器,只能获取public修饰的构造器@Testpublic void getConstructors() {//a.获取类对象Class c = Student.class;//b.提取类中全部由public修饰的构造器对象Constructor[] constructors = c.getConstructors();//c.遍历所有构造器for (Constructor constructor : constructors) {System.out.println(constructor.getName() + "=====>" + constructor.getParameterCount());//得到参数名称和对应的参数个数}}//2、getDeclaredConstructors()//获取全部构造器,无所谓权限@Testpublic void getDeclaredConstructors() {//a.获取类对象Class c = Student.class;//b.提取类中全部的构造器对象Constructor[] constructors = c.getDeclaredConstructors();//c.遍历所有构造器for (Constructor constructor : constructors) {System.out.println(constructor.getName() + "=====>" + constructor.getParameterCount());}}//3、getConstructor(Class<?>... parameterTypes)//获取某个构造器,只能拿public修饰的某个构造器@Testpublic void getConstructor() throws Exception {//a.获取类对象Class c = Student.class;//b.定位当个构造器(按照参数定位无参构造器)Constructor cons = c.getConstructor();System.out.println(cons.getName() + "=====>" + cons.getParameterCount());}//4、getDeclaredConstructor(Class<?>... parameterTypes)//获取某个构造器,无所谓权限@Testpublic void getDeclaredConstructor() throws Exception {//a.获取类对象Class c = Student.class;//b.定位当个构造器(按照参数定位无参构造器)Constructor cons = c.getDeclaredConstructor();System.out.println(cons.getName() + "=====>" + cons.getParameterCount());//c.定位某个有参构造器//要知道参数变量类型Constructor cons1 = c.getDeclaredConstructor(int.class , String.class);System.out.println(cons1.getName() + "=====>" + cons1.getParameterCount());}

    //1、调用构造器得到一个类的对象返回@Testpublic void getDeclaredConstructor() throws Exception {//a.获取类对象Class c = Student.class;//b.定位当个构造器(按照参数定位无参构造器)Constructor cons = c.getDeclaredConstructor();System.out.println(cons.getName() + "=====>" + cons.getParameterCount());//        //如果遇到构造器被私有,可以暴力反射
//        cons.setAccessible(true);//权限被打开Student s = (Student) cons.newInstance();System.out.println(s);System.out.println("--------------------");//c.定位某个有参构造器Constructor cons1 = c.getDeclaredConstructor(int.class , String.class);System.out.println(cons1.getName() + "=====>" + cons1.getParameterCount());Student s1 = (Student) cons1.newInstance(18,"孙悟空");System.out.println(s1);}

获取成员变量对象

    //1、获取全部的成员变量// File[] getDeclaredFields()@Testpublic void getDeclaredFields() {//a.获取类对象Class c = Student.class;//b.定位所有成员变量Field[] fields = c.getDeclaredFields();//c.遍历一下for (Field field : fields) {System.out.println(field.getName() + "====>" + field.getType());//得到成员变量的名称和类型}}//2、获取某个成员变量getDeclaredField(String name)@Testpublic void getDeclaredField() throws Exception {//a.获取类对象Class c = Student.class;//b.定位某个成员变量Field f = c.getDeclaredField("age");//申明变量的名称System.out.println(f.getName() + "====>" + f.getType());}

    @Testpublic void setField() throws Exception {//a.获取类对象Class c = Student.class;//提取某个成员变量Field ageF = c.getDeclaredField("age");ageF.setAccessible(true);//暴力打开权限//c.赋值Student s = new Student();ageF.set(s,18);//s.setAge(18)System.out.println(s);//d.取值int age = (int) ageF.get(s);//s.getAgeSystem.out.println(age);}

获取方法对象

    //1、获取类中所有成员方法对象@Testpublic void getDeclaredMethods(){//a.获取类对象Class c = Dog.class;//b.获取全部方法,包括私有Method[] methods = c.getDeclaredMethods();//c.遍历全部方法for (Method method : methods) {System.out.println(method.getName() + "返回类型:" + method.getReturnType() + "参赛名称:" + method.getParameterCount()) ;}}//2、获取某个方法对象@Testpublic void getDeclaredMethod() throws Exception {//a.获取类对象Class c = Dog.class;//b.提取单个方法对象Method m1 = c.getDeclaredMethod("eat");//要申明方法名称//无参对象Method m2 = c.getDeclaredMethod("eat",String.class);//有参对象//暴力打开权限m1.setAccessible(true);m2.setAccessible(true);//c.触发方法的执行Dog d = new Dog();//注意:方法如果没有返回结果回来,那么返回的是nullString result = (String) m1.invoke(d);System.out.println(result);String result2 = (String) m2.invoke(d,"骨头");System.out.println(result2);}

反射的作用

绕过编译阶段为集合添加数据

        ArrayList<Integer> list = new ArrayList<>();list.add(12);list.add(23);Class c = list.getClass();Method add = c.getDeclaredMethod("add", Object.class);boolean rs = (boolean) add.invoke(list,"黑马");System.out.println(rs);System.out.println(list);

通用框架的底层原理

public class MybatisUtil {//保存任意类型变量public static void save(Object obj){try (//获取打印输出管道,使用完可自动释放资源PrintStream ps = new PrintStream(new FileOutputStream("data",true));){//获取类对象Class c = obj.getClass();ps.println("=========" + c.getSimpleName() + "==============");//获取全部成员变量Field[] f = c.getDeclaredFields();//遍历获取成员变量的信息for (Field field : f) {//获取成员变量的名称String name = field.getName();//提取本成员变量在obj对象中的值(取值)field.setAccessible(true);//暴力打开权限String value = field.get(obj) + "";//把该值转为字符串类型//将成员变量名称和对应的值输出ps.println(name + "=" + value);}} catch (Exception e) {e.printStackTrace();}}
}
    public static void main(String[] args) {Student s = new Student();s.setName("小红");s.setAge(18);s.setSex('男');s.setClassName("12");s.setHobby("游泳");MybatisUtil.save(s);Teacher t = new Teacher();t.setName("王艳梅");t.setSex('男');t.setSalary(6000);MybatisUtil.save(t);}

注解

概述

自定义注解

public @interface book {String name();String[] authors();double price();
}
@book(name="Java",authors = {"黑马"},price = 100)
public class Demo {@book(name="Java",authors = {"黑马"},price = 100)public static void main(String[] args) {}
}

public @interface MyBook {String value();//特殊属性
}@MyBook(value = "JavaSE")
@MyBook("JavaSE")
public class Demo {}

元注解

@Target({ElementType.METHOD,ElementType.FIELD})//元注解
@Retention(RetentionPolicy.RUNTIME)//一直活着,在运行阶段也不消失
public @interface MyTest {}

注解解析

@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface book {String value();String[] authors();double price();
}
public class Demo2 {@Testpublic void parseClass(){//a.得到类对象Class c = BookStore.class;//b.判断这个类上是否存在注解if (c.isAnnotationPresent(book.class)){//c.直接获取该注解对象book books = (book) c.getDeclaredAnnotation(book.class);System.out.println(books.value());System.out.println(Arrays.toString(books.authors()));System.out.println(books.price());}}@Testpublic void parseMethod() throws Exception {//a.得到类对象Class c = BookStore.class;//获取类方法对象Method m = c.getDeclaredMethod("test");//b.判断这个类上是否存在注解if (m.isAnnotationPresent(book.class)){//c.直接获取该注解对象book books = (book) m.getDeclaredAnnotation(book.class);System.out.println(books.value());System.out.println(Arrays.toString(books.authors()));System.out.println(books.price());}}
}@book(value = "活着",authors = "余华" ,price = 12)
class BookStore{@book(value = "酒国",authors = "莫言" ,price = 112)public void test(){}
}

junit框架

@Target({ElementType.METHOD})//元注解
@Retention(RetentionPolicy.RUNTIME)//一直活着,在运行阶段也不消失
public @interface MyTest {}
public class Demo3 {public void test1() {System.out.println("=====test1======");}@MyTestpublic void test2() {System.out.println("=====test2======");}@MyTestpublic void test3() {System.out.println("=====test3======");}public static void main(String[] args) throws Exception {Demo3 d = new Demo3();//a.获取类对象Class c = Demo3.class;//获取所有方法对象Method[] m = c. getDeclaredMethods();//遍历所有方法,判断是否有注解for (Method method : m) {if (method.isAnnotationPresent(MyTest.class)){method.invoke(d);}}}
}

动态代理

概述

快速入门




//接口
public interface Skill {void dance();void sing();
}//被代理对象实现接口
public class Star implements Skill{private String name;public Star(String name) {this.name = name;}@Overridepublic void dance() {System.out.println(name + "跳得好");}@Overridepublic void sing() {System.out.println(name + "唱得好");}
}
public class StarProxyInstance {//设计一个方法来返回一个明星对象的代理对象public static Skill getProxy(Star obj){//为这个对象生成一个代理对象/*newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)*/return (Skill) Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(), new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("收首付款");//method 调用方法对象  args 代表这个方法的参数Object rs = method.invoke(obj,args);System.out.println("收尾款");return rs;}});}
}public static void main(String[] args) {//创建一个对象Star s = new Star("杨超越");//为对象创建一个代理对象Skill s2 = StarProxyInstance.getProxy(s);s2.dance();s2.sing();}

动态代理的应用案例:性能分析

public interface UserService {String login(String loginName,String passWord);void deleteUser();String selectUser();void deleteById(int id);
}public class UserServiceImpl implements UserService {@Overridepublic void deleteById(int id) {try {System.out.println("删除了" + id);Thread.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}}
}
public class ProxyUnit {//通过一个静态方法,为用户业务对象返回一个代理对象public static UserService getProxy(UserService obj){return (UserService) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long startTime = System.currentTimeMillis();//真正触发执行Object rs = method.invoke(obj,args);long endTime = System.currentTimeMillis();System.out.println(method.getName() + "方法耗时:" + (endTime - startTime) / 1000.0 + "s");return rs;}});}
}public static void main(String[] args) {//把用户对象包装成代理对象UserService userService = ProxyUnit.getProxy(new UserServiceImpl());System.out.println(userService.login("admin", "12345"));System.out.println(userService.selectUser());userService.deleteUser();userService.deleteById(4);}

public class ProxyUnit {//使用泛型,可以为任意接口类型的实现类对象做代理public static <T> T getProxy(T obj){return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(),new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {long startTime = System.currentTimeMillis();//真正触发执行Object rs = method.invoke(obj,args);long endTime = System.currentTimeMillis();System.out.println(method.getName() + "方法耗时:" + (endTime - startTime) / 1000.0 + "s");return rs;}});}
}

XML

概述

XML的创建和语法规则

<?xml version="1.0" encoding="UTF-8" ?><!-- 注释 -->
<student><name>女儿国国外</name><sex>女</sex><hobby>唐僧</hobby><info><age>18</age><adder>女儿国</adder></info><sql>select * from user where age &lt; 18;<![CDATA[select * from user where age < 18;]]></sql>
</student>

XML文档约束

方式一:DTD约束

//DTD约束文档格式
<!ELEMENT 书架 (书+)>
<!ELEMENT 书 (书名,作者,售价)>
<!ELEMENT 书名 (#PCDATA)>
<!ELEMENT 作者 (#PCDATA)>
<!ELEMENT 售价 (#PCDATA)>
//调用约束文档
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE 书架 SYSTEM "data.dtd">
<书架><书><书名></书名><作者></作者><售价></售价></书>
</书架>

方式二:schema约束


XML解析技术

概述


Dom4J解析XML文件

public class Demo {@Testpublic void parseXMLData() throws Exception {//1、创建一个Dom4j解析器对象,代表整个Dom4j框架SAXReader saxReader = new SAXReader();//2、把XML文件加载到内存中成为一个Document文件对象
//        Document document = saxReader.read(new File("xml\\xmldata\\hello_world.xml"));//需要通过模块名去定位//注意:getResourceAsStream中的/是直接从src目录下拿文件InputStream is = Demo.class.getResourceAsStream("/hello_world.xml");Document document = saxReader.read(is);//3、获取根元素对象Element root = document.getRootElement();System.out.println(root.getNamespacePrefix());}
}

Dom4J解析XML文件中的各种节点

案例

<?xml version="1.0" encoding="UTF-8" ?>
<contactList><contact id="1" vip="true"><name>  潘金莲  </name><gender>女</gender><email>panpan@itcast.cn</email></contact><contact id="2" vip="false"><name>武松</name><gender>男</gender><email>wusong@itcast.cn</email></contact><contact id="3" vip="false"><name>武大郎</name><gender>男</gender><email>wuda@itcast.cn</email></contact><user></user>
</contactList>
public class Contact {private String name;private int id;private  boolean vip;private char gender;private String email;public Contact() {}public Contact(String name, int id, boolean vip, char gender, String email) {this.name = name;this.id = id;this.vip = vip;this.gender = gender;this.email = email;}public String getName() {return name;}public void setName(String name) {this.name = name;}public int getId() {return id;}public void setId(int id) {this.id = id;}public boolean isVip() {return vip;}public void setVip(boolean vip) {this.vip = vip;}public char getGender() {return gender;}public void setGender(char gender) {this.gender = gender;}public String getEmail() {return email;}public void setEmail(String email) {this.email = email;}@Overridepublic String toString() {return "Contact{" +"name='" + name + '\'' +", id=" + id +", vip=" + vip +", gender=" + gender +", email='" + email + '\'' +'}';}
}
public class Demo {@Testpublic void parseToList() throws Exception {//1、导入框架//2、创建SaxReader对象SAXReader saxReader = new SAXReader();//3、加载XML文件成为文档对象Document对象Document document = saxReader.read(Demo.class.getResourceAsStream("/Contacts.xml"));//4、先拿根元素Element root = document.getRootElement();//5、提取contact子元素List<Element> contactElms = root.elements("contact");//6、准备一个ArrayList集合封装联系人信息List<Contact> contacts = new ArrayList<>();//7、遍历Contact子元素for (Element contactElm : contactElms) {//8、每一个子元素都是一个联系人对象Contact contact = new Contact();contact.setId(Integer.valueOf(contactElm.attributeValue("id")));contact.setVip(Boolean.valueOf(contactElm.attributeValue("vip")));contact.setName(contactElm.elementTextTrim("name"));contact.setGender(contactElm.elementTextTrim("gender").charAt(0));contact.setEmail(contactElm.elementText("email"));//9、把联系人对象的数据加到List集合contacts.add(contact);}//10、遍历List集合for (Contact contact : contacts) {System.out.println(contact);}}
}

XML检索技术:Xpath


绝对路径

public class XpathDemo {//1、绝对路径:根元素/子元素/子元素@Testpublic void parse01() throws Exception {//a.创建解析器对象SAXReader saxReader = new SAXReader();//b.把XML加载成Document对象Document document =saxReader.read(XpathDemo.class.getResourceAsStream("/Contacts2.xml"));//c.检索全部名称List<Node> nameNodes = document.selectNodes("contactList/contact/name");for (Node nameNode : nameNodes) {Element nameEle = (Element) nameNode;System.out.println(nameEle.getTextTrim());}}}

相对路径

public class XpathDemo {//2、相对路径:./子元素/子元素   (.代表当前路径)@Testpublic void parse02() throws Exception {//a.创建解析器对象SAXReader saxReader = new SAXReader();//b.把XML加载成Document对象Document document =saxReader.read(XpathDemo.class.getResourceAsStream("/Contacts2.xml"));Element root = document.getRootElement();//c.检索全部名称List<Node> nameNodes = root.selectNodes("./contact/name");for (Node nameNode : nameNodes) {Element nameEle = (Element) nameNode;System.out.println(nameEle.getTextTrim());}}}

全文搜索

public class XpathDemo {/*3、全文搜索://元素  在全文找这个元素//元素1/元素2   在全文找元素1下面的一级元素2//元素1//元素2  在全文找元素1下面的全部元素2*/@Testpublic void parse03() throws Exception {//a.创建解析器对象SAXReader saxReader = new SAXReader();//b.把XML加载成Document对象Document document =saxReader.read(XpathDemo.class.getResourceAsStream("/Contacts2.xml"));//c.检索数据
//        List<Node> nameNodes = document.selectNodes("//name");
//        List<Node> nameNodes = document.selectNodes("//contact/name");List<Node> nameNodes = document.selectNodes("//contact//name");for (Node nameNode : nameNodes) {Element nameEle = (Element) nameNode;System.out.println(nameEle.getTextTrim());}}}

属性查找

public class XpathDemo {/*4、属性查找//@属性名称  在全文检索属性对象//元素[@属性名称]   在全文检索包含该属性的元素对象//元素[@属性名称=值]  在全文检索包含该属性的元素且属性值为该值的元素对象*/@Testpublic void parse04() throws Exception {//a.创建解析器对象SAXReader saxReader = new SAXReader();//b.把XML加载成Document对象Document document =saxReader.read(XpathDemo.class.getResourceAsStream("/Contacts2.xml"));//c.检索数据List<Node> nodes = document.selectNodes("//@id");for (Node node : nodes) {Attribute attr = (Attribute) node;System.out.println(attr.getName() + "====>" + attr.getValue());}//查询name元素(包含id属性的)
//        Node node = document.selectSingleNode("//name[@id]");Node node = document.selectSingleNode("//name[@id=888]");Element ele = (Element) node;System.out.println(ele.getTextTrim());}}

设计模式

工厂模式

public abstract class Computer {private String name;private double price;public abstract void start();public String getName() {return name;}public void setName(String name) {this.name = name;}public double getPrice() {return price;}public void setPrice(double price) {this.price = price;}
}public class Mac extends Computer{@Overridepublic void start() {System.out.println(getName() + "优雅启动");}
}public class HuaWei extends Computer{@Overridepublic void start() {System.out.println(getName()+ "菊花");}
}
public class FactoryPattern {//定义一个方法,创建对象返回public static Computer createComputer (String info){switch (info){case "mac" :Computer c1  =new Mac();c1.setName("MacBook pro");c1.setPrice(19999);return c1;case "huawei" :Computer c2 = new HuaWei();c2.setName("HuaWei pro 16");c2.setPrice(59999);return c2;default:return null;}}
}public class FactoryDemo {public static void main(String[] args) {Computer c1 = FactoryPattern.createComputer("huawei");c1.start();Computer c2 = FactoryPattern.createComputer("mac");c2.start();}
}

装饰模式

//父类
public abstract class InputStream {public abstract int read();public abstract int read(byte[]buffer);
}//原始类
public class FileInputStream extends InputStream{@Overridepublic int read() {System.out.println("以低性能的方式读取一个字节a");return 97;}@Overridepublic int read(byte[] buffer) {buffer[0] = 97;buffer[1] = 98;buffer[2] = 99;System.out.println("以低性能的方式读取了一个字节数组:" + Arrays.toString(buffer));return 3;}
}
//装饰类:继承InputStream 扩展原始类的功能
public class BufferedInputStream extends InputStream{private InputStream is;public BufferedInputStream(InputStream is){this.is = is;}@Overridepublic int read() {System.out.println("提供8KB的缓冲区,提高数据性能");return is.read();}@Overridepublic int read(byte[] buffer) {System.out.println("提供8KB的缓冲区,提高数据性能");return is.read(buffer);}
}public class DecoratorDemo {public static void main(String[] args) {InputStream is = new BufferedInputStream(new FileInputStream());System.out.println(is.read());System.out.println(is.read(new byte[3]));}
}

完结

Java基础一篇就够相关推荐

  1. JAVA中整型常量的长度,Java基础入门篇(三)——Java常量、变量,

    Java基础入门篇(三)--Java常量.变量, 一.Java常量 (一)什么是常量 常量指的是在程序中固定不变的值,是不能改变的数据.在Java中,常量包括整型常量.浮点型常量.布尔常量.字符常量等 ...

  2. 超详细的Java面试题总结(二)之Java基础知识篇

    系列文章: 超详细的Java面试题总结(一)之Java基本知识 超详细的Java面试题总结(二)之Java基础知识篇 超详细的Java面试题总结(三)之Java集合篇常见问题 超详细的Java面试题总 ...

  3. (Java实习生)每日10道面试题打卡——Java基础知识篇2

    临近秋招,备战暑期实习,祝大家每天进步亿点点! 本篇总结的是Java基础知识相关的面试题,后续会每日更新~ 1.请你说一下Java中的IO流?以及他们的分类和作用? IO 流的分类: 按照数据流的方向 ...

  4. 你所需要的java基础提升篇大总结

    java基础篇深入解析大总结 java基础(一) 深入解析基本类型 java基础(二) 自增自减与贪心规则 java基础(三) 加强型for循环与Iterator java基础(四) java运算顺序 ...

  5. (Java实习生)每日10道面试题打卡——Java基础知识篇

    临近秋招,备战暑期实习,祝大家每天进步亿点点! 本篇总结的是Java基础知识相关的面试题,后续会每日更新~ 1.请你说一下什么是面向对象? Java是面向对象的编程语言,不同于C语言是面向过程的.对于 ...

  6. 「Java面试题精华集」Java基础知识篇(2022最新版)附PDF版

    两个星期前,我和我的好朋友决定做一系列的 Java 知识点常见重要问题的小册.小册的标准就一个,那就是:取精华,取重点.每一本小册,我们都会充分关注我们所总结的知识点是否达到这个标准. 昨天晚上终于把 ...

  7. java基础知识点_「Java面试题/知识点精华集」20000+字的Java基础知识篇(2020最新版) !

    " 本文已经收录进我的 79K Star 的 Java 开源项目 JavaGuide:https://github.com/Snailclimb/JavaGuide (「Java学习+面试指 ...

  8. Java基础知识篇(2020最新版) 准备放进收藏夹吃灰的勿进

    . Java 基本功 1.1. Java 入门(基础概念与常识) 1.1.1. Java 语言有哪些特点? 简单易学: 面向对象(封装,继承,多态): 平台无关性( Java 虚拟机实现平台无关性): ...

  9. Java 基础进阶篇(四):抽象类与模板方法设计模式

    文章目录 一.抽象类.抽象方法概述 二.抽象类的特征 三.模板方法设计模式 3.1使用场景 3.2 实现步骤 3.3 写作文案例 补充:final 和 abstract 是什么关系? 一.抽象类.抽象 ...

最新文章

  1. mfc 访问局域网mysql_数据库操作:MFC连接与MYSQL
  2. 人生三部曲:顺序,选择,循环
  3. python特征选择relieff图像特征优选_ReliefF与QPSO结合的故障特征选择算法
  4. How should I set up tag files for a multi-level directory hierarchy? kiss snow
  5. Qt之QStackedWidget
  6. 【活动(北京)】Global Azure Bootcamp
  7. C语言入坑指南-数组之谜
  8. 【Oracle】DBA_AUDIT_TRAIL表SES_ACTIONS字段对应的操作列表
  9. 获取Kubernetes容器上下文环境
  10. 六年级下计算机课ppt课件ppt课件,小学信息技术浙摄影版六年级上册第1课 走进计算机说课ppt课件...
  11. OpenCV环境搭建(Windows+Visual studio)及Hello World
  12. 用python实现弹跳球游戏_Python Tkinter弹跳球类游戏res
  13. JetBrains Rider想创建新工程一直显示Syncing Project Templates...
  14. poj3678 Katu Puzzle 【解法一】
  15. 海地PVC/COC认证
  16. MBR分区的恢复 - 数据恢复
  17. 【学习总结】VIO初始化学习1:Monocular Visual–Inertial State Estimation With Online Initialization and Camera–IMU
  18. 每日一道leetcode(python)77. 组合
  19. JS实现九乘九乘法表
  20. python二级考试报名官网_Python 全国考级二级

热门文章

  1. HR/猎头眼中的好简历是什么样子的?
  2. 深度技术GhostXP SP3 2011_06极速体验版
  3. 《走进计算机教室》教案,走进网络教案
  4. python自动化测试岗位_2020自动化测试岗位需求的7项必备技能(更新版)
  5. 手机型号大全资料_建筑工程图纸代号大全,从此识图无压力!
  6. 婚礼请帖_20个精美的婚礼请柬网站设计
  7. OneAlive--游戏音效管理器
  8. 项目实训(十)—— AudioManager音效管理
  9. 灰常牛逼的命令行备忘录 navi
  10. 计算机信息系统集成生产厂家,佛山弱电工程集成计算机信息系统集成工程厂家...