(一)、配置文件
好处:
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 t1=new MyThread();
MyThread t2=new MyThread();
t1.setName("线程1");
t2.setName("线程2");
//开启线程
t1.start();
t2.start();
//交替运行
}
}
MyThread:
package dxc;
public class MyThread extends Thread {
@Override
public 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 mr=new MyRun();
//创建线程对象
Thread t1=new Thread(mr);//将要执行的任务放进去
Thread t2=new Thread(mr);
//给线程设置名字
t1.setName("线程1");
t2.setName("线程2");
t1.start();
t2.start();//交替执行
}
}
MyRun:
package dxc;
public class MyRun implements Runnable{
@Override
public 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 mc=new MyCallable();
FutureTask<Integer> ft=new FutureTask<>(mc);
Thread t1=new Thread(ft);
t1.start();
Integer result = ft.get();
System.out.println(result);
}
}
MyCallable:
package dxc;
import java.util.concurrent.Callable;
public class MyCallable implements Callable<Integer> {
@Override
public Integer call() throws Exception {
int sum=0;
for (int i = 0; i < 100; i++) {
sum+=i;
}
return sum;
}
}
三种实现方式优缺点:
2.3 常见成员方法
注:
如果不给线程设置名字,线程有默认名字
格式:Thread-x(x从0开始)
Thread构造方法可以传递一个字符串,直接设置线程名字
JVM虚拟机启动后,会自动启动多条线程,
其中一条线程叫main线程,作用是调用main方法,并执行里面的代码
sleep():哪条线程执行到这个方法,这条线程就会在这里停留对应的时间
方法的参数就是停留的时间,毫秒。时间到了后,线程会自动醒来,继续执行下面其他代码
2.3.1 线程的优先级
Java中线程是抢占式调度(随机)
默认线程优先级是5
优先级:1-10(1最小)
优先级高,只是抢占cpu概率大,先执行完的概率大,但并非100%抢占
2.3.2 守护线程(备胎线程)
当其他非守护线程执行完毕之后,守护线程也会陆续执行完毕
2.3.3 礼让线程和插入线程
礼让线程:出让cpu的执行权
用在run方法中,尽可能让执行结果均匀
插入线程:
package dxc;
public class d5 {
public static void main(String[] args) throws InterruptedException {
MyThread t=new 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 ticket=0;
@Override
public void run() {
//1.循环
//2.同步代码块(同步方法)
//3.判断共享数据是否到了末尾
while (true){
if (method()) break;
}
}
private synchronized boolean method(){
if (ticket==100){
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 mr=new MyRunnable();
Thread t1=new Thread(mr);
Thread t2=new Thread(mr);
Thread t3=new 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 ticket=0;
static Lock lock=new ReentrantLock();
@Override
public void run() {
//1.循环
//2.同步代码块(同步方法)
//3.判断共享数据是否到了末尾
while (true){
lock.lock();
try {
if (ticket==100){
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{
@Override
public void run() {
/* * 1.循环 * 2.同步代码块 * 3.判断共享数据是否到了末尾,到了 * 4.没到,执行核心逻辑 * */
while (true){
synchronized (Desk.lock){
if (Desk.count==0){
break;
}else {
//判断桌子有没有食物
if(Desk.foodFlag==1){
//有就等待
try {
Desk.lock.wait();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}else {
System.out.println("厨师做了一碗面条");
//没有就制作,修改桌子状态
Desk.foodFlag=1;
//唤醒消费者开吃
Desk.lock.notifyAll();
}
}
}
}
}
}
食客代码:
package dxcday2;
public class Fooddie extends Thread{
/* * 1.循环 * 2.同步代码块 * 3.判断共享数据是否到了末尾,到了 * 4.没到,执行核心逻辑 * */
@Override
public void run() {
while (true){
synchronized (Desk.lock ){
if (Desk.count==0){
break;
}else {
//判断桌子上有没有面条
//没有就等待
if (Desk.foodFlag==0){
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.foodFlag=0;//修改桌子状态
}
}
}
}
}
}
凳子代码:
package dxcday2;
public class Desk {
/* * 控制生产者和消费者的执行 * */
//表示桌子上是否有面条,0是没有,1是有
//如果有多线程,直接定义这个值就行
public static int foodFlag=0;
//总个数(能吃几碗面)
public static int count=10;
//锁对象
public static Object lock=new Object();
}
测试代码:
package dxcday2;
public class dxc1 {
public static void main(String[] args) {
/* * 需求:完成生产者和消费者等着唤醒机制的代码 * 实现线程轮流交替执行过程 * */
//创建线程对象
Cook c=new Cook();
Fooddie fd=new 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{
ArrayBlockingQueue<String> queue;
public Cook(ArrayBlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public 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 {
ArrayBlockingQueue<String> queue;
public Fooddie(ArrayBlockingQueue<String> queue) {
this.queue = queue;
}
@Override
public 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) {
ArrayBlockingQueue<String> abq=new ArrayBlockingQueue<>(1);
//创建线程把阻塞队列传递过去
Cook c=new Cook(abq);
Fooddie f=new Fooddie(abq);
c.start();
f.start();
}
}
2.8 多线程的6种状态
实际上Java虚拟机中没有运行状态
2.9 综合练习
2.9.1 送礼物
线程1:
package dxczhlx;
public class p2 extends Thread{
@Override
public void run() {
while (true){
synchronized (lw.lock){
if (lw.i<=10){
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{
@Override
public void run() {
while (true){
synchronized (lw.lock){
if (lw.i<=10){
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 i=100;
public static Object lock=new Object();
}
test:
package dxczhlx;
public class test {
public static void main(String[] args) {
p1 p1=new p1();
p2 p2=new 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 money=100;
static int count=3;
//最小的中奖金额
static final double MIN=0.01;
@Override
public void run() {
synchronized (MyThread.class){
if (count==0){
//判断共享数据是否到了末尾,已经到了
System.out.println(getName()+"没有抢到红包");
}else {
//没到
//不能直接随机
//定义一个变量,表示中奖金额
double prize=0;
if (count==1){
//表示此时最后一个红包,无需随机,金额就是剩余金额
prize=money;
}else {
//表示第一次和第二次
Random r=new Random();
//100-(3-1)*0.01 第一个红包最多99.98元
double bounds=money-(count-1)*MIN;
prize=r.nextDouble(bounds);//jdk17的方法
if (prize<MIN){
prize=MIN;//如果随机金额小于最小金额,强制变成最小金额
}
}
//从money中去掉当前中奖金额
money=money-prize;
//红包个数-1
count--;
//打印本次红包信息
System.out.println(getName()+"抢到了"+prize+"元");
}
}
}
}
test:
package lx2;
public class test {
public static void main(String[] args) {
MyThread t1=new MyThread();
MyThread t2=new MyThread();
MyThread t3=new MyThread();
MyThread t4=new MyThread();
MyThread t5=new 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{
//定义共享数据
ArrayList<Integer> list;
public MyThread(ArrayList<Integer> list) {
this.list = list;
}
@Override
public 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) {
//创建奖池
ArrayList<Integer> list=new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
MyThread t1=new MyThread(list);
MyThread t2=new 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{
//定义共享数据
ArrayList<Integer> list;
//创建集合存储抽到的金额
//线程一
static ArrayList<Integer> list1=new ArrayList<>();
//线程二
static ArrayList<Integer> list2=new ArrayList<>();
public MyThread(ArrayList<Integer> list) {
this.list = list;
}
@Override
public void run() {
while (true){
synchronized (MyThread.class){
if (list.size()==0){
if ("抽奖箱1".equals(getName())){
int result1=0;
int max1=0;
for (Integer num : list1) {
result1+=num;
if (num>max1){
max1=num;
}
}
System.out.println("抽奖箱1"+list1+","+"总金额为"+result1+","+"最大值为"+max1);
}else {
int result2=0;
int max2=0;
for (Integer num : list2) {
result2+=num;
if (num>max2){
max2=num;
}
}
System.out.println("抽奖箱2"+list2+","+"总金额为"+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) {
//创建奖池
ArrayList<Integer> list=new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
MyThread t1=new MyThread(list);
MyThread t2=new 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 Callable<Integer> {
//定义共享数据
ArrayList<Integer> list;
public MyCallable(ArrayList<Integer> list) {
this.list = list;
}
@Override
public Integer call() throws Exception {
ArrayList<Integer> boxlist=new 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 {
ArrayList<Integer> list=new ArrayList<>();
Collections.addAll(list,10,5,20,50,100,200,500,800,2,80,300,700);
//创建多线程要运行的参数对象
MyCallable mc=new MyCallable(list);
//创建多线程运行结果管理者对象
FutureTask<Integer> ft1=new FutureTask<>(mc);
FutureTask<Integer> ft2=new FutureTask<>(mc);
//创建线程
Thread t1=new Thread(ft1);
Thread t2=new Thread(ft2);
t1.setName("抽奖箱1");
t2.setName("抽奖箱2");
t1.start();
t2.start();
Integer max1 = ft1.get();
Integer max2 = ft2.get();
if (max1>max2){
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 pool=new 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.开头就是私有地址
特殊ip:127.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");//可以传递主机名,也可以传递ip
System.out.println(address);
String name = address.getHostName();//获取主机名
System.out.println(name);
String ip = address.getHostAddress();//获取ip
System.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 ds=new DatagramSocket();
//打包数据
String str="你好";
byte[] bytes = str.getBytes();
InetAddress address=InetAddress.getByName("127.0.0.1");
int port=10086;
DatagramPacket dp=new 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 ds=new DatagramSocket(10086);
//接收数据包
byte[] b1=new byte[1024];
DatagramPacket dp=new 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 ds=new DatagramSocket();
Scanner sc=new Scanner(System.in);
System.out.println("请输入要说的话:");
while (true) {
String str = sc.nextLine();
if ("886".equals(str)){
break;
}
byte[] bytes = str.getBytes();
InetAddress address=InetAddress.getByName("127.0.0.1");
int port=10086;
//打包数据
DatagramPacket dp=new 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 ds=new DatagramSocket(10086);
byte[] bytes=new byte[1024];
DatagramPacket dp=new 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 socket=new 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 ss=new ServerSocket(10000);
//监听客户端的连接
Socket socket = ss.accept();
//从连接通道获取输入流
InputStream is = socket.getInputStream();
int b;
while ((b=is.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 ss=new ServerSocket(10000);
//监听客户端的连接
Socket socket = ss.accept();
//从连接通道获取输入流
InputStream is = socket.getInputStream();
InputStreamReader isr=new InputStreamReader(is);
int b;
while ((b=isr.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 socket=new Socket("127.0.0.1",8000);
//输出数据
Scanner sc=new 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 serverSocket=new ServerSocket(8000);
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
InputStreamReader isr=new InputStreamReader(is);
int b;
while ((b=isr.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 serverSocket=new ServerSocket(8001);
//等待连接
Socket socket = serverSocket.accept();
InputStream is = socket.getInputStream();
InputStreamReader isr=new InputStreamReader(is);
//读取数据
//read方法需要有一个结束标记才会,结束读取
//不然程序会一直停在这个循环当中,等待读取数据
int b;
while ((b=isr.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 socket=new Socket("127.0.0.1",8001);
//输出数据
String str="见到你很高兴";
OutputStream os = socket.getOutputStream();
os.write(str.getBytes());
//写出一个结束标记
socket.shutdownOutput();
//接收服务端回写的数据
InputStream is = socket.getInputStream();
InputStreamReader isr=new InputStreamReader(is);
int b;
while ((b=isr.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 socket=new Socket("127.0.0.1",9001);
//读取本地文件,写到服务端
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("day6\\clientdir\\331.jpg"));
BufferedOutputStream bos=new BufferedOutputStream(socket.getOutputStream());
byte[] bytes=new byte[1024];
int len;
while ((len=bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
//往服务器写出结束标记
socket.shutdownOutput();
//接收服务器回写数据
BufferedReader br=new 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 ss=new ServerSocket(9001);
//等待连接
Socket socket = ss.accept();
//读取数据并保存到本地文件
BufferedInputStream bis=new BufferedInputStream(socket.getInputStream());
String name= UUID.randomUUID().toString().replace("-","");//生成一个随机且唯一的id
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("day6\\serverdir\\"+name+".jpg"));
byte[] bytes=new byte[1024];
int len;
while ((len=bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
//回写数据
BufferedWriter bw=new 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 ss=new 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 socket=new Socket("127.0.0.1",9001);
//读取本地文件,写到服务端
BufferedInputStream bis=new BufferedInputStream(new FileInputStream("day6\\clientdir\\331.jpg"));
BufferedOutputStream bos=new BufferedOutputStream(socket.getOutputStream());
byte[] bytes=new byte[1024];
int len;
while ((len=bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
//往服务器写出结束标记
socket.shutdownOutput();
//接收服务器回写数据
BufferedReader br=new 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.socket=socket;
}
@Override
public void run() {
try {
//读取数据并保存到本地文件
BufferedInputStream bis=new BufferedInputStream(socket.getInputStream());
String name= UUID.randomUUID().toString().replace("-","");//生成一个随机且唯一的id
BufferedOutputStream bos=new BufferedOutputStream(new FileOutputStream("day6\\serverdir\\"+name+".jpg"));
byte[] bytes=new byte[1024];
int len;
while ((len=bis.read(bytes)) !=-1){
bos.write(bytes,0,len);
}
//回写数据
BufferedWriter bw=new 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 pool=new ThreadPoolExecutor(
3,//核心线程数
16,//线程池总大小
60,//空闲时间
TimeUnit.SECONDS,//单位
new ArrayBlockingQueue<>(2),//阻塞队列
Executors.defaultThreadFactory(),//线程工厂,线程池如何创建线程对象
new ThreadPoolExecutor.AbortPolicy()//阻塞队列
);
ServerSocket ss=new 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 bw=new 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 bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
//键盘录入
Scanner sc=new Scanner(System.in);
System.out.println("请输入用户名");
String username=sc.nextLine();
System.out.println("请输入密码");
String password=sc.nextLine();
//拼接
//格式: username=zhangsan&password=123
StringBuilder sb=new 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 br=new 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 sc=new 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.socket=socket;
}
@Override
public void run() {
while (true) {
try {
//接收服务器发过来的聊天记录
BufferedReader br=new 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 ArrayList<Socket> list=new ArrayList<>();
public static void main(String[] args) throws IOException {
ServerSocket ss=new ServerSocket(8003);
//1.获取本地正确的用户名和密码
Properties prop=new Properties();
FileInputStream fis=new 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.prop=prop;
this.socket=socket;
}
@Override
public void run() {
//接收用户发送的数据
try {
BufferedReader br=new 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 usernameInput=userInfoArr[0].split("=")[1];
String passwordInput=userInfoArr[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 bw=new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()));
bw.write(message);
bw.newLine();
bw.flush();
}
public void writeMessagetoClient(Socket s, String message) throws IOException {
BufferedWriter bw=new 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 s=new Student();
Class class3 = s.getClass();
}
}
4.2 反射获取
获取构造方法:
setAccessible(true):临时取消权限校验(暴力反射)
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 s=new Student("zhangsan",23,"男");
name.setAccessible(true);
String value=(String)name.get(s);
System.out.println(value);
//修改对象里面记录的值
name.set(s,"lisi");//将s对象里的名字修改成lisi
System.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 stu=new 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 s=new Student("aaa",20,"女",167.5,"睡觉");
Teacher t=new Teacher("波妞",10000);
saveObject(s);
}
public static void saveObject(Object obj) throws IllegalAccessException, IOException {
//获得字节码文件的对象
Class clazz = obj.getClass();
//创建IO流,保存数据
BufferedWriter bw=new 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(name+"="+value);
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 prop=new Properties();
FileInputStream fis=new 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);
}
}
配置文件:
classname=reflect5.Teacher
method=teach
(五)、动态代理
无侵入式的给代码添加额外功能
对象想有什么方法被代理,代理就一定要有对应的方法
需要被代理的方法放在接口中。对象和代理都要实现同一个接口
创建代理对象:
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() {
@Override
public 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;
}
@Override
public String sing(String name) {
return null;
}
@Override
public void dance() {
}
}
Test:
package daili;
public class Test {
public static void main(String[] args) {
/* * 需求: * 外面的人想要明星唱歌 * 1.获取代理的对象 * 代理对象=ProxyUtil.createProxy(明星对象); * 2.再调用代理的唱歌方法 * 代理对象.唱歌的方法(“只因你太美”); * */
bigstar bigstar=new 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;
}
//唱歌跳舞
@Override
public String sing(String name ){
System.out.println(this.name+"正在唱"+name);
return "谢谢";
}
@Override
public 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();
}
文章评论