Java基础(三)- 多线程、网络通信、单元测试、反射、注解、动态代理

多线程基础

线程:一个程序内部的一条执行流程,只有一条执行流程就是单线程

java.lang.Thread代表线程

主线程退出,子线程存在,进程不会退出

可以使用jconsole查看

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

创建线程

有多个方法可以创建线程

  • 继承Thread类

    • 优点:编码简单
    • 缺点:无法继承其他类,不利于功能的扩展
  • 实现Runnable接口

    • 优点:任务类只是实现了接口,可以继续继承其他类、实现其他接口,扩展性强
    • 缺点:需要多创建一个Runnable对象
  • 实现Callable接口和FutureTask类

    • 优点:可以返回线程执行结束之后的结果
    • 缺点:编码复杂

    执行为什么是start()?

    使用run不是多线程, 相当于直接调用方法 还是单线程

    start->start0(本地方法 JVM调用 C/C++实现的)
    

方法一

public class Demo1 {public static void main(String[] args) throws Exception {//main是主线程执行的//新建了一个t线程Thread t = new primeThread();//启动线程 start自动调用run方法 必须要调用start方法//如果是t.run() 相当于直接调用方法 还是单线程t.start();for (int i = 0; i < 5; i++) {System.out.println("主线程");Thread.sleep(500);}}
}class primeThread extends Thread{public primeThread(){}@Overridepublic void run() {//描述线程的执行的任务for (int i = 0; i < 5; i++) {System.out.println("子线程");try {Thread.sleep(500);} catch (Exception e) {e.printStackTrace();}}}
}

方法二

public class Demo2 {public static void main(String[] args) throws Exception {//runnable只是一个任务对象Runnable target = new prime1Thread();//需要线程对象接受任务对象 开辟新的线程new Thread(target).start();for (int i = 0; i < 5; i++) {System.out.println("主线程");Thread.sleep(500);}}
}class prime1Thread implements Runnable{@Overridepublic void run() {for (int i = 0; i < 5; i++) {System.out.println("子线程");try {Thread.sleep(500);} catch (Exception e) {e.printStackTrace();}}}
}//可以使用匿名内部类
public class Demo2 {public static void main(String[] args) throws Exception {//需要线程对象进行调用任务对象开辟新的线程new Thread(()-> {for (int i = 0; i < 5; i++) {System.out.println("子线程");try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}	}}).start();for (int i = 0; i < 5; i++) {System.out.println("主线程");Thread.sleep(500);}}
}

方法三

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;public class Demo3 {public static void main(String[] args) throws ExecutionException, InterruptedException {//创建一个Callable对象Callable<String> myCallable = new MyCallable(100);// 把Callable的对象封装成一个FutureTask对象(任务对象)// 未来任务对象的作用?// 1、是一个任务对象,实现下Runnable对象// 2、可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕的结果//也可以使用匿名内部类FutureTask<String> stringFutureTask = new FutureTask<>(myCallable);new Thread(stringFutureTask).start();//获取结果会阻塞线程System.out.println(stringFutureTask.get());}
}//泛型
class MyCallable implements Callable<String>{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 sum+"";}
}

线程方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • setPriority()更改线程的优先级
  • getPriority()获取线程的优先级
  • interrupt中断线程,并不是真正的结束线程 所以一般用于中断正在休眠的线程
  • yield线程的礼让,不一定礼让成功(和join相反,线程的插队)
public class Demo4 {public static void main(String[] args) throws InterruptedException {Thread t1 = new Thread1("1号线程");
//        t1.setName("1号线程");//启动之前取名字t1.start();t1.join();
//        System.out.println(t1.getName());Thread t2 = new Thread1("2号线程");
//        t2.setName("2号线程");//启动之前取名字t2.start();t2.join();//t2线程执行完成之后才能继续往下执行
//        System.out.println(t2.getName());Thread t3 = new Thread1("3号线程");t3.start();t3.join();Thread m = Thread.currentThread();m.setName("最牛逼的名字");
//        System.out.println(m.getName());for (int i = 0; i < 5; i++) {System.out.println(m.getName()+"输出"+(i+1));}}
}class Thread1 extends Thread{public Thread1(String name) {super(name);}@Overridepublic void run() {Thread t= Thread.currentThread();for (int i = 0; i < 3; i++) {System.out.println("子线程"+t.getName()+"输出:"+(i+1));}}
}

线程终止

  • 当线程执行完成时,自动退出
  • 使用变量来控制run方法退出的方式停止线程

守护线程

当所有的用户线程都退出时,守护线程自动退出

垃圾回收机制

public class Test {public static void main(String[] args) {//子线程设置为守护线程myDaemonThread myDaemonThread = new myDaemonThread();myDaemonThread.setDaemon(true);myDaemonThread.start();for (int i = 0; i < 10; i++) {System.out.println(Thread.currentThread().getName() + " 执行");try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}/*
守护线程:
当用户线程退出后 子线程也自动退出*/
class myDaemonThread extends Thread {@Overridepublic void run() {while (true) {System.out.println(Thread.currentThread().getName() + " 正在执行");try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}}}
}

线程安全

概念

多个线程同时操作同一个共享资源的时候可能出现业务安全问题

模拟线程安全问题

package Thread_;public class Demo5 {public static void main(String[] args) {Thread xiaoHong = new DrawThread("小红");Thread xiaoMing = new DrawThread("小明");xiaoMing.start();xiaoHong.start();}
}
class Account{private static double moneys = 100000;private Account(){}public static double getMoneys() {return moneys;}public static void setMoneys(double moneys) {Account.moneys = moneys;}public static boolean drawMoneys(double moneys){String name = Thread.currentThread().getName();if (moneys>Account.getMoneys()){System.out.println(name+"来取钱,钱不够");return false;}Account.moneys-=moneys;System.out.println(name+"来取钱,取钱成功,剩余"+Account.moneys);return true;}
}class DrawThread extends Thread{public DrawThread(String name) {super(name);}@Overridepublic void run() {Account.drawMoneys(100000.0);}
}

线程同步

认识线程同步

多个线程实现先后依次访问共享资源

**加锁:**每次只允许一个线程加锁,加锁之后才能访问,访问完毕之后自动解锁,然后其他线程才能再加锁继续

方法一:同步代码块

把访问共享资源的核心代码给上锁,保证线程安全

synchronized(同步锁){访问共享资源的核心代码
}

对于当前同时执行的线程来说,同步锁必须是同一把(同一对象

锁对象的选择:

  • 实例对象:使用this
  • 静态对象:使用类型.class
public class Demo5 {public static void main(String[] args) throws InterruptedException {Account acc1 = new Account(100000);Thread xiaoHong = new DrawThread("小红",acc1);Thread xiaoMing = new DrawThread("小明",acc1);xiaoMing.start();xiaoHong.start();Account acc2 = new Account(100000);Thread daGang = new DrawThread("大纲",acc2);Thread daLi = new DrawThread("大力",acc2);daGang.start();daLi.start();}
}class Account {private double moneys;public Account() {}public Account(double moneys) {this.moneys = moneys;}public double getMoneys() {return moneys;}public void setMoneys(double moneys) {this.moneys = moneys;}public void drawMoneys(double moneys) throws InterruptedException {String name = Thread.currentThread().getName();/** 两个人同时竞争lock这个对象(这把锁),只有一个人能够得到* 上锁之后另外一个人要等待开锁** 但是这个lock对于所有的对象是一个锁* 一个对象上锁的时候 和该对象无关的对象也无法进入核心代码* 非static建议使用 this* static建议使用 ClassName.class* */synchronized (this) {
//            Thread.sleep(5000); 测试if (moneys > this.getMoneys()) {System.out.println(name + "来取钱,钱不够");} else {this.moneys -= moneys;System.out.println(name + "来取钱,取钱" + moneys + "成功,剩余" + this.moneys);}}}
}class DrawThread extends Thread {private Account acc;public DrawThread(String name,Account acc) {super(name);this.acc = acc;}@Overridepublic void run() {try {acc.drawMoneys(100000);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

方法二:同步方法

访问共享资源的核心方法给上锁

修饰符 synchronized 返回值类型 方法名称(形参列表){操作共享资源的代码
}
public class Demo5 {public static void main(String[] args) throws InterruptedException {Account acc1 = new Account(100000);Thread xiaoHong = new DrawThread("小红", acc1);Thread xiaoMing = new DrawThread("小明", acc1);xiaoMing.start();xiaoHong.start();Account acc2 = new Account(100000);Thread daGang = new DrawThread("大纲", acc2);Thread daLi = new DrawThread("大力", acc2);daGang.start();daLi.start();}
}class Account {private double moneys;public Account() {}public Account(double moneys) {this.moneys = moneys;}public double getMoneys() {return moneys;}public void setMoneys(double moneys) {this.moneys = moneys;}/*有一个隐含的锁 实例方法是 this  静态方法是 类型.class*/public synchronized void drawMoneys(double moneys) throws InterruptedException {String name = Thread.currentThread().getName();if (moneys > this.getMoneys()) {System.out.println(name + "来取钱,钱不够");} else {this.moneys -= moneys;System.out.println(name + "来取钱,取钱" + moneys + "成功,剩余" + this.moneys);}}
}class DrawThread extends Thread {private Account acc;public DrawThread(String name, Account acc) {super(name);this.acc = acc;}@Overridepublic void run() {try {acc.drawMoneys(100000);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

方法三:Lock锁

Lock锁是IDK5开始提供的一个新的锁定操作,通过它可以创建出锁对象进行加锁和解锁,更灵活、更方便、更强大

Lock是接口,不能直接实例化,可以采用它的实现类**ReentrantLock**来构建Lock锁对象。

package Thread_;import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;public class Demo5 {public static void main(String[] args) throws InterruptedException {Account acc1 = new Account(100000);Thread xiaoHong = new DrawThread("小红", acc1);Thread xiaoMing = new DrawThread("小明", acc1);xiaoMing.start();xiaoHong.start();Account acc2 = new Account(100000);Thread daGang = new DrawThread("大纲", acc2);Thread daLi = new DrawThread("大力", acc2);daGang.start();daLi.start();}
}class Account {/*创建了一个锁对象 每一个账户都有一个自己的锁对象不允许二次赋值*/private final Lock lk = new ReentrantLock();private double moneys;public Account() {}public Account(double moneys) {this.moneys = moneys;}public double getMoneys() {return moneys;}public void setMoneys(double moneys) {this.moneys = moneys;}public void drawMoneys(double moneys) throws InterruptedException {String name = Thread.currentThread().getName();try {lk.lock();if (moneys > this.getMoneys()) {System.out.println(name + "来取钱,钱不够");} else {this.moneys -= moneys;System.out.println(name + "来取钱,取钱" + moneys + "成功,剩余" + this.moneys);}} catch (Exception e) {throw new RuntimeException(e);} finally {lk.unlock();//无论try中代码是否有错误 都会解锁}}
}class DrawThread extends Thread {private Account acc;public DrawThread(String name, Account acc) {super(name);this.acc = acc;}@Overridepublic void run() {try {acc.drawMoneys(100000);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

释放锁的时机

  • 当前线程的同步方法、同步代码块执行结束
  • 当前线程在同步方法、同步代码块中遇到breakreturn
  • 当前线程在同步方法、同步代码块中出现了未处理的Error或者Exception,导致异常结束
  • 当前线程在同步方法、同步代码块中执行了线程对象的wait()方法,当前线程暂停 释放锁,等待唤醒

不释放锁

  • Thread.sleep()Thread.yeild不会释放锁
  • suspend()挂起方法,也不会释放锁
    • suspendresume控制线程,不推荐使用

线程死锁

多个线程都占用了对方的锁资源,但是不肯相让,导致了死锁

public class Demo {public static void main(String[] args) {new Thread(new MyDeadThread(false)).start();new Thread(new MyDeadThread(true)).start();}
}
class MyDeadThread implements Runnable{private boolean flag;private static Object o1 = new Object();private static Object o2 = new Object();public MyDeadThread() {}public MyDeadThread(boolean flag) {this.flag = flag;}@Overridepublic void run() {while (true){/*flag=true 占用o1锁 抢夺o2锁flag=false 占用o2锁 抢夺o1锁如果两个线程 一个占用o1 一个占用o2 那么就造成死锁*/if (flag){synchronized (o1){System.out.println("o1");synchronized (o2){System.out.println("o2");}}}else {synchronized (o2){System.out.println("o2");synchronized (o1){System.out.println("o1");}}}}}
}

线程通信

当多个线程共同操作共享资源的时候,线程间通过某种方式相互告知自己的状态,相互协调,避免无效的资源争夺

生产者消费者模型

  • 生产者线程负责生产数据
  • 消费者线程负责消费生产者生产的数据
  • 生产者生产完数据应该等待,通知消费者消费;消费者消费完数据也应该等待,通知生产者生产

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

public class ThreadTest {public static void main(String[] args) {Desk desk = new Desk();//3个生产者new Thread(()-> {while (true){desk.put();}},"厨师1").start();new Thread(()-> {while (true){desk.put();}},"厨师2").start();new Thread(()-> {while (true){desk.put();}},"厨师3").start();//2个消费者new Thread(()-> {while (true){desk.get();}},"吃货1").start();new Thread(()-> {while (true){desk.get();}},"吃货2").start();}
}import java.util.ArrayList;
import java.util.List;public class Desk {private final List<String>list = new ArrayList<>();//这个五个人是同一把锁public synchronized void put(){try {String name = Thread.currentThread().getName();if (list.isEmpty()){list.add(name+"做的肉包子");System.out.println(name+"做的肉包子");Thread.sleep(500);}//等待自己 唤醒别人 先唤醒后等待//只能线程对象调用this.notify();this.wait();} catch (Exception e) {throw new RuntimeException(e);}}public synchronized void get(){try {String name = Thread.currentThread().getName();if (!list.isEmpty()){System.out.println(name + "吃了"+list.remove(0));Thread.sleep(500);}//等待自己 唤醒别人 先唤醒后等待//只能线程对象调用this.notify();this.wait();} catch (Exception e) {throw new RuntimeException(e);}}
}

线程池

概念

可以复用线程的技术

**不使用线程池:**用户每发起一个请求,后台就需要创建一个新线程来处理,下次新任务来了肯定又要创建新线程处理的,而创建新线程的开销是很大的,并且请求过多时,肯定会产生大量的线程出来,这样会严重影响系统的性能。

使用ExecutorService创建线程池

使用ExecutorService的实现类ThreadPoolExecutor创建一个线程池对象(JDK5.0之后提供代表线程池的接口:ExecutorService

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  1. corePoolSize:指定线程池的核心线程的数量
  2. maximumPoolSize:指定线程池的最大线程的数量
  3. keepAliceTime:指定临时线程的存活时间
  4. unit:指定临时线程存货时间的单位(秒、分、时、天)
  5. workQueue:指定线程池的任务队列
  6. threadFactory:指定线程池的线程工厂
  7. handler:指定线程池的任务拒绝策略(线程都在忙,任务队列也满了的时候,新任务来了该怎么处理)
        /*ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)*/ExecutorService poolExecutor = new ThreadPoolExecutor(3, 5, 8, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());

什么时候创建临时对象?

新任务提交时发现核心线程都在忙任务队列也满了,并且还可以创建临时线程,才会创建

什么时候会开始拒绝新任务?

核心线程和临时线程都在忙,任务队列也满了

新任务拒绝策略

在这里插入图片描述

处理Runnable任务

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class _ThreadPool {public static void main(String[] args) {/*ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)*/ExecutorService poolExecutor = new ThreadPoolExecutor(3, 5,8, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4),Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());MyRunnable myRunnable1 = new MyRunnable();MyRunnable myRunnable2 = new MyRunnable();MyRunnable myRunnable3 = new MyRunnable();//三个核心线程在忙poolExecutor.execute(myRunnable1);poolExecutor.execute(myRunnable2);poolExecutor.execute(myRunnable3);//任务队列占满poolExecutor.execute(myRunnable3);poolExecutor.execute(myRunnable3);poolExecutor.execute(myRunnable3);poolExecutor.execute(myRunnable3);//可以创建两个临时线程poolExecutor.execute(myRunnable3);poolExecutor.execute(myRunnable3);//拒绝新任务poolExecutor.execute(myRunnable3);//        poolExecutor.shutdown();//等任务执行完后关闭线程池
//        poolExecutor.shutdownNow();//立刻关闭线程池}
}class MyRunnable implements Runnable {@Overridepublic void run() {String name = Thread.currentThread().getName();System.out.println(name + "666");try {Thread.sleep(100000);} catch (InterruptedException e) {throw new RuntimeException(e);}}
}

处理Callable任务

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;public class _ThreadPool {public static void main(String[] args) throws  Exception {/*ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)*/ExecutorService poolExecutor = new ThreadPoolExecutor(3, 5,8, TimeUnit.SECONDS, new ArrayBlockingQueue<>(4),Executors.defaultThreadFactory(), new ThreadPoolExecutor.CallerRunsPolicy());Future<String>f1 =  poolExecutor.submit(new MyCallable(100));Future<String>f2 =  poolExecutor.submit(new MyCallable(200));Future<String>f3 =  poolExecutor.submit(new MyCallable(300));Future<String>f4 =  poolExecutor.submit(new MyCallable(400));System.out.println(f1.get());System.out.println(f2.get());System.out.println(f3.get());System.out.println(f4.get());}
}class MyCallable implements Callable<String> {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()+"计算出1-"+n+"的和为"+sum;}
}

使用Executors创建线程池(大型并发系统不建议)

(线程池的工具类)调用方法返回不同特点的线程池对象

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

  • FixedThreadPool、SingleThreadExecutor允许请求队列长度为Integer.MAX_VALUE
  • CachedThreadPool允许创建线程数量为Integer.MAX_VALUE

这些方法的底层,都是通过线程池的实现类ThreadPoolExecutor创建的线程池对象

ExecutorService pool = Executors.newFixedThreadPool(3);

核心线程配置数量

  • 计算密集型的任务:CPU核数+1
  • IO密集型的任务:CPU核数*2

并发和并行

并发的含义

进程中的线程是由CPU负责调度执行的,但是CPU能同时处理线程的数量是有限的。

为了保证全部线程都能往前执行,CPU会轮询为系统的每个线程服务,由于CPU切换速度很快,给我们的感觉就是这些线程在同时执行,这就是并发

并行的含义

同一时刻上,同时有多个线程在被CPU调度执行

线程生命周期

也就是线程从生到死的过程,经历的各种状态以及状态转换

理解线程这些状态有利于提高并发编程的理解能力

在这里插入图片描述

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

扩展:悲观锁和乐观锁

悲观锁:一开始就加锁,没有安全感,每次只能一个线程进入,访问完毕后再解锁。线程安全 性能较差

乐观锁:一开始不上锁,认为没问题,等出现线程安全的时候才开始控制。线程安全 性能较好

//乐观锁
import java.util.concurrent.atomic.AtomicInteger;public class Demo7 {//一个静态变量,100个线程,每个线程对其加100次public static void main(String[] args) {Runnable mRunnable = new MRunnable2();for (int i = 0; i < 100; i++) {//100个线程执行相同的任务new Thread(mRunnable).start();}}
}class MRunnable2 implements Runnable {
//    private int count;//整数修改的乐观锁:原子类,private AtomicInteger count = new AtomicInteger();@Overridepublic void run() {for (int i = 0; i < 100; i++) {System.out.println("count====>" + (count.incrementAndGet()));}}
}

多线程练习

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;public class Test1 {public static void main(String[] args) throws InterruptedException {/*** 目标:有100份礼品,小红,小明两人同时发送,当剩下的礼品小于10份的时候则不再送出,* 利用多线程模拟该过程并将线程的名称打印出来。并最后在控制台分别打印小红,小明各自送出多少分礼物。*/ArrayList<String> gifts = new ArrayList<>();String[] names = {"口红", "包包", "腰带", "剃须刀", "香水", "衣服"};Random r = new Random();for (int i = 0; i < 100; i++) {gifts.add(names[r.nextInt(names.length)] + (i + 1));}sendThread xm = new sendThread(gifts, "小明");sendThread xh = new sendThread(gifts, "小红");xm.start();xh.start();xm.join();xh.join();System.out.println("小明送出去" + xm.getCount());System.out.println("小红送出去" + xh.getCount());}
}class sendThread extends Thread {private ArrayList<String> gifts;private int count;public int getCount() {return count;}public void setCount(int count) {this.count = count;}public sendThread() {}public sendThread(ArrayList<String> gifts, String name) {super(name);this.gifts = gifts;}@Overridepublic void run() {Random r = new Random();String name = Thread.currentThread().getName();while (true) {synchronized (gifts) {int length = gifts.size();if (length < 10)break;String s = gifts.remove(r.nextInt(length));System.out.println(name + "送出礼物" + s);++count;}}}
}

网络编程基础

可以让设备中的程序与网络上其他设备中的程序进行数据交互(实现网络通信的)

java.net.*的包下

网络通信三要素

  • IP地址:设备在网络中的地址,是唯一的标识
  • 端口号:应用程序在设备中唯一的标识
  • 协议:连接和数据在网络中传输的规则

java获取Ip地址InetAddress

![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/fe8b9baf7b3b42619311c8ac4ff54acf.png)
import java.net.InetAddress;
import java.net.UnknownHostException;public class GetIP {public static void main(String[] args) throws Exception {//本机InetAddress ip = InetAddress.getLocalHost();System.out.println(ip.getHostName());System.out.println(ip.getHostAddress());//指定InetAddress ipBaiDu = InetAddress.getByName("www.baidu.com");System.out.println(ipBaiDu.getHostName());System.out.println(ipBaiDu.getHostAddress());//本机ping 百度System.out.println(ipBaiDu.isReachable(6000));}
}

UDP通信

java.net.DatagramSocket实现UDP通信

在这里插入图片描述

一发一收

Client

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;public class Client {public static void main(String[] args) throws Exception {//创建客户端 以及客户端端口DatagramSocket socket  = new DatagramSocket(6666);String data = "我是客户端,哈哈哈";byte[]bytes = data.getBytes();//创建数据包DatagramPacket packet = new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),5555);//发送数据socket.send(packet);System.out.println("客户端数据发送完毕");//释放资源socket.close();}
}

Serve

import java.net.DatagramPacket;
import java.net.DatagramSocket;public class Serve {public static void main(String[] args) throws Exception {System.out.println("===服务端启动===");//创建服务端 注册服务端端口DatagramSocket socket = new DatagramSocket(5555);byte[] buffer = new byte[1024*64];//64KB  UDP一个数据包最大为64KB//创建一个用来接收数据的数据包对象DatagramPacket packet = new DatagramPacket(buffer, buffer.length);//接受数据socket.receive(packet);//从字节数组中获取接受的数据int len = packet.getLength();String data = new String(buffer,0,len);System.out.println(data);//获取客户端的IP 端口System.out.println(packet.getAddress().getHostAddress());System.out.println(packet.getPort());//释放资源socket.close();}
}
多发多收

可以多个用户同时发送

Client

import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.util.Scanner;public class Client {public static void main(String[] args) throws Exception {//创建客户端 以及客户端端口(默认随机分配)DatagramSocket socket  = new DatagramSocket();Scanner sc = new Scanner(System.in);while (true) {System.out.println("请输入消息://exit是退出");String msg = sc.nextLine();if (msg.equals("exit")){System.out.println("欢迎下次光临");break;}byte[]bytes = msg.getBytes();//创建数据包DatagramPacket packet = new DatagramPacket(bytes,bytes.length, InetAddress.getLocalHost(),5555);//发送数据socket.send(packet);}socket.close();}
}

Serve

import java.net.DatagramPacket;
import java.net.DatagramSocket;public class Serve {public static void main(String[] args) throws Exception {System.out.println("===服务端启动===");//创建服务端 注册服务端端口DatagramSocket socket = new DatagramSocket(5555);byte[] buffer = new byte[1024*64];//64KB  UDP一个数据包最大为64KB//创建一个用来接收数据的数据包对象DatagramPacket packet = new DatagramPacket(buffer, buffer.length);while (true) {//接受数据socket.receive(packet);//从字节数组中获取接受的数据int len = packet.getLength();String data = new String(buffer,0,len);System.out.println(data);//获取客户端的IP 端口System.out.println(packet.getAddress().getHostAddress());System.out.println(packet.getPort());System.out.println("----------------");}}
}

TCP通信

客户端:java.net.Socket

在这里插入图片描述

一发一收

client

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;public class ClientTCP {public static void main(String[] args) throws Exception {//创建socket对象Socket socket = new Socket(InetAddress.getLocalHost(), 5555);//从socket通信管道中得到一个字节输出流OutputStream os = socket.getOutputStream();//封装成数据输出流DataOutputStream dataOutputStream = new DataOutputStream(os);//写入数据dataOutputStream.writeUTF("你好呀!");//关闭数据流dataOutputStream.close();//关闭socketsocket.close();}
}

serve

import java.io.DataInputStream;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class ServeTCP {public static void main(String[] args) throws Exception{System.out.println("--服务端启动--");//创建服务端对象 绑定端口ServerSocket serverSocket = new ServerSocket(5555);//等待连接Socket socket = serverSocket.accept();//接受数据InputStream ds = socket.getInputStream();//封装DataInputStream dataInputStream = new DataInputStream(ds);//接受数据String s = dataInputStream.readUTF();System.out.println(s);//客户端ip地址System.out.println(socket.getRemoteSocketAddress());dataInputStream.close();socket.close();}
}
多发多收

client

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Objects;
import java.util.Scanner;public class ClientTCP {public static void main(String[] args) throws Exception {//创建socket对象Socket socket = new Socket(InetAddress.getLocalHost(), 5555);//从socket通信管道中得到一个字节输出流OutputStream os = socket.getOutputStream();//封装成数据输出流DataOutputStream dataOutputStream = new DataOutputStream(os);Scanner sc = new Scanner(System.in);while (true) {//写入数据System.out.println("请说:");String s = sc.nextLine();if (Objects.equals(s, "exit")){System.out.println("欢迎下次光临");break;  }dataOutputStream.writeUTF(s);dataOutputStream.flush();}//关闭数据流dataOutputStream.close();//关闭socketsocket.close();}
}

serve

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;public class ServeTCP {public static void main(String[] args) throws Exception{System.out.println("--服务端启动--");//创建服务端对象 绑定端口ServerSocket serverSocket = new ServerSocket(5555);//等待连接Socket socket = serverSocket.accept();//接受数据InputStream ds = socket.getInputStream();//封装DataInputStream dataInputStream = new DataInputStream(ds);//接受数据while (true) {try {String s = dataInputStream.readUTF();System.out.println(s);//客户端ip地址
//                System.out.println(socket.getRemoteSocketAddress());} catch (IOException e) {System.out.println(socket.getRemoteSocketAddress()+"离线");break;}}dataInputStream.close();socket.close();}
}
多个客户端连接一个服务端

服务端:

  • 主线程负责接受客户端连接
  • 子线程负责具体每一个客户端

client

import java.io.DataOutputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Scanner;public class ClientTCP {public static void main(String[] args) throws Exception {Socket socket = new Socket("127.0.0.1", 8888);OutputStream os = socket.getOutputStream();DataOutputStream dos = new DataOutputStream(os);Scanner sc = new Scanner(System.in);while (true){String s = sc.nextLine();if (s.equals("exit")){System.out.println("欢迎下次光临");dos.close();socket.close();break;}dos.writeUTF(s);dos.flush();}}
}

serve

import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;public class ServeTCP {public static void main(String[] args) throws Exception {System.out.println("服务端开启...");ServerSocket serverSocket = new ServerSocket(8888);while (true) {Socket socket = serverSocket.accept();System.out.println(socket.getRemoteSocketAddress()+"上线了");new Thread(new SocketThread(socket)).start();}}
}class SocketThread implements Runnable{private Socket socket;public SocketThread(Socket socket){this.socket = socket;}@Overridepublic void run() {SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();try {InputStream is = socket.getInputStream();DataInputStream dis = new DataInputStream(is);while (true) {try {String s = dis.readUTF();System.out.println(remoteSocketAddress+"发送:"+s);} catch (Exception e) {System.out.println(remoteSocketAddress+"下线了");socket.close();dis.close();break;}}} catch (Exception e) {e.printStackTrace();}}
}

案例:群聊

client

import java.io.DataInputStream;
import java.io.DataOutputStream;import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Scanner;public class ClientChat {public static void main(String[] args) {try {Socket socket = new Socket("127.0.0.1", 8888);new ClientThread(socket).start();OutputStream os = socket.getOutputStream();DataOutputStream dos = new DataOutputStream(os);Scanner sc = new Scanner(System.in);while (true) {String s = sc.nextLine();if (s.equals("exit")) {System.out.println("欢迎下次光临");socket.close();dos.close();break;}dos.writeUTF(s);dos.flush();}} catch (Exception e) {e.printStackTrace();}}
}class ClientThread extends Thread {private Socket socket;public ClientThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {InputStream is = socket.getInputStream();DataInputStream dis = new DataInputStream(is);while (true) {try {String msg = dis.readUTF();System.out.println(msg);} catch (Exception e) {dis.close();socket.close();break;}}} catch (Exception e) {e.printStackTrace();}}
}

serve

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;public class ServeChat {public static final List<Socket> onlineUsers = new ArrayList<>();public static void main(String[] args) throws Exception{System.out.println("==服务器启动==");ServerSocket serverSocket = new ServerSocket(8888);while (true) {Socket socket = serverSocket.accept();onlineUsers.add(socket);new ServeReaderThread(socket).start();}}
}class ServeReaderThread extends Thread {private Socket socket;public ServeReaderThread(Socket socket) {this.socket = socket;}@Overridepublic void run() {try {InputStream is = socket.getInputStream();DataInputStream dis = new DataInputStream(is);while (true) {try {String msg = dis.readUTF();System.out.println(msg);sendAllOnlineUsers(socket,msg);} catch (Exception e) {ServeChat.onlineUsers.remove(socket);socket.close();dis.close();System.out.println(socket.getRemoteSocketAddress() + "下线");break;}}} catch (Exception e) {e.printStackTrace();}}private void sendAllOnlineUsers(Socket socket,String msg) throws Exception {for (Socket onlineUser : ServeChat.onlineUsers) {SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();if (Objects.equals(onlineUser.getRemoteSocketAddress(),remoteSocketAddress)){continue;}OutputStream os = onlineUser.getOutputStream();DataOutputStream dos = new DataOutputStream(os);dos.writeUTF(remoteSocketAddress+"说:"+msg);dos.flush();}}
}

案例:简易BS架构

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.ServerSocket;
import java.net.Socket;public class Serve {public static void main(String[] args) throws Exception {ServerSocket serverSocket = new ServerSocket(8080);while (true){Socket socket = serverSocket.accept();System.out.println(socket.getRemoteSocketAddress()+"上线了");new CThread(socket).start();}}
}class CThread extends Thread{private Socket socket;public CThread(Socket socket){this.socket=socket;}@Overridepublic void run() {try {OutputStream os = socket.getOutputStream();PrintStream ps = new PrintStream(os);/*服务器必须给浏览器相应Http协议规定的格式*/ps.println("HTTP/1.1 200 OK");ps.println("Content-Type:text/html;charset=UTF-8");ps.println();//必须换行ps.println("<div style='color:red;font-size:120px;'>java666</div>");ps.close();socket.close();} catch (Exception e) {e.printStackTrace();}}
}

改进:线程池

import java.io.DataOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
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 Serve {public static void main(String[] args) throws Exception {ServerSocket serverSocket = new ServerSocket(8080);ThreadPoolExecutor pool = new ThreadPoolExecutor(16 * 2, 16 * 2, 0, TimeUnit.SECONDS, new ArrayBlockingQueue<>(8), Executors.defaultThreadFactory(), new ThreadPoolExecutor.AbortPolicy());while (true){Socket socket = serverSocket.accept();System.out.println(socket.getRemoteSocketAddress()+"上线了");pool.execute(new CThread(socket));}}
}class CThread implements Runnable{private Socket socket;public CThread(Socket socket){this.socket=socket;}@Overridepublic void run() {try {OutputStream os = socket.getOutputStream();PrintStream ps = new PrintStream(os);/*服务器必须给浏览器相应Http协议规定的格式*/ps.println("HTTP/1.1 200 OK");ps.println("Content-Type:text/html;charset=UTF-8");ps.println();//必须换行ps.println("<div style='color:red;font-size:120px;'>java666</div>");ps.close();socket.close();} catch (Exception e) {e.printStackTrace();}}
}

案例:多用户即时通信系统

需求分析

  • 用户登录
  • 拉取在线用户
  • 无异常退出
  • 私聊
  • 群聊
  • 发文件
  • 服务器推送新闻

java高级

单元测试

就是针对最小的功能单元(方法),编写测试代码对其进行正确性测试

junit单元测试框架

  • 可以灵活的编写测试代码,可以针对某个方法执行测试,也支持一键完成对全部的方法自动化测试
  • 不需要程序员去分析测试结果,会自动生成测试报告

具体使用

public class Demo {public static void printNumber(String name){if (name==null)return;System.out.println("名字长度:"+name.length());}public static int getMaxIndex(String data){if (data==null)return -1;return data.length();}
}
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;/*
测试类*/
public class DemoTest {@Beforepublic void test1(){System.out.println("---------Before---------");}@Afterpublic void test2(){System.out.println("---------After---------");}@AfterClasspublic static void test3(){System.out.println("---------AfterClass---------");}@BeforeClasspublic static void test4(){System.out.println("---------BeforeClass---------");}/*公开 无返回值*/@Test //测试方法public void testPrintNumber(){Demo.printNumber("admin");Demo.printNumber(null);}@Test //测试方法public void testGetMaxIndex(){//断言机制:可以通过预测业务方法的结果来测试 bugSystem.out.println(Demo.getMaxIndex("admin"));System.out.println(Demo.getMaxIndex(null));//断言机制:可以通过预测业务方法的结果来测试 bugAssert.assertEquals("有bug",4,Demo.getMaxIndex("admin"));}
}

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

以下是学习框架源码的时候会用到,开发几乎不会用

反射

认识反射

加载类,并允许以编程的方式解剖类中的各个成分(成员变量、方法、构造器等)

步骤

  • 加载类,获取类的字节码:Class对象
  • 获取类的构造器:Constructor对象
  • 获取类成员变量:Field对象
  • 获取类成员方法:Method对象

获取类的字节码

  • Class c1 = 类名.class
  • 调用Class提供的方法 public static Class forName(String package); 全类名
  • Object的方法 对象.getClass()

获取类的构造器

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

import java.lang.reflect.Constructor;public class Demo1 {public static void main(String[] args) throws Exception {Class c = Cat.class;Constructor constructor = c.getDeclaredConstructor();System.out.println(constructor.getName()+"--"+constructor.getParameterCount());Cat o = (Cat) constructor.newInstance();System.out.println(o);Constructor declaredConstructor = c.getDeclaredConstructor(String.class, int.class);System.out.println(declaredConstructor.getName()+"--"+declaredConstructor.getParameterCount());declaredConstructor.setAccessible(true);//打破修饰符的限制Cat o1 = (Cat)declaredConstructor.newInstance("学习", 5);}
}   class Cat{private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Cat() {}private Cat(String name, int age) {this.name = name;this.age = age;}public Cat(String name) {this.name = name;}
}

获取类的成员变量

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

import java.lang.reflect.Field;public class Demo1 {public static void main(String[] args) throws Exception {Class c = Cat.class;Field[] fields = c.getDeclaredFields();for (Field field : fields) {System.out.println(field.getName()+"--"+field.getType());}Field name = c.getDeclaredField("name");System.out.println(name.getName()+"--"+name.getType());Cat cat = new Cat();name.setAccessible(true);name.set(cat,"猫猫");System.out.println(name.get(cat));}
}class Cat{public static int a;public static final String COUNTRY ="中国";private String name;private int age;public String getName() {return name;}public void setName(String name) {this.name = name;}public int getAge() {return age;}public void setAge(int age) {this.age = age;}public Cat() {}private Cat(String name, int age) {this.name = name;this.age = age;}public Cat(String name) {this.name = name;}
}

获取类的成员方法

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

作用、应用场景

基本作用:可以得到一个类全部成分对其操作;可以破坏封装性;适合做java的框架

import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;public class Test {public static void main(String[] args)throws Exception {Student stu = new Student("小明", 18, 82.5);Teacher tea = new Teacher("大强", 58);saveObject(stu);saveObject(tea);}public static void saveObject(Object obj) throws Exception {Class o = obj.getClass();String cname = o.getSimpleName();PrintStream ps = new PrintStream(new FileOutputStream("./out/obj.txt",true));ps.println("---------"+cname+"---------");Field[] fields = o.getDeclaredFields();for (Field field : fields) {field.setAccessible(true);String name = field.getName();String value = field.get(obj)+"";ps.println(name+":"+value);}ps.close();}
}
class Student{private String name;private int age;private double sorce;public Student(String name, int age, double sorce) {this.name = name;this.age = age;this.sorce = sorce;}
}class Teacher{private String name;private int age;public Teacher(String name, int age) {this.name = name;this.age = age;}
}

注解

就是java中特殊的标记,比如@override、@Test等

作用:让其他程序根据注解信息来决定怎么执行程序

注解可以用在类、方法、构造器、成员变量、参数等等

自定义注解

public @interface 注解名称{public 属性类型 属性名() default 默认值;
}

只有一个注解 且为 value 可以省略不写value

注解原理

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注解本质就是一个接口,java中所有的注解都是继承了Annotation的接口

@注解(…)其实就是一个实现类对象,实现了该注解以及Annotation的接口

元注解

修饰注解的注解

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

注解的解析

就是判断类上、方法上、成员变量上是否存在注解,并把注解里的内容给解析出来。

要解析谁的注解,就要先拿到谁

Class、Method、Field,Constructor、都实现了AnnotatedElement接口,它们都拥有解析注解的能力。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

package annotation;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target({ElementType.TYPE,ElementType.METHOD})//当前被修饰的注解只能使用在类上
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest{String value();double aaa() default 100;String[] bbb();
}
package annotation;@MyTest(value = "大强",aaa = 199.9,bbb={"css","java","html"})public class Demo {
@MyTest(value = "小明",aaa = 99.9,bbb={"java","html"})void test(){}
}
package annotation;import java.lang.reflect.Method;
import java.util.Arrays;public class AnnotationTest {public static void main(String[] args) throws Exception {Class c = Demo.class;Method test = c.getDeclaredMethod("test");if (c.isAnnotationPresent(MyTest.class)) {MyTest myTest = (MyTest) c.getDeclaredAnnotation(MyTest.class);System.out.println(myTest.value());System.out.println(myTest.aaa());System.out.println(Arrays.toString(myTest.bbb()));}if (test.isAnnotationPresent(MyTest.class)) {MyTest myTest = test.getDeclaredAnnotation(MyTest.class);System.out.println(myTest.value());System.out.println(myTest.aaa());System.out.println(Arrays.toString(myTest.bbb()));}}
}

应用场景

模拟junit

package annotation;import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;public class TestTest {@MyTest2public void test1(){System.out.println("==test1==");}public void test2(){System.out.println("==test2==");}public void test3(){System.out.println("==test3==");}public static void main(String[] args) throws Exception {Class c = TestTest.class;Method[] methods = c.getDeclaredMethods();for (Method method : methods) {if (method.isAnnotationPresent(MyTest2.class)){method.invoke(new TestTest());}}}
}

动态代理

概念

对象做的事情太多的话,可以通过代理来转移部分职责

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-blog.csdnimg.cn/direct/867cad296ec44d6385e47ae55f719acc.png)
package proxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;public class ProxyUtil {public static Star createProxy(BigStar bigStar) {/*参数1:指定一个类加载器参数2:指定生成的代理是什么样子,也就是有什么方法参数3:指定生成的代理对象要干什么事情*/return (Star) Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(), new Class[]{Star.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//代理对象要做的事情 会在这里写代码if (method.getName().equals("sing")){System.out.println("准备话筒,收钱20w");}else if (method.getName().equals("dance")){System.out.println("准备场地,收钱1000w");}return method.invoke(bigStar,args);}});}
}
package proxy;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(name+"正在跳舞~~~");}
}
package proxy;public interface Star {public String sing(String name);public void dance();
}
package proxy;public class Test {public static void main(String[] args) {BigStar s = new BigStar("杨超越");Star starProxy = ProxyUtil.createProxy(s);String rs = starProxy.sing("好日子");System.out.println(rs);System.out.println("--------------------------");starProxy.dance();}
}

坦克大战

java坐标系

下图说明了Java坐标系。坐标原点位于左上角,以像素为单位。在Java坐标系中,第一个是x坐标,表示当前位置为水平方向,距离坐标原点x个像素;第二个是y坐标,表示当前位置为垂直方向,距离坐标原点y个像素。

外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

package tankeGame;import javax.swing.*;
import java.awt.*;public class Draw extends JFrame {//JFrame 对应窗口 可以理解为一个画框private MyPanel mp =null;//定义一个画板public Draw(){//初始化画板mp = new MyPanel();//画板放入窗口this.add(mp);//设置窗口大小this.setSize(1000,800);//可以显示this.setVisible(true);//点窗口的× 程序退出this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new Draw();}
}//1.定义一个MyPanel继承JPanel,这个就是画板  画图形
class MyPanel extends JPanel{/*MyPanel:画板(面板)对象Graphics g:画笔paint调用时机:1.组件第一次在屏幕中显示的时候,系统自动调用2.窗口最小化 再最大化3.窗口大小发生变化4.repaint函数被调用*/@Overridepublic void paint(Graphics g) {//绘图的方法super.paint(g);//调用父类的方法完成初始化//画一个圆g.drawOval(10,10,100,100);//画直线g.drawLine(10,10,60,60);//画矩形g.drawRect(10,10,100,100);//填充矩形//设置画笔颜色g.setColor(Color.BLUE);g.fillRect(50,50,100,100);g.fillOval(200,200,50,60);//画图片//1.加载图片资源Image image = Toolkit.getDefaultToolkit().getImage("d:/shangan.png");//2.画图片g.drawImage(image,300,300,300,300,this);//画字符串g.setColor(Color.cyan);g.setFont(new Font("隶书",Font.BOLD,50));//位置是字体的左下角g.drawString("yb0os1",500,100);}
}

事件处理机制

委派事件模型

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;//事件控制 键盘控制小球的移动
//画笔
public class BallMove extends JFrame {private DrawBall ball = null;public BallMove() {ball = new DrawBall();this.add(ball);this.setVisible(true);this.setSize(500, 400);this.addKeyListener(ball);//JFame对象可以监听ball上面发生的键盘事件this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}public static void main(String[] args) {new BallMove();}
}//画板
//KeyListener 监听器 监听键盘事件
class DrawBall extends JPanel implements KeyListener {int x = 10;int y = 10;@Override//有字符输出时 该方法会触发public void keyTyped(KeyEvent e) {}@Override//当某个键被按下时 该方法会触发public void keyPressed(KeyEvent e) {
//        System.out.println((char) e.getKeyChar() + "被按下");//根据用户按下的不同键,来处理小球的移动//java中给每一个键分配一个值switch (e.getKeyCode()){case KeyEvent.VK_DOWN://向下的箭头++y;break;case KeyEvent.VK_UP://向上的--y;break;case KeyEvent.VK_LEFT://向左--x;break;case KeyEvent.VK_RIGHT://向右++x;break;}//重绘面板this.repaint();}@Override//当某个键被松开时 该方法会触发public void keyReleased(KeyEvent e) {}@Overridepublic void paint(Graphics g) {super.paint(g);g.fillOval(x, y, 20, 20);}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/13571.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【学习】实验室服务器常用的Linux指令。

1. 下载GitHub代码。 使用代码&#xff1a; git clone https://github.com/Turoad/CLRNet.git2. 压缩 / 解压。 打包压缩 是日常工作中备份文件的一种方式 在不同操作系统中&#xff0c;常用的打包压缩方式是不同的选项 含义 Windows 常用 rarMac 常用 zipLinux 常用 tar.gz…

学硕都考11408的211院校!河北工业大学计算机考研考情分析!

河北工业大学&#xff08;Hebei University of Technology&#xff09;&#xff0c;简称河北工大&#xff0c;坐落于天津市&#xff0c;由河北省人民政府、天津市人民政府与中华人民共和国教育部共建&#xff0c; 隶属于河北省&#xff0c;是国家“双一流”建设高校、国家“211…

自动化测试在软件开发生命周期中如何提高代码质量?

自动化测试是一种在软件开发生命周期中使用软件工具来执行测试的方法&#xff0c;它可以大大提高代码质量&#xff0c;减少开发过程中的错误和缺陷。本文将从零开始&#xff0c;详细且规范地介绍如何使用自动化测试来提高代码质量。 第一步&#xff1a;明确测试目标 在开始自…

webgl入门-绘制三角形

绘制三角形 前言 三角形是一个最简单、最稳定的面&#xff0c;webgl 中的三维模型都是由三角面组成的。咱们这一篇就说一下三角形的绘制方法。 课堂目标 理解多点绘图原理。可以绘制三角形&#xff0c;并将其组合成多边形。 知识点 缓冲区对象点、线、面图形 第一章 web…

iPhone实况照片从Windows资源管理器复制的JPG+MOV无法正常还原到iPhone

背景&#xff1a; 之前使用的iPhone 15 Pro&#xff0c;使用的Windows资源管理器当中复制导出的实况照片&#xff0c;复制出来的格式例如IMG_0001.JPG, IMG_0001.MOV。之后手机就卖掉了。现在使用的iPhone 14 Pro Max&#xff0c;想要导回之前备份的实况照片。尝试使用爱思助手…

supOS NEO科技普惠!永久免费!亿元补贴

数字化转型正在全球蓬勃发展&#xff0c;工业操作系统进入大规模推广期&#xff01; 如果您正在被预算不足、技术团队不强、数字化投入产出比等问题困扰&#xff0c;supOS NEO是您最好的选择。 “让supOS走进万千工厂、千行百业&#xff01;让全世界每个工厂都能用得上supOS&am…

MM模块学习三 (创建采购申请)

采购信息记录比较特殊既是主数据又是货源 注&#xff1a;发票校验是指把供应商提供的发票做到系统里面产生一张应付凭证。 1.决定采购需求 采购需求可以手工创建&#xff08;ME51N&#xff09;&#xff0c;也可以自动产生&#xff08;比如&#xff1a;MRP&#xff0c;以及比如…

CTFshow之文件上传web入门151关-161关解密。包教包会!!!!

这段时间一直在搞文件上传相关的知识&#xff0c;正好把ctf的题目做做写写给自字做个总结&#xff01; 不过有一个确定就是所有的测试全部是黑盒测试&#xff0c;无法从代码层面和大家解释&#xff0c;我找个时间把upload-labs靶场做一做给大家讲讲白盒的代码审计 一、实验准…

2024-5-23 石群电路-14

2024-5-23&#xff0c;星期四&#xff0c;22:20&#xff0c;天气&#xff1a;晴&#xff0c;心情&#xff1a;晴。今天没有什么重要的事情发生&#xff0c;心情一如既往的平静&#xff0c;距离返校假期还有两天~~~。 今天观看了石群老师电路基础课程的第23/24个视频&#xff0…

真实案例分享,终端pc直接telnet不到出口路由器。

1、背景信息 我终端pc的网卡地址获取的网关是在核心交换机上&#xff0c;在核心交换机上telnet出口路由器可以实现。 所有终端网段都不能telnet出口路由器&#xff0c;客户希望能用最小的影响方式进行解决。 2、现有配置信息 终端的无线和有线分别在两个网段中&#xff0c;…

【课后练习分享】Java用户注册界面设计和求三角形面积的图形界面程序

目录 java编程题&#xff08;每日一练&#xff09;&#xff1a; 问题一的答案代码如下&#xff1a; 问题一的运行截图如下&#xff1a; 问题二的答案代码如下&#xff1a; 问题二的运行截图如下&#xff1a; java编程题&#xff08;每日一练&#xff09;&#xff1a; 1.…

大数据量MySQL的分页查询优化

目录 造数据查看耗时优化方案总结 造数据 我用MySQL存储过程生成了100多万条数据&#xff0c;存储过程如下。 DELIMITER $$ USE test$$ DROP PROCEDURE IF EXISTS proc_user$$CREATE PROCEDURE proc_user() BEGINDECLARE i INT DEFAULT 1;WHILE i < 1000000 DOINSERT INT…

提权方式及原理汇总

一、Linux提权 1、SUID提权 SUID&#xff08;设置用户ID&#xff09;是赋予文件的一种权限&#xff0c;它会出现在文件拥有者权限的执行位上&#xff0c;具有这种权限的文件会在其执行时&#xff0c;使调用者暂时获得该文件拥有者的权限。 为可执行文件添加suid权限的目的是简…

二叉树求解大小操作详解

目录 一、求所有结点个数 1.1 递归思路 1.2 递归分支图 1.3 递归栈帧图 1.4 C语言实现 二、求叶子结点个数 2.1 递归思路 2.2 递归分支图 2.3 递归栈帧图 2.4 C语言实现 三、求第K层的结点个数 3.1 递归思路 3.2 递归分支图 3.3 递归栈帧图 3.4 C语言实现 四、求…

冯喜运:5.24现货黄金趋势解读,黄金原油行情分析及操作建议

【黄金消息面分析】&#xff1a;美国劳工部公布的最新数据显示&#xff0c;截至5月18日的一周内&#xff0c;首次申请失业救济人数下降至21.5万人&#xff0c;创下自去年9月以来的最大降幅。数据公布后&#xff0c;现货黄金短线下挫6美元&#xff0c;报2362.71美元/盎司。这表明…

2024受欢迎的便签app是哪个

在繁忙的工作和生活中&#xff0c;便签app成为了我们不可或缺的小助手。2024年&#xff0c;随着人们对高效工作和生活品质的追求&#xff0c;选择一款功能强大且用户友好的便签app显得尤为重要。在众多选择中&#xff0c;敬业签以其出色的记录与提醒功能&#xff0c;脱颖而出&a…

Python知识详解【1】~{正则表达式}

正则表达式是一种用于匹配字符串模式的文本工具&#xff0c;它由一系列普通字符和特殊字符组成&#xff0c;可以非常灵活地描述和处理字符串。以下是正则表达式的一些基本组成部分及其功能&#xff1a; 普通字符&#xff1a;大多数字母和数字在正则表达式中表示它们自己。例如…

指针,指针变量,引用,取地址符,malloce()函数使用,C中“—>” 和“ . ” 作用与区别

目录 一&#xff1a;指针,指针变量&#xff0c;引用&#xff0c;取地址符&#xff1a; 前提 &#xff1a; 1.“ * ” 的两种用途 2." & “的两种用途 2.1&#xff1a;引用 2.2&#xff1a;取地址 补充&#xff1a; 二 : malloc(),动态申请地址空间 1.原型定义…

Dubbo生态之初识dubbo协议

1.RPC框架 在java的发展中&#xff0c;随着业务的越来越庞大&#xff0c;单体架构的工作繁琐且耦合度高&#xff0c;因此单体架构过渡到了分布式架构&#xff0c;而分布式架构就必然涉及到各个服务之间的远程通信(RPC框架)&#xff0c;RPC框架如图所示: 工作流程: a.客户端调…

查看当前Shell系统环境变量

查看当前Shell系统环境变量 查看命令 env效果 查看Shell变量(系统环境变量自定义变量函数) 命令 set效果 常用系统环境变量 变量名称含义PATH与windows环境变量PATH功能一样&#xff0c;设置命令的搜索路径&#xff0c;以冒号为分割HOME当前用户主目录&#xff1a;/rootSH…