宁晋网站建设公司,有好的网站推荐一下吗,市场调研报告ppt模板,青州做网站的网络公司Java10 #xff08;一#xff09;、配置文件#xff08;二#xff09;、多线程2.1 并发和并行2.2 多线程的实现方式2.3 常见成员方法2.3.1 线程的优先级2.3.2 守护线程#xff08;备胎线程#xff09;2.3.3 礼让线程和插入线程 2.4 线程生命周期2.5 线程安全问题2.6 锁2.… Java10 一、配置文件二、多线程2.1 并发和并行2.2 多线程的实现方式2.3 常见成员方法2.3.1 线程的优先级2.3.2 守护线程备胎线程2.3.3 礼让线程和插入线程 2.4 线程生命周期2.5 线程安全问题2.6 锁2.6.1 死锁 2.7 等待唤醒机制2.7.1 阻塞队列实现等待唤醒机制 2.8 多线程的6种状态2.9 综合练习2.9.1 送礼物2.9.2 抢红包2.9.3抽奖12.9.4 抽奖2 多线程的统计2.9.5 抽奖3多线程的比较 2.10 线程池2.10.1 自定义线程池 三、网络编程3.1 网络编程三要素3.1.1 IP3.1.2 InetAddress类3.1.3 端口号3.1.4 协议3.1.4.1 UDP协议3.1.4.1 TCP协议 3.2 综合练习3.2.1 多发多收3.2.2 接收和反馈3.2.3 上传文件3.2.4 上传文件多线程版3.2.5 BS架构3.2.6 聊天室 四、反射4.1 获取class对象三种方法4.2 反射获取4.3 练习 五、动态代理 一、配置文件
好处 1.可以把软件的设置永久化存储 2.如果我们要修改参数不需要改动代码直接修改配置文件就行
properties配置文件 后缀名就是properties 文件中数据都是按照键值对存储 可以往Properties添加任意类型数据但是一般只添加string类型数据 特有方法store和load load加载把本地文件数据加载进程序中 store保存把数据写进本地文件
二、多线程
多线程可以让程序同时做多件事情提高运行效率 线程操作系统能够进行运算调度的最小单位。它被包含在进程之中是进程中的实际运作单位应用软件中相互独立可以同时运行的功能
进程是程序的基本执行实体 一个软件运行之后就是一个进程
2.1 并发和并行
并发同一时刻多个指令在单个cpu上交替执行 并行同一时刻多个指令在多个cpu上同时执行
2.2 多线程的实现方式
1.继承Thread类的方式进行实现 测试类
package dxc;public class d1 {public static void main(String[] args) {/** 多线程的第一种启动方式* 1.定义一个类继承Thread* 2.重写run方法* 3.创建子类的对象并启动线程** */MyThread t1new MyThread();MyThread t2new MyThread();t1.setName(线程1);t2.setName(线程2);//开启线程t1.start();t2.start();//交替运行}
}
MyThread
package dxc;public class MyThread extends Thread {Overridepublic void run() {for (int i 0; i 100 ; i) {System.out.println(getName()HelloWorld);}}
}
2.实现Runnable接口的方式进行实现 测试类
package dxc;public class d2 {public static void main(String[] args) {/** 1.自己定义一个类实现Runnable接口* 2.重写里面的run方法* 3.创建自己的类的对象* 4.创建一个Thread类的对象并开启线程* *///创建MyRun对象表示多线程要执行的任务MyRun mrnew MyRun();//创建线程对象Thread t1new Thread(mr);//将要执行的任务放进去Thread t2new Thread(mr);//给线程设置名字t1.setName(线程1);t2.setName(线程2);t1.start();t2.start();//交替执行}
}
MyRun
package dxc;public class MyRun implements Runnable{Overridepublic void run() {//书写线程要执行的代码for (int i 0; i 100; i) {//获取到当前线程的对象Thread t Thread.currentThread();System.out.println(t.getName()HelloWorld);}}
}
3.利用Callable接口和Future接口方式实现 测试类
package dxc;import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class d3 {public static void main(String[] args) throws ExecutionException, InterruptedException {/** 特点可以获取多线程运行的结果** 1.创建一个类MyCallable实现Callable接口* 2.重写call有返回值表示多线程运行结果* 3.创建MyCallable的对象表示多线程要执行的任务* 4.创建FutureTask对象管理多线程运行的结果* 5.创建Thread类的对象并启动表示线程* */MyCallable mcnew MyCallable();FutureTaskInteger ftnew FutureTask(mc);Thread t1new Thread(ft);t1.start();Integer result ft.get();System.out.println(result);}
}
MyCallable
package dxc;import java.util.concurrent.Callable;public class MyCallable implements CallableInteger {Overridepublic Integer call() throws Exception {int sum0;for (int i 0; i 100; i) {sumi;}return sum;}
}
三种实现方式优缺点
2.3 常见成员方法 注 如果不给线程设置名字线程有默认名字 格式Thread-xx从0开始
Thread构造方法可以传递一个字符串直接设置线程名字
JVM虚拟机启动后会自动启动多条线程 其中一条线程叫main线程作用是调用main方法并执行里面的代码
sleep哪条线程执行到这个方法这条线程就会在这里停留对应的时间 方法的参数就是停留的时间毫秒。时间到了后线程会自动醒来继续执行下面其他代码
2.3.1 线程的优先级
Java中线程是抢占式调度随机 默认线程优先级是5 优先级1-101最小 优先级高只是抢占cpu概率大先执行完的概率大但并非100%抢占
2.3.2 守护线程备胎线程
当其他非守护线程执行完毕之后守护线程也会陆续执行完毕
2.3.3 礼让线程和插入线程
礼让线程出让cpu的执行权 用在run方法中尽可能让执行结果均匀
插入线程
package dxc;public class d5 {public static void main(String[] args) throws InterruptedException {MyThread tnew MyThread();t.setName(土豆);t.start();//表示把t这个线程插入到当前线程之前//t:土豆//当前线程main线程t.join();//执行在main线程当中的for (int i 0; i 10; i) {System.out.println(main线程i);}}
}
2.4 线程生命周期 sleep结束后是不会立即执行下方代码的要等抢到执行权
2.5 线程安全问题
线程执行有随机性。产生如数据越界重复等等问题
同步代码块 把操作共享数据的代码锁起来 格式 锁对象可以是任意的但是锁对象一定是唯一的 特点1锁默认打开有一个线程进去了锁自动关上 特点2当里面所有代码执行完毕线程出来锁自动打开
注同步代码块不能写在循环的外面 锁对象可以使用当前类的字节码文件对象。类名.class
同步方法把synchronized加在方法上写在修饰符后面 特点1.同步方法是锁住方法里面所有的代码 2.锁对象不能自己指定非静态方法this。静态方法当前类的字节码文件对象
StringBuffer用于多线程安全中
需求100个票三个窗口卖票
package dxDemo;public class MyRunnable implements Runnable{int ticket0;Overridepublic void run() {//1.循环//2.同步代码块同步方法//3.判断共享数据是否到了末尾while (true){if (method()) break;}}private synchronized boolean method(){if (ticket100){return true;}else {ticket;System.out.println(Thread.currentThread().getName()在卖第ticket张票);}return false;}
}
test
package dxDemo;public class test {public static void main(String[] args) {MyRunnable mrnew MyRunnable();Thread t1new Thread(mr);Thread t2new Thread(mr);Thread t3new Thread(mr);t1.setName(窗口1);t2.setName(窗口2);t3.setName(窗口3);t1.start();t2.start();t3.start();}
}
2.6 锁
手动上锁和释放锁 void lock获得锁 void unlock释放锁
卖票代码改成手动锁
package dxDemo;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class MyRunnable implements Runnable{static int ticket0;static Lock locknew ReentrantLock();Overridepublic void run() {//1.循环//2.同步代码块同步方法//3.判断共享数据是否到了末尾while (true){lock.lock();try {if (ticket100){break;}else {Thread.sleep(10);ticket;System.out.println(Thread.currentThread().getName()在卖第ticket张票);}} catch (InterruptedException e) {throw new RuntimeException(e);}finally {lock.unlock();}}}}
2.6.1 死锁
是一种错误一个线程拿a锁一个拿b锁都在等对方解锁 不要让锁嵌套容易造成死锁使代码卡死
2.7 等待唤醒机制
生产者和消费者模式
生产者生产数据 消费者消费数据
常见方法
需求完成生产者和消费者等着唤醒机制的代码 实现线程轮流交替执行过程
厨师代码
package dxcday2;public class Cook extends Thread{Overridepublic void run() {/** 1.循环* 2.同步代码块* 3.判断共享数据是否到了末尾到了* 4.没到执行核心逻辑* */while (true){synchronized (Desk.lock){if (Desk.count0){break;}else {//判断桌子有没有食物if(Desk.foodFlag1){//有就等待try {Desk.lock.wait();} catch (InterruptedException e) {throw new RuntimeException(e);}}else {System.out.println(厨师做了一碗面条);//没有就制作修改桌子状态Desk.foodFlag1;//唤醒消费者开吃Desk.lock.notifyAll();}}}}}
}
食客代码
package dxcday2;public class Fooddie extends Thread{/** 1.循环* 2.同步代码块* 3.判断共享数据是否到了末尾到了* 4.没到执行核心逻辑* */Overridepublic void run() {while (true){synchronized (Desk.lock ){if (Desk.count0){break;}else {//判断桌子上有没有面条//没有就等待if (Desk.foodFlag0){try {Desk.lock.wait();//让当前线程跟锁绑定} catch (InterruptedException e) {throw new RuntimeException(e);}}else {Desk.count--;//总数-1要先-1再打印//有就开吃System.out.println(食客在吃面条还能吃Desk.count碗);//吃完要唤醒厨师并且总数-1,修改桌子状态Desk.lock.notifyAll();//唤醒Desk.foodFlag0;//修改桌子状态}}}}}
}
凳子代码
package dxcday2;public class Desk {/** 控制生产者和消费者的执行* *///表示桌子上是否有面条0是没有1是有//如果有多线程直接定义这个值就行public static int foodFlag0;//总个数能吃几碗面public static int count10;//锁对象public static Object locknew Object();}
测试代码
package dxcday2;public class dxc1 {public static void main(String[] args) {/** 需求完成生产者和消费者等着唤醒机制的代码* 实现线程轮流交替执行过程* *///创建线程对象Cook cnew Cook();Fooddie fdnew Fooddie();c.setName(厨师);fd.setName(食客);c.start();fd.start();}}
2.7.1 阻塞队列实现等待唤醒机制
厨师put数据进管道 食客take数据
take方法和put方法底层都有锁写代码时不需要加锁 实现了四个接口 两个实现类 ArrayBlockingQueue底层是数组有界 LinkedBlockingQueue底层是链表无界。但不是真正无界界限是int的最大值
Cook代码
package dxcday2_1;import java.util.concurrent.ArrayBlockingQueue;public class Cook extends Thread{ArrayBlockingQueueString queue;public Cook(ArrayBlockingQueueString queue) {this.queue queue;}Overridepublic void run() {while (true){//不断添加面条进阻塞队列中try {queue.put(面条);System.out.println(厨师放了一碗面条进去);//打印语句在锁的外面所以执行时看起来数据是乱的实际上是正确的。没有影响到共享数据} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
Fooddie
package dxcday2_1;import java.util.concurrent.ArrayBlockingQueue;public class Fooddie extends Thread {ArrayBlockingQueueString queue;public Fooddie(ArrayBlockingQueueString queue) {this.queue queue;}Overridepublic void run() {while (true) {//不断从阻塞队列中获取面条try {String food queue.take();System.out.println(food);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}
Test
package dxcday2_1;import java.util.concurrent.ArrayBlockingQueue;public class Test {public static void main(String[] args) {ArrayBlockingQueueString abqnew ArrayBlockingQueue(1);//创建线程把阻塞队列传递过去Cook cnew Cook(abq);Fooddie fnew Fooddie(abq);c.start();f.start();}
}
2.8 多线程的6种状态 实际上Java虚拟机中没有运行状态
2.9 综合练习
2.9.1 送礼物 线程1
package dxczhlx;public class p2 extends Thread{Overridepublic void run() {while (true){synchronized (lw.lock){if (lw.i10){break;}else {try {sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(getName()送出第lw.i份礼物);lw.i--;}}}}
}
线程2
package dxczhlx;public class p1 extends Thread{Overridepublic void run() {while (true){synchronized (lw.lock){if (lw.i10){break;}else {try {sleep(10);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(getName()送出第lw.i份礼物);lw.i--;}}}}
}
控制类
package dxczhlx;public class lw {public static int i100;public static Object locknew Object();
}
test
package dxczhlx;public class test {public static void main(String[] args) {p1 p1new p1();p2 p2new p2();p1.setName(小程);p2.setName(小羊);p1.start();p2.start();}
}
2.9.2 抢红包 MyThread精确数字使用BigDecimal
package lx2;import java.util.Random;public class MyThread extends Thread{//共享数据//100块分3个包static double money100;static int count3;//最小的中奖金额static final double MIN0.01;Overridepublic void run() {synchronized (MyThread.class){if (count0){//判断共享数据是否到了末尾已经到了System.out.println(getName()没有抢到红包);}else {//没到//不能直接随机//定义一个变量表示中奖金额double prize0;if (count1){//表示此时最后一个红包无需随机金额就是剩余金额prizemoney;}else {//表示第一次和第二次Random rnew Random();//100-3-1*0.01 第一个红包最多99.98元double boundsmoney-(count-1)*MIN;prizer.nextDouble(bounds);//jdk17的方法if (prizeMIN){prizeMIN;//如果随机金额小于最小金额强制变成最小金额}}//从money中去掉当前中奖金额moneymoney-prize;//红包个数-1count--;//打印本次红包信息System.out.println(getName()抢到了prize元);}}}
}
test
package lx2;public class test {public static void main(String[] args) {MyThread t1new MyThread();MyThread t2new MyThread();MyThread t3new MyThread();MyThread t4new MyThread();MyThread t5new MyThread();t1.setName(小1);t2.setName(小2);t3.setName(小3);t4.setName(小4);t5.setName(小5);t1.start();t2.start();t3.start();t4.start();t5.start();}
}
2.9.3抽奖1 可以将sleep方法写在锁的外面使结果尽可能平均 MyThread
package lx3;import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;public class MyThread extends Thread{//定义共享数据ArrayListInteger list;public MyThread(ArrayListInteger list) {this.list list;}Overridepublic void run() {while (true){synchronized (MyThread.class){if (list.size()0){break;}else {//继续抽奖Collections.shuffle(list);int prize list.remove(0);System.out.println(getName()又产生了prize元大奖);}}}}}
Test
package lx3;import java.util.ArrayList;
import java.util.Collections;public class Test {public static void main(String[] args) {//创建奖池ArrayListInteger listnew ArrayList();Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);MyThread t1new MyThread(list);MyThread t2new MyThread(list);t1.setName(抽奖箱1);t2.setName(抽奖箱2);t1.start();t2.start();}
}
2.9.4 抽奖2 多线程的统计 MyThread
package lx4;import java.util.ArrayList;
import java.util.Collections;public class MyThread extends Thread{//定义共享数据ArrayListInteger list;//创建集合存储抽到的金额//线程一static ArrayListInteger list1new ArrayList();//线程二static ArrayListInteger list2new ArrayList();public MyThread(ArrayListInteger list) {this.list list;}Overridepublic void run() {while (true){synchronized (MyThread.class){if (list.size()0){if (抽奖箱1.equals(getName())){int result10;int max10;for (Integer num : list1) {result1num;if (nummax1){max1num;}}System.out.println(抽奖箱1list1总金额为result1最大值为max1);}else {int result20;int max20;for (Integer num : list2) {result2num;if (nummax2){max2num;}}System.out.println(抽奖箱2list2总金额为result2最大值为max2);}break;}else {//继续抽奖Collections.shuffle(list);int prize list.remove(0);//System.out.println(getName()又产生了prize元大奖);if (抽奖箱1.equals(getName())){list1.add(prize);}else {list2.add(prize);}}}}}}
Test
package lx4;import java.util.ArrayList;
import java.util.Collections;public class Test {public static void main(String[] args) {//创建奖池ArrayListInteger listnew ArrayList();Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);MyThread t1new MyThread(list);MyThread t2new MyThread(list);t1.setName(抽奖箱1);t2.setName(抽奖箱2);t1.start();t2.start();}
}
改进把存储金额的集合放在run方法中不同线程会在自己的栈中创建集合 每一个线程都有一个栈
2.9.5 抽奖3多线程的比较 MyCallable:
package lx5;import lx4.MyThread;import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.Callable;public class MyCallable implements CallableInteger {//定义共享数据ArrayListInteger list;public MyCallable(ArrayListInteger list) {this.list list;}Overridepublic Integer call() throws Exception {ArrayListInteger boxlistnew ArrayList();while (true){synchronized (MyThread.class){if (list.size()0){System.out.println(Thread.currentThread().getName()boxlist);break;}else {//继续抽奖Collections.shuffle(list);int prize list.remove(0);boxlist.add(prize);}}Thread.sleep(10);}//返回集合最大值if (boxlist.size()0){return null;}else {return Collections.max(boxlist);}}
}
test:
package lx5;import java.util.ArrayList;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Test {public static void main(String[] args) throws ExecutionException, InterruptedException {ArrayListInteger listnew ArrayList();Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);//创建多线程要运行的参数对象MyCallable mcnew MyCallable(list);//创建多线程运行结果管理者对象FutureTaskInteger ft1new FutureTask(mc);FutureTaskInteger ft2new FutureTask(mc);//创建线程Thread t1new Thread(ft1);Thread t2new Thread(ft2);t1.setName(抽奖箱1);t2.setName(抽奖箱2);t1.start();t2.start();Integer max1 ft1.get();Integer max2 ft2.get();if (max1max2){System.out.println(抽奖箱1产生最大奖项,金额为max1);}else {System.out.println(抽奖箱2产生最大奖项,金额为max2);}}
}
2.10 线程池
用来存放线程的容器
主要核心原理 1.创建一个池子池子中是空的 2.提交任务 时池子会创建新的线程对象任务执行完毕线程归还给池子。下次再提交任务时不需要创建新的线程复用已有线程 3.如果提交任务时池子中没有空闲线程也无法创建新的线程任务就会排队等待
Executors线程池的工具类通过调用方法返回不同类型的线程池对象 submit提交任务 shutdown销毁线程池
2.10.1 自定义线程池
ThreadPoolExecutor 七个参数 1.核心线程数量 2. 线程池中最大线程的数量核心线程数量 3. 空闲时间值 4. 空闲时间单位用TimeUnit指定 5. 阻塞队列 6. 创建线程的方式 7. 要执行的任务过多时的解决方案
临时线程是核心线程都在使用且阻塞队列排满了才会创建临时线程执行任务 先提交的任务不一定先执行
如果任务数核心线程临时线程队伍长度会触发任务拒绝策略 任务拒绝策略是ThreadPoolExecutor的内部类
package zdydxc;import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class z1 {public static void main(String[] args) {ThreadPoolExecutor poolnew ThreadPoolExecutor(3,//核心线程数量6,//最大线程数60,//空闲线程最大存活时间TimeUnit.SECONDS,//时间对象new ArrayBlockingQueue(3),//任务队列Executors.defaultThreadFactory(),//创建线程工厂new ThreadPoolExecutor.AbortPolicy()//任务拒绝策略);}
}
最大并行数cpu的最大线程数
线程池的大小如何定义 CPU密集型运算计算较多最大并行数1 I/O密集型运算读取本地文件或数据库较多 使用Thread dump工具测试CPU计算时间和等待时间
三、网络编程
在网络通信协议下不同计算机上运行的程序进行的数据传输 Java中使用java.net包下的技术
常见软件架构 B/S浏览器/服务器 只需要一个浏览器用户通过不同的网址。客户访问不同的服务器 优点不需要开发客户端只需要页面服务端 用户不需要下载打开浏览器就能使用 缺点如果应用过大用户体验差 C/S客户端/服务器 在用户本地需要下载并安装客户端程序 在远程有一个服务端程序 优点画面精美用户体验好 缺点需要开发客户端和服务端。用户下载和更新麻烦 3.1 网络编程三要素
ip设备在网络中的地址是唯一的标识 端口号 应用程序在设备中唯一的标识 协议数据在网络中传输的规则常见协议有UDP、TCP、http、https、ftp
3.1.1 IP
上网设备在网络中的地址是唯一的
常见分类 IPv4互联网通信协议第四版 采用32位地址长度分成四组。总共42亿多ip已经分配完毕 分类 公网地址万维网使用和私有地址局域网使用 192.168.开头就是私有地址 特殊ip127.0.0.1回送地址也称本地回环地址本机ip永远只会寻找当前所在本机 CMD命令ipconfig查看本机IP地址。ping检查网络是否连通 IPv6互联网通信协议第六版 128位地址长度分8组 最多2的128次方个ip 3.1.2 InetAddress类 package zdydxc;import java.net.InetAddress;
import java.net.UnknownHostException;public class z2 {public static void main(String[] args) throws UnknownHostException {InetAddress address InetAddress.getByName(LAPTOP-B2IFU3U3);//可以传递主机名也可以传递ipSystem.out.println(address);String name address.getHostName();//获取主机名System.out.println(name);String ip address.getHostAddress();//获取ipSystem.out.println(ip);}
}
3.1.3 端口号
由两个字节表示的整数取值范围0-65535 其中0-1023用于一些知名的网络服务或应用 我们自己使用1024以上的就可以
注一个端口号只能被一个应用程序使用
3.1.4 协议 UDP协议用户数据报协议 面向无连接的通信协议 速度快有大小限制一次最多发送64k数据不安全容易丢失数据
TCP协议传输控制协议 面向有连接的通信协议 速度慢没有大小限制数据安全
3.1.4.1 UDP协议
发送数据 1.创建发送端的DatagramSocket对象 2.数据打包DatagramPacket 3.发送数据 4.释放资源
package zdydxc;import java.io.IOException;
import java.net.*;public class z3 {public static void main(String[] args) throws IOException {//绑定端口 通过这个端口往外发送数据//空参从所有可用端口中随机一个使用//有参指定端口号进行绑定DatagramSocket dsnew DatagramSocket();//打包数据String str你好;byte[] bytes str.getBytes();InetAddress addressInetAddress.getByName(127.0.0.1);int port10086;DatagramPacket dpnew DatagramPacket(bytes,bytes.length,address,port); //发送数据ds.send(dp);//释放资源ds.close();}
}
接受数据 1.创建DatagramSocket对象 2.接收打包好的数据 3.解析数据包 4.释放资源
package zdydxc;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.SocketException;public class z3js {public static void main(String[] args) throws IOException {//创建对象//接受时必须绑定端口并且绑定端口要和发送端口保持一致DatagramSocket dsnew DatagramSocket(10086);//接收数据包byte[] b1new byte[1024];DatagramPacket dpnew DatagramPacket(b1,b1.length);//该方法是阻塞的//程序执行到这一步会在这里死等//等发送端发送消息ds.receive(dp);//解析数据包byte[] data dp.getData();int length dp.getLength();InetAddress address dp.getAddress();int port dp.getPort();System.out.println(接收到数据new String(data,0,length));System.out.println(该数据是从address这台电脑中的port这个端口发送的);ds.close();}
}
练 发送端
package udplx;import java.io.IOException;
import java.net.*;
import java.util.Scanner;public class send {public static void main(String[] args) throws IOException {DatagramSocket dsnew DatagramSocket();Scanner scnew Scanner(System.in);System.out.println(请输入要说的话);while (true) {String str sc.nextLine();if (886.equals(str)){break;}byte[] bytes str.getBytes();InetAddress addressInetAddress.getByName(127.0.0.1);int port10086;//打包数据DatagramPacket dpnew DatagramPacket(bytes,bytes.length,address,port);//发送ds.send(dp);}ds.close();}
}
接收端
package udplx;import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;public class receive {public static void main(String[] args) throws IOException {DatagramSocket dsnew DatagramSocket(10086);byte[] bytesnew byte[1024];DatagramPacket dpnew DatagramPacket(bytes,bytes.length);while (true) {ds.receive(dp);byte[] data dp.getData();int length dp.getLength();System.out.println(new String(data,0,length));}}
}
UDP三种通信方式 单播一对一 组播给一组电脑发送数据 组播地址224.0.0.0-239.255.255.255 其中224.0.0.0-224.0.0.255为预留组播地址 组播创建的是MulticastSocket对象其他代码与单播差不多 接收端要将本机添加到组中
广播给所有电脑发送数据 广播地址255.255.255.255 广播代码与单播一样ip改成广播地址就行
3.1.4.1 TCP协议 客户端 1.创建客户端的Socket对象与指定服务端连接 2.获取输出流写数据 3.释放资源
package tcp;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;public class client {public static void main(String[] args) throws IOException {//创建对象的同时会连接服务端//如果连接不上代码会报错Socket socketnew Socket(127.0.0.1,10000);//获取输出流OutputStream os socket.getOutputStream();//写出数据os.write(aaa.getBytes());//3.释放资源os.close();socket.close();}
}
服务端 1.创建服务端的Socket对象ServerSocket 2.监听客户端连接返回一个Socket对象 3.获取输入流读数据并把数据显示在控制台 4.释放资源
package tcp;import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class server {public static void main(String[] args) throws IOException {//创建对象保证与客户端端口一致ServerSocket ssnew ServerSocket(10000);//监听客户端的连接Socket socket ss.accept();//从连接通道获取输入流InputStream is socket.getInputStream();int b;while ((bis.read()) !-1){System.out.println((char) b);}socket.close();ss.close();}
}
中文乱码问题将字节流转换字符流
package tcp;import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class server {public static void main(String[] args) throws IOException {//创建对象保证与客户端端口一致ServerSocket ssnew ServerSocket(10000);//监听客户端的连接Socket socket ss.accept();//从连接通道获取输入流InputStream is socket.getInputStream();InputStreamReader isrnew InputStreamReader(is);int b;while ((bisr.read()) !-1){System.out.println((char) b);}socket.close();ss.close();}
}
三次握手和四次挥手协议
三次握手保证连接的建立
四次挥手确保连接断开并且数据处理完毕
3.2 综合练习
3.2.1 多发多收 Client
package lx1;import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws IOException {//创建对象Socket socketnew Socket(127.0.0.1,8000);//输出数据Scanner scnew Scanner(System.in);OutputStream os socket.getOutputStream();while (true) {System.out.println(输入要发送的信息);String str sc.nextLine();if (886.equals(str)){break;}os.write(str.getBytes());}socket.close();}
}
server
package lx1;import jdk.nashorn.internal.runtime.Scope;import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {ServerSocket serverSocketnew ServerSocket(8000);Socket socket serverSocket.accept();InputStream is socket.getInputStream();InputStreamReader isrnew InputStreamReader(is);int b;while ((bisr.read()) !-1){System.out.println((char) b);}socket.close();serverSocket.close();}
}
3.2.2 接收和反馈 Server
package lx2;import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;public class Server {public static void main(String[] args) throws IOException {//创建对象ServerSocket serverSocketnew ServerSocket(8001);//等待连接Socket socket serverSocket.accept();InputStream is socket.getInputStream();InputStreamReader isrnew InputStreamReader(is);//读取数据//read方法需要有一个结束标记才会结束读取//不然程序会一直停在这个循环当中等待读取数据int b;while ((bisr.read()) !-1){System.out.println((char) b);}//回写数据String str到底有多开心;OutputStream os socket.getOutputStream();os.write(str.getBytes());socket.close();serverSocket.close();}
}
Client
package lx2;import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {//创建对象Socket socketnew Socket(127.0.0.1,8001);//输出数据String str见到你很高兴;OutputStream os socket.getOutputStream();os.write(str.getBytes());//写出一个结束标记socket.shutdownOutput();//接收服务端回写的数据InputStream is socket.getInputStream();InputStreamReader isrnew InputStreamReader(is);int b;while ((bisr.read()) !-1){System.out.println((char) b);}socket.close();}
}
3.2.3 上传文件 Client
package lx3;import java.io.*;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {Socket socketnew Socket(127.0.0.1,9001);//读取本地文件写到服务端BufferedInputStream bisnew BufferedInputStream(new FileInputStream(day6\\clientdir\\331.jpg));BufferedOutputStream bosnew BufferedOutputStream(socket.getOutputStream());byte[] bytesnew byte[1024];int len;while ((lenbis.read(bytes)) !-1){bos.write(bytes,0,len);}//往服务器写出结束标记socket.shutdownOutput();//接收服务器回写数据BufferedReader brnew BufferedReader(new InputStreamReader(socket.getInputStream()));String s br.readLine();System.out.println(s);//关闭资源socket.close();}
}
Server
package lx3;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;public class Server {public static void main(String[] args) throws IOException {ServerSocket ssnew ServerSocket(9001);//等待连接Socket socket ss.accept();//读取数据并保存到本地文件BufferedInputStream bisnew BufferedInputStream(socket.getInputStream());String name UUID.randomUUID().toString().replace(-,);//生成一个随机且唯一的idBufferedOutputStream bosnew BufferedOutputStream(new FileOutputStream(day6\\serverdir\\name.jpg));byte[] bytesnew byte[1024];int len;while ((lenbis.read(bytes)) !-1){bos.write(bytes,0,len);}//回写数据BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(上传成功);bw.newLine();bw.flush();socket.close();ss.close();}
}
3.2.4 上传文件多线程版 Server
package lx3;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.UUID;public class Server {public static void main(String[] args) throws IOException {ServerSocket ssnew ServerSocket(9001);while (true) {//等待连接Socket socket ss.accept();//开启一条线程//一个用户就对应服务端的一条线程new Thread(new MyRunnable(socket)).start();}}
}
Client
package lx3;import java.io.*;
import java.net.Socket;public class Client {public static void main(String[] args) throws IOException {Socket socketnew Socket(127.0.0.1,9001);//读取本地文件写到服务端BufferedInputStream bisnew BufferedInputStream(new FileInputStream(day6\\clientdir\\331.jpg));BufferedOutputStream bosnew BufferedOutputStream(socket.getOutputStream());byte[] bytesnew byte[1024];int len;while ((lenbis.read(bytes)) !-1){bos.write(bytes,0,len);}//往服务器写出结束标记socket.shutdownOutput();//接收服务器回写数据BufferedReader brnew BufferedReader(new InputStreamReader(socket.getInputStream()));String s br.readLine();System.out.println(s);//关闭资源socket.close();}
}
MyRunnable
package lx3;import java.io.*;
import java.net.Socket;
import java.util.UUID;public class MyRunnable implements Runnable{Socket socket;public MyRunnable (Socket socket){this.socketsocket;}Overridepublic void run() {try {//读取数据并保存到本地文件BufferedInputStream bisnew BufferedInputStream(socket.getInputStream());String name UUID.randomUUID().toString().replace(-,);//生成一个随机且唯一的idBufferedOutputStream bosnew BufferedOutputStream(new FileOutputStream(day6\\serverdir\\name.jpg));byte[] bytesnew byte[1024];int len;while ((lenbis.read(bytes)) !-1){bos.write(bytes,0,len);}//回写数据BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(上传成功);bw.newLine();bw.flush();} catch (IOException e) {throw new RuntimeException(e);} finally {if (socket!null){try {socket.close();} catch (IOException e) {throw new RuntimeException(e);}}}}
}
线程池的服务端
package lx3;import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class Server {public static void main(String[] args) throws IOException {ThreadPoolExecutor poolnew ThreadPoolExecutor(3,//核心线程数16,//线程池总大小60,//空闲时间TimeUnit.SECONDS,//单位new ArrayBlockingQueue(2),//阻塞队列Executors.defaultThreadFactory(),//线程工厂线程池如何创建线程对象new ThreadPoolExecutor.AbortPolicy()//阻塞队列);ServerSocket ssnew ServerSocket(9001);while (true) {//等待连接Socket socket ss.accept();//开启一条线程//一个用户就对应服务端的一条线程// new Thread(new MyRunnable(socket)).start();pool.submit(new MyRunnable(socket));}}
}
3.2.5 BS架构
浏览器中输入:127.0.0.1:端口号 运行服务端接收浏览器传的数据
3.2.6 聊天室
Client
import java.io.*;
import java.net.Socket;
import java.util.Scanner;public class Client {public static void main(String[] args) throws IOException {Socket socket new Socket(127.0.0.1, 8003);System.out.println(服务器已经连接成功);//最里面是字节流转换为字符流包裹在缓冲流中BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));while (true) {System.out.println(--------------欢迎来到黑马聊天室--------------);System.out.println(1.登录);System.out.println(2.注册);System.out.println(输入您的选择);Scanner sc new Scanner(System.in);String choose sc.nextLine();switch (choose) {case 1 : login(socket);break;case 2 : System.out.println(用户选择注册);break;default : System.out.println(没有这个选项);break;}}}public static void login(Socket socket) throws IOException {//获取输出流BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));//键盘录入Scanner scnew Scanner(System.in);System.out.println(请输入用户名);String usernamesc.nextLine();System.out.println(请输入密码);String passwordsc.nextLine();//拼接//格式 usernamezhangsanpassword123StringBuilder sbnew StringBuilder();sb.append(username).append(username).append(password).append(password);//第一次写的是什么操作登录或者注册bw.write(login);bw.newLine();bw.flush();//第二次写的是用户名和密码bw.write(sb.toString());bw.newLine();bw.flush();//获取输入流BufferedReader brnew BufferedReader(new InputStreamReader(socket.getInputStream()));String message br.readLine();//根据回写的数据不同做出不同操作//1.登录成功 2.密码有误 3.用户名不存在if (1.equals(message)){System.out.println(登录成功开始聊天);//开一条单独的线程专门用来接收服务端发送过来的聊天记录new Thread(new ClientMyRunnable(socket)).start();//开始聊天talk2All(bw);}else if (2.equals(message)){System.out.println(密码有误);} else if (3.equals(message)) {System.out.println(用户名不存在);}}//往服务器写出消息private static void talk2All(BufferedWriter bw) throws IOException {Scanner scnew Scanner(System.in);while (true){System.out.println(请输入您要说的话);String str sc.nextLine();//把聊天内容写给服务器bw.write(str);bw.newLine();bw.flush();}}
}class ClientMyRunnable implements Runnable{Socket socket;public ClientMyRunnable(Socket socket){this.socketsocket;}Overridepublic void run() {while (true) {try {//接收服务器发过来的聊天记录BufferedReader brnew BufferedReader(new InputStreamReader(socket.getInputStream()));String msg br.readLine();System.out.println(msg);} catch (IOException e) {throw new RuntimeException(e);}}}
}Server
import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Properties;public class Server {static ArrayListSocket listnew ArrayList();public static void main(String[] args) throws IOException {ServerSocket ssnew ServerSocket(8003);//1.获取本地正确的用户名和密码Properties propnew Properties();FileInputStream fisnew FileInputStream(chat\\a.txt);prop.load(fis);//加载数据fis.close();//2.接收客户端的数据并进行判断while (true){Socket socket ss.accept();new Thread(new MyRunnable(socket,prop)).start();}}
}class MyRunnable implements Runnable{Socket socket;Properties prop;MyRunnable(Socket socket,Properties prop){this.propprop;this.socketsocket;}Overridepublic void run() {//接收用户发送的数据try {BufferedReader brnew BufferedReader(new InputStreamReader(socket.getInputStream()));while (true) {String choose br.readLine();//第一次读取switch (choose){case login :login(br);break;case register: register();}}} catch (IOException e) {throw new RuntimeException(e);}}//获取用户登录的信息并判断是否正确public void login (BufferedReader br) throws IOException {//第二次读取String userinfo br.readLine();String[] userInfoArr userinfo.split();String usernameInputuserInfoArr[0].split()[1];String passwordInputuserInfoArr[1].split()[1];//判断用户名是否存在if (prop.containsKey(usernameInput)){String rightPassword prop.get(usernameInput) ;if (rightPassword.equals(passwordInput)){//提示用户登录成功开始聊天writeMessagetoClient(1);//登陆成功时把客户端连接到的Socket对象保存起来Server.list.add(socket);//写一个while循环表示正在聊天//接收客户端发送的消息并打印在控制台//写成一个方法talkAll(br,usernameInput);while (true){}}else {//密码有误writeMessagetoClient(2);}}else {//用户名不存在writeMessagetoClient(3);}}private void talkAll(BufferedReader br,String username) throws IOException {while (true){String message br.readLine();System.out.println(username发送过来消息message);//群发操作for (Socket s : Server.list) {//s依次表示每一个客户端的连接对象writeMessagetoClient(s,username发送过来消息message);}}}//给客户端回写数据public void writeMessagetoClient(String message) throws IOException {BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));bw.write(message);bw.newLine();bw.flush();}public void writeMessagetoClient(Socket s, String message) throws IOException {BufferedWriter bwnew BufferedWriter(new OutputStreamWriter(s.getOutputStream()));bw.write(message);bw.newLine();bw.flush();}public void register(){}}四、反射
反射允许对成员变量成员方法构造方法的信息进行编程访问
4.1 获取class对象三种方法
1.Class.forName(“全类名”); 全类名包名类名 2.类名.class 3.对象.getClass()
package reflect1;public class r1 {public static void main(String[] args) throws ClassNotFoundException {//方式1//最常用Class class1 Class.forName(reflect1.Student);//方式2//一般当做参数传递Class class2 Student.class;//方式3//已经有了这个类的对象时才会使用Student snew Student();Class class3 s.getClass();}
}
4.2 反射获取
获取构造方法 setAccessibletrue临时取消权限校验暴力反射 getDeclaredConstructor里面的参数要与需要获取的方法里的形参一致如int.class getModifiers获取权限修饰符返回的整数 获取成员变量
package reflect;import java.lang.reflect.Field;public class f1 {public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {Class clazz Class.forName(reflect.Student);//获取单个成员变量Field name clazz.getDeclaredField(name);System.out.println(name);//获取权限修饰符int modifiers name.getModifiers();System.out.println(modifiers);//获取成员变量名字String n name.getName();System.out.println(n);//获取成员变量的数据类型Class? type name.getType();System.out.println(type);//获取成员变量记录的值Student snew Student(zhangsan,23,男);name.setAccessible(true);String value(String)name.get(s);System.out.println(value);//修改对象里面记录的值name.set(s,lisi);//将s对象里的名字修改成lisiSystem.out.println(s);}
}
获取成员方法
package reflect3;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;public class r3 {public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {Class clazz Class.forName(reflect3.Student);//获取所有方法对象(包含父类中的所有方法)//getDeclaredMethods可以获取私有的方法但不能获取到父类的方法Method[] methods clazz.getMethods();for (Method method : methods) {System.out.println(method);}//获取指定单一方法Method m clazz.getDeclaredMethod(eat, String.class);System.out.println(m);//获取修饰符int modifiers m.getModifiers();System.out.println(modifiers);//获取名字String name m.getName();System.out.println(name);//获取方法形参Parameter[] parameters m.getParameters();for (Parameter parameter : parameters) {System.out.println(parameter);}//获取方法抛出的异常Class[] exceptionTypes m.getExceptionTypes();for (Class exceptionType : exceptionTypes) {System.out.println(exceptionType);}//方法运行 invoke//参数一用obj对象调用该方法//参数二调用方法的传递的参数如果没有就不写//返回值方法的返回值如果没有就不写Student stunew Student();m.setAccessible(true);//参数一s:表示方法的调用者//参数二汉堡包表示在调用方法的时候传递的实际参数m.invoke(stu,汉堡);}
}
4.3 练习
练1对于任意一个对象都可以把对象所有的字段名和值保存到文件中去
package reflect4;import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.lang.reflect.Field;public class l1 {public static void main(String[] args) throws IllegalAccessException, IOException {Student snew Student(aaa,20,女,167.5,睡觉);Teacher tnew Teacher(波妞,10000);saveObject(s);}public static void saveObject(Object obj) throws IllegalAccessException, IOException {//获得字节码文件的对象Class clazz obj.getClass();//创建IO流保存数据BufferedWriter bwnew BufferedWriter(new FileWriter(day6\\a.txt));//2.获取所有成员变量Field[] fields clazz.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);//获取名字String name field.getName();//获取值Object value field.get(obj);//写出数据bw.write(namevalue);bw.newLine();}bw.close();}
}
练2 动态创建对象并调用方法
package reflect5;import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;public class test {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {//1读取配置文件的信息Properties propnew Properties();FileInputStream fisnew FileInputStream(day6\\prop.properties);prop.load(fis);//把数据读取到数组当中fis.close();//2.获取全类名和方法名String classname (String) prop.get(classname);String Methodname (String) prop.get(method);//利用反射创建对象并运行方法Class clazz Class.forName(classname);//获取构造方法创建对象Constructor con clazz.getDeclaredConstructor();Object o con.newInstance();//获取成员方法并运行Method Method clazz.getDeclaredMethod(Methodname);Method.setAccessible(true);Method.invoke(o);}
}
配置文件 classnamereflect5.Teacher methodteach
五、动态代理
无侵入式的给代码添加额外功能
对象想有什么方法被代理代理就一定要有对应的方法 需要被代理的方法放在接口中。对象和代理都要实现同一个接口
创建代理对象 ProxyUtil
package daili;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtil implements star{//给一个明星的对象创建一个代理//形参被代理的明星对象//返回值给明星创建的代理public static star createProxy(bigstar bigstar){star star (star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),//参数一用于指定用哪个类加载器去加载生成的代理类new Class[]{star.class},//参数二指定接口这些接口含有需要被代理的方法//生成的代理对象要干什么事情new InvocationHandler() {Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {/** 参数一代理的对象* 参数二要运行的方法* 参数三调用sing方法传递的实参* */if (sing.equals(method.getName())){System.out.println(准备话筒,收钱);}else if (dance.equals(method.getName())){System.out.println(准备场地收钱);}//开始唱歌或跳舞return method.invoke(bigstar,args);}});return star;}Overridepublic String sing(String name) {return null;}Overridepublic void dance() {}
}
Test
package daili;public class Test {public static void main(String[] args) {/** 需求* 外面的人想要明星唱歌* 1.获取代理的对象* 代理对象ProxyUtil.createProxy(明星对象);* 2.再调用代理的唱歌方法* 代理对象.唱歌的方法“只因你太美”* */bigstar bigstarnew bigstar(鸡哥);star proxy ProxyUtil.createProxy(bigstar);String result proxy.sing(只因);System.out.println(result);}
}
bigstar
package daili;public class bigstar implements star{private String name;public bigstar() {}public bigstar(String name) {this.name name;}//唱歌跳舞Overridepublic String sing(String name ){System.out.println(this.name正在唱name);return 谢谢;}Overridepublic void dance(){System.out.println(this.name正在跳舞);}/*** 获取* return name*/public String getName() {return name;}/*** 设置* param name*/public void setName(String name) {this.name name;}public String toString() {return bigstar{name name };}
}
star接口
package daili;public interface star {public abstract String sing(String name );public abstract void dance();
}