一. 枚举
1.1 枚举概述
是一种特殊的类,经常用于描述几个常用的有限的值
1.2 自定义枚举
格式:
public enum 枚举名{
枚举项(描述一个固定的值),枚举项,...
构造方法...
成员方法...
成员变量...
}
使用:
枚举名.枚举项
java
//描述季节的固定的几个值
public enum Season {
//四个季节,四个枚举项来表示
//spring, summer, autumn, winner
//枚举项都是静态的并且被final修饰的变量,所以命名一般都是大写
SPRING, SUMMER, AUTUMN, WINNER;
//SPRING(1), SUMMER, AUTUMN, WINNER;
//枚举的构造方法不能被外部直接使用new调用
/*private Season(){
}*/
/*private Season(int num){
}*/
/*public void show(){
}*/
}
public class Test {
public static void main(String[] args) {
System.out.println(Season.SPRING);
System.out.println(Season.SUMMER);
System.out.println(Season.AUTUMN);
System.out.println(Season.WINNER);
//所有的枚举都继承java.Enum类
//Enum e = Season.SPRING;
Season s = Season.SPRING;
int result = s.compareTo(Season.SUMMER);
System.out.println(result);
String name = s.name();
System.out.println(name);
wuNong(Season.SPRING);
}
//闫晨宇提供一个务农的方法
public static void wuNong(Season season){
if (season.equals(Season.SPRING)){
System.out.println("播种");
}else if (season.equals(Season.SUMMER)) {
System.out.println("除草");
}else if (season.equals(Season.AUTUMN)) {
System.out.println("收果");
}else if (season.equals(Season.WINNER)) {
System.out.println("收秸秆");
}
}
}
1.3 枚举的本质
枚举本质上就是一个类
所有的枚举都继承了java.lang.Enum
枚举项本质上就是当前枚举的一个变量,被static修饰
二.多线程
2.1 多线程概述
并行: 多个任务在同一个时间点同时执行
并发: 多个任务在同一个时间片段内,交替执行
进程: 计算机分配资源的基本单位
线程: 进程中的一个执行单元(执行路径)
前提: 单核单线程理解
2.2 多线程的三种创建方式
2.2.1 继承Thread类
java
//Thread就是线程
public class MyThread extends Thread {
//写任务的代码
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("MyThread.run中: 我爱柳岩" + i);
}
}
}
public class Test {
public static void main(String[] args) {
//1.创建MyThread类的对象
MyThread mt = new MyThread();
//2.调用start方法,开启线程
mt.start();//用于开启线程,并且自动的执行线程任务run方法 子线程
//jvm会自动开启一个线程,执行main方法中的代码, 该线程 main线程(主线程)
for (int i = 0; i < 100; i++) {
System.out.println("主线程: 我爱舒淇"+i);
}
}
}
注意: 开启线程是调用Thread类的start方法,如果手动调用run方法,不叫开启线程,在当前线程中执行run方法的代码
2.2.2 实现Runnable接口
java
/*
Runnable接口是jdk提供的专门书写线程任务的接口
*/
//自定义的类用于书写线程任务
public class MyRunnable implements Runnable{
@Override
public void run() {
for (int i = 0; i < 100; i++) {
System.out.println("我爱柳岩的妹妹..."+i);
}
}
}
java
public class Test {
public static void main(String[] args) {
//1.创建MyRunnable类的对象
MyRunnable mr = new MyRunnable();
//2.开启线程,执行线程任务
Thread t = new Thread(mr);
t.start();//开启线程,自动执行MyRunnable对象的run方法
Thread t2= new Thread(mr);
t2.start();
//3.使用lambda表达式提供线程任务
Thread t3 = new Thread(()->{
for (int i = 0; i < 1000; i++) {
System.out.println("天王盖地虎,我是第一..."+i);
}
});
t3.start();
}
}
注意: 继承Thread的方式,线程任务和线程耦合死了,不灵活,所以一般使用第二种
2.2.3 实现Callable接口
可以让当前线程获取子线程执行的结果
java
/*
Callable接口是jdk提供的用于规范线程任务的接口 call,可以返回结果
*/
public class MyCallable implements Callable<Long> {
//线程任务
@Override
public Long call() throws Exception {
long sum = 0;
for (int i = 0; i < 100000; i++) {
sum+=i;
}
System.out.println("MyCallable.run 输出: "+sum);
return sum;
}
}
public class Test {
public static void main(String[] args)throws Exception {
//1.创建MyCallable对象
MyCallable mc = new MyCallable();
//2.创建FutureTask类,包装一个Callable
//FutureTask是Runnable接口的实现类
//FurureTask中提供了一个方法 get方法,用于获取未来任务执行完毕后返回的结果
FutureTask<Long> ft = new FutureTask<>(mc);
//2.创建线程,把线程任务交给线程执行
Thread t = new Thread(ft);
t.start();
//获取子线程执行的结果, 一定是在开启线程之后获取
Long result = ft.get();//获取子线程的任务,如果子线程没有返回结果,那么我就一直等等等(阻塞),直到返回结果为止!
System.out.println("子线程运算的结果为: "+result);
}
}
2.3 线程安全
2.3.1 前提
Thread中常见的API
Thread():创建普通的线程
Thread(Runnable r): 创建线程的同时指定线程任务
Thread(Runnable r,String name): 创建线程的同时指定线程任务,并且指定线程的名字
Thread.currentThread(): 获取正在执行的线程对象
String getName(): 获取线程的名字
java
//书写卖票的任务
public class SaleMovieTicketRunnable implements Runnable {
//票的总量
private int tickets = 100;
@Override
public void run() {
//模拟卖票的代码
while (true) {
if (tickets > 0) {
System.out.println(Thread.currentThread().getName()+" 卖出第" + tickets + "张票...");
//票数减少
tickets--;
} else {
//结束卖票
break;
}
}
}
}
public class Test {
public static void main(String[] args) {
//真正的卖票 多窗口同时卖票
SaleMovieTicketRunnable r = new SaleMovieTicketRunnable();
//创建两个线程,模拟卖票
Thread t1 = new Thread(r, "窗口1");
t1.start();
Thread t2 = new Thread(r, "窗口2");
t2.start();
}
}
线程安全问题:
提前:
1.多线程
2.多个线程操作共同的资源
3.多个线程对共同的资源做增删改的操作
本质:
多线程的调用是争抢调度
2.3.2解决线程安全问题
同步(加锁)
同步代码块:
格式:
synchronized(锁){
保证只能有一个线程执行的代码
}
锁: 可以是任何java对象, 多个线程如果要达到同步的效果,这多个线程必须使用的是同一把锁
java
//书写卖票的任务
public class SaleMovieTicketRunnable implements Runnable {
//票的总量
private int tickets = 100;
//private Object lock = new Object();
@Override
public void run() {
//模拟卖票的代码
while (true) {
/*synchronized (lock){
if (tickets > 0) {
System.out.println(Thread.currentThread().getName()+" 卖出第" + tickets + "张票...");
//票数减少
tickets--;
} else {
//结束卖票
break;
}
}*/
synchronized (this){
if (tickets > 0) {
System.out.println(Thread.currentThread().getName()+" 卖出第" + tickets + "张票...");
//票数减少
tickets--;
} else {
//结束卖票
break;
}
}
}
}
}
同步方法:
格式:
public synchronized 返回值类型 方法名(参数列表){
代码
}
锁默认是this
java
//书写卖票的任务
public class SaleMovieTicketRunnable implements Runnable {
//票的总量
private int tickets = 100;
@Override
public void run() {
//模拟卖票的代码
while (true) {
if (sale()){
break;
}
}
}
//同步方法: 锁是this
//返回值代表票有没有卖完
public synchronized boolean sale(){
if (tickets > 0) {
System.out.println(Thread.currentThread().getName()+" 卖出第" + tickets + "张票...");
//票数减少
tickets--;
return false;
} else {
//结束卖票
return true;
}
}
}
2.4 线程池
概念: 使用一个容器(数组|集合),存放了多个线程对象
作用: 提高线程的使用率, 避免创建过多的线程
2.4.2 线程池的使用
1.创建线程池
ThreadPoolExecutor:
java
ThreadPoolExecutor( int corePoolSize,//核心线程的个数
int maximumPoolSize,//最大的线程个数
long keepAliveTime,//线程的最大存活时间
TimeUnit unit,//时间单位
BlockingQueue<Runnable> workQueue,//任务队列
ThreadFactory threadFactory,//线程工厂:创建线程对象
RejectedExecutionHandler handler)//拒绝策略
2.把线程任务交给线程池
java
public class Test {
public static void main(String[] args) {
//创建线程池
ThreadPoolExecutor executor = new ThreadPoolExecutor(
4,//核心线程数量
6,//最大线程数量
10,//最大存活时间
TimeUnit.MINUTES,//时间单位
new ArrayBlockingQueue<>(3),//任务队列
Executors.defaultThreadFactory(),//线程工厂
//new ThreadPoolExecutor.AbortPolicy()//拒绝策略 抛弃任务,报错
//new ThreadPoolExecutor.DiscardPolicy()//拒绝策略 抛弃任务
new ThreadPoolExecutor.CallerRunsPolicy()//拒绝策略, 抛弃任务,那个线程提交的任务,该线程执行这个任务
);
//2.把任务交给线程池 submit(Runnable r)
for (int i = 0; i < 10; i++) {
executor.submit(()->{
System.out.println(Thread.currentThread().getName()+" 我是你大爷...");
});
}
//关闭线程池
//executor.shutdown();
}
}
2.5 java中的异常
2.5.1 概念
程序发生了不正常的现象
jdk提供了大量的XxxException类,用于描述不同类型的异常情况
异常的继承体系:
Throwable(类):
Error(类): 严重的错误(程序员无法通过修改代码解决)
Exception(类): 因为程序员代码书写的问题,导致异常的出现
RuntimeException(类): 运行时异常
很多的子类
很多的其它子类: 编译期异常
java
public class Demo {
public static void main(String[] args) {
//int i = 1/0;//一旦程序发生了不正常的现象,代码不往后走了 ArithmeticException
//System.out.println(i);
//String s = null;
//System.out.println(s.length());//NullPointerException
//int[] arr = {1,2,3};
//System.out.println(arr[5]);//ArrayIndexOutOfBoundsException
A a = new B();
C c = (C)a;//ClassCastException
System.out.println(c);
}
}
class A{
}
class B extends A{
}
class C extends A{
}
2.5.2 异常的产生
throw new XxxException("原因");
java
public class Demo2 {
public static void main(String[] args) {
/*int[] arr = null;
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));*/
/*DateTimeFormatter df = DateTimeFormatter.ofPattern("你大爷");
LocalDateTime date = LocalDateTime.parse("2022-01-01 01:01:01", df);//DateTimeParseException
System.out.println(date);*/
printHelloWorldN(-1);
}
public static void printHelloWorldN(int n) {
//合法性校验
if (n <= 0) {
//System.out.println("参数不合法: " + n + " 必须大于0!");
throw new RuntimeException("参数不合法: " + n + " 必须大于0!");
}
for (int i = 0; i < n; i++) {
System.out.println("HelloWorld~");
}
}
}
2.5.3 异常的处理
throw new XxxException("原因"):产生了异常, 并且把异常抛给调用者
jvm的默认处理:
1.在控制台输出异常的信息
2.停止程序的运行
程序员手动处理:
1.我不处理,我往上抛,抛给我的调用者
throws 异常类名
2.我处理了,不再往上抛了
java
public class Demo04 {
public static void main(String[] args) {
print();
}
//抛出处理
public static void print() {
/*
try..catch
try{
可能产生异常的代码
}catch(XxxException xxx){//发生了XxxException我就处理,否则不处理
异常发生后的处理方案
}
*/
try {
System.out.println("aaaaaaa");
printHelloWorldN(2);//try中一旦产生了异常,那么try中后续的代码将不执行,直接去执行catch代码块
System.out.println("bbbbbbb");
}catch (RuntimeException exception){
System.out.println("处理方案....");
}
}
public static void printHelloWorldN(int n) {
System.out.println("ccccccc");
//合法性校验
if (n <= 0) {
//System.out.println("参数不合法: " + n + " 必须大于0!");
throw new RuntimeException("参数不合法: " + n + " 必须大于0!");
}
System.out.println("ddddddd");
for (int i = 0; i < n; i++) {
System.out.println("HelloWorld~");
}
}
}
2.5.4 编译器异常和运行时异常
Throwable(类):
Error(类): 严重的错误(程序员无法通过修改代码解决)
Exception(类): 因为程序员代码书写的问题,导致异常的出现 编译期异常
RuntimeException(类): 运行时异常
很多的子类
很多的其它子类: 编译期异常
运行时异常: 在编译期间没有提示
编译期异常: 在编译期间有提示, 万一真的出错了,你给我一个解决方案
2.5.5 异常类的常用API
java
public class Demo6 {
public static void main(String[] args) {
/*int[] arr = null;
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));*/
/*DateTimeFormatter df = DateTimeFormatter.ofPattern("你大爷");
LocalDateTime date = LocalDateTime.parse("2022-01-01 01:01:01", df);//DateTimeParseException
System.out.println(date);*/
try {
printHelloWorldN(-1);
} catch (Exception e) {
//Exception对象中,封装了发生异常的详细信息,借助于e对象,得到异常的数据
//获取异常的原因
String message = e.getMessage();
System.out.println(message);
//输出调用栈信息
e.printStackTrace();
}
}
public static void printHelloWorldN(int n) {
//合法性校验
if (n <= 0) {
//System.out.println("参数不合法: " + n + " 必须大于0!");
throw new RuntimeException("参数不合法: " + n + " 必须大于0!");
}
for (int i = 0; i < n; i++) {
System.out.println("HelloWorld~");
}
}
}
2.5.7 finally关键字
格式:
try{
}catch(XxxException e){
}finally{
代码// 不管有没有发生异常,这些代码必须执行
}
java
public class Demo7 {
public static void main(String[] args) {
try{
printHelloWorldN(2);
}catch (RuntimeException r){
System.out.println("处理方案");
}finally {
System.out.println("finally代码块...");
}
}
public static void printHelloWorldN(int n) {
//合法性校验
if (n <= 0) {
//System.out.println("参数不合法: " + n + " 必须大于0!");
throw new RuntimeException("参数不合法: " + n + " 必须大于0!");
}
for (int i = 0; i < n; i++) {
System.out.println("HelloWorld~");
}
}
}
2.5.8 处理异常的注意事项
throws 抛出异常处理还是在try...catch...捕获异常处理中, 声明的异常类型要大于或等于真正抛出的异常类型
java
public class Demo08 {
public static void main(String[] args) {
/*try{
method1(10);
}catch (RuntimeException e){
System.out.println("处理方案...");
}*/
try{
method1(-1);
}catch (Exception e){
System.out.println("处理方案...");
}
}
public static void method1(int n) throws Exception{
//合法性校验
if (n <= 0) {
//System.out.println("参数不合法: " + n + " 必须大于0!");
throw new Exception("参数不合法: " + n + " 必须大于0!");
}
if (n>5){
throw new IOException("IO异常...");
}
}
}
2.5.9 自定义异常
jdk提供的异常类用于描述不同类型的异常, 它无法描述所有的情况做到见名知意, 自定义异常类用于特殊类型的异常情况
定义类,继承Exception或者RuntimeException即可
java
public class ArgumentException extends Exception{
public ArgumentException(){
}
public ArgumentException(String message){
super(message);
}
}
public class Demo09 {
public static void main(String[] args) {
/*try{
method1(10);
}catch (RuntimeException e){
System.out.println("处理方案...");
}*/
try{
method1(-1);
}catch (ArgumentException e){
System.out.println("处理方案...");
}
}
public static void method1(int n) throws ArgumentException{
//合法性校验
if (n <= 0) {
//System.out.println("参数不合法: " + n + " 必须大于0!");
throw new ArgumentException("参数不合法: " + n + " 必须大于0!");
}
}
}
三.网络编程
3.1 网络编程相关概念
概念: 写的程序可以通过网络进行访问
3要素:
ip: 设备在网络上的唯一标识
端口: 设备上程序的唯一标识 0~65535
协议: tcp,udp,ip...
网路模型:
应用层 http
传输层 tcp|udp
网络层 ip
数据链路层|物理层
3.2 TCP通信(CS架构)
网络软件的架构:
B(browser)/S(server)架构: 开发server服务器程序即可,
C(client)/S(server)架构: 开发客户端和服务端
java
public class Client {
public static void main(String[] args) throws Exception{
//Socket(套接字): 完成两个网络设备之间的连接与通信
//1.创建对象完成连接 127.0.0.1: 本机回环地址(代表我当前电脑)(localhost)
Socket s = new Socket("127.0.0.1",8888);
//2.给服务器发送数据
BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw.write("今天晚上我们去打台球...");
bw.flush();
//bw.close();
s.shutdownOutput();//我不再发数据了
//3.获取服务端发送的数据
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
/*String data = br.readLine();
System.out.println(data);*/
String data = null;
while ((data = br.readLine())!=null){
System.out.println(data);
}
s.shutdownInput();//不再读了
//释放资源,断开连接
s.close();
}
}
java
public class Server {
public static void main(String[] args)throws Exception {
//1.创建对象,绑定端口
ServerSocket ss = new ServerSocket(8888);
//2.监听客户端的连接
Socket s = ss.accept();//一旦有客户端连接,这个方法会返回一个socket对象,跟客户通信
//3.接收客户端发送数据的代码
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String data = br.readLine();
System.out.println(data);
//br.close();
s.shutdownInput();//我不再读客户端发送的数据了
//4.服务端给客户端发送数据
/*BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw.write("好哈,老地方,不见不散...");
bw.newLine();//写出一个换行
bw.write("记得买烟...");
bw.newLine();//写出一个换行
bw.write("记得带水...");
bw.flush();*/
PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
pw.println("好啊,不见不散");
pw.println("记得买烟...");
pw.println("记得带水...");
pw.println("记得带杆...");
pw.flush();
s.shutdownOutput();//不再发了
//释放资源
s.close();
ss.close();
}
}
3.3 HTTP协议
http概念: hyper text transport protocol: 超文本(不仅可以包含文本,还可以包含视频,音频,图片等多媒体数据)传输协议, 规定数据传输双方的规则
特点:
1.无状态的协议
2.基于TCP实现的高级协议
3.默认端口80
4.一次请求只对应一次响应
请求数据格式:
请求行: GET / HTTP/1.1
请求方式 请求资源路径 协议/版本
请求头: Host: localhost:8888
键值对, 键是http协议规定好的,值可以修改
请求空行: 空行,啥都没有,分隔请求头和请求体
请求体:
username=zhangsan&password=123456
响应数据格式:
响应行: HTTP/1.1 200 OK
协议/版本 响应状态码 描述
2xx: 200 成功
3xx: 302 重定向
4xx: 404 浏览器路径写错了或者是参数传递错了或者是请求方式错了...
5xx: 500 服务器发生错误
响应头: Content-Type: image/gif
响应头名字是http协议规定好的, 值可以修改
响应空行: 空行,啥都没有,分隔响应头和响应体
响应体:
服务器给浏览器响应的主体数据
3.4 TCP实现BS架构
java
public class Server {
public static void main(String[] args)throws Exception {
//1.创建对象,绑定端口
ServerSocket ss = new ServerSocket(8888);
//2.监听客户端的连接
Socket s = ss.accept();//一旦有客户端连接,这个方法会返回一个socket对象,跟客户通信
//3.接收客户端发送数据的代码
BufferedReader br = new BufferedReader(new InputStreamReader(s.getInputStream()));
String data = null;
while (!(data = br.readLine()).equals("")){
System.out.println("读取: "+data);//""
}
//br.close();
s.shutdownInput();//我不再读客户端发送的数据了
//4.服务端给客户端发送数据
/*BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw.write("好哈,老地方,不见不散...");
bw.newLine();//写出一个换行
bw.write("记得买烟...");
bw.newLine();//写出一个换行
bw.write("记得带水...");
bw.flush();*/
PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
//写响应行
pw.println("HTTP/1.1 200 OK");
pw.println("Content-Type: text/html;charset=utf-8");
pw.println();
pw.println("<h1 style='color:red'>好啊,不见不散</h1>");
pw.println("<h2>记得买烟...</h2>");
pw.println("记得带水...");
pw.println("记得带杆...");
pw.flush();
System.out.println("aaaaaaa");
s.shutdownOutput();//不再发了
//释放资源
//s.close();
//ss.close();
}
}
3.5 Tomcat
equals("")){
System.out.println("读取: "+data);//""
}
//br.close();
s.shutdownInput();//我不再读客户端发送的数据了
//4.服务端给客户端发送数据
/*BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(s.getOutputStream()));
bw.write("好哈,老地方,不见不散...");
bw.newLine();//写出一个换行
bw.write("记得买烟...");
bw.newLine();//写出一个换行
bw.write("记得带水...");
bw.flush();*/
PrintWriter pw = new PrintWriter(new OutputStreamWriter(s.getOutputStream()));
//写响应行
pw.println("HTTP/1.1 200 OK");
pw.println("Content-Type: text/html;charset=utf-8");
pw.println();
pw.println("<h1 style='color:red'>好啊,不见不散</h1>");
pw.println("<h2>记得买烟...</h2>");
pw.println("记得带水...");
pw.println("记得带杆...");
pw.flush();
System.out.println("aaaaaaa");
s.shutdownOutput();//不再发了
//释放资源
//s.close();
//ss.close();
}
}
### 3.5 Tomcat