0


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

多线程基础

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

java.lang.Thread代表线程

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

可以使用

jconsole

查看

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

创建线程

有多个方法可以创建线程

  • 继承Thread类- 优点:编码简单- 缺点:无法继承其他类,不利于功能的扩展
  • 实现Runnable接口- 优点:任务类只是实现了接口,可以继续继承其他类、实现其他接口,扩展性强- 缺点:需要多创建一个Runnable对象
  • 实现Callable接口和FutureTask类- 优点:可以返回线程执行结束之后的结果- 缺点:编码复杂执行为什么是start()?使用run不是多线程, 相当于直接调用方法 还是单线程start->start0(本地方法 JVM调用 C/C++实现的)

方法一

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

方法二

publicclassDemo2{publicstaticvoidmain(String[] args)throwsException{//runnable只是一个任务对象Runnable target =newprime1Thread();//需要线程对象接受任务对象 开辟新的线程newThread(target).start();for(int i =0; i <5; i++){System.out.println("主线程");Thread.sleep(500);}}}class prime1Thread implementsRunnable{@Overridepublicvoidrun(){for(int i =0; i <5; i++){System.out.println("子线程");try{Thread.sleep(500);}catch(Exception e){
                e.printStackTrace();}}}}//可以使用匿名内部类publicclassDemo2{publicstaticvoidmain(String[] args)throwsException{//需要线程对象进行调用任务对象开辟新的线程newThread(()->{for(int i =0; i <5; i++){System.out.println("子线程");try{Thread.sleep(500);}catch(InterruptedException e){thrownewRuntimeException(e);}}}).start();for(int i =0; i <5; i++){System.out.println("主线程");Thread.sleep(500);}}}

方法三

importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutionException;importjava.util.concurrent.FutureTask;publicclassDemo3{publicstaticvoidmain(String[] args)throwsExecutionException,InterruptedException{//创建一个Callable对象Callable<String> myCallable =newMyCallable(100);// 把Callable的对象封装成一个FutureTask对象(任务对象)// 未来任务对象的作用?// 1、是一个任务对象,实现下Runnable对象// 2、可以在线程执行完毕之后,用未来任务对象调用get方法获取线程执行完毕的结果//也可以使用匿名内部类FutureTask<String> stringFutureTask =newFutureTask<>(myCallable);newThread(stringFutureTask).start();//获取结果会阻塞线程System.out.println(stringFutureTask.get());}}//泛型classMyCallableimplementsCallable<String>{privateint n;publicMyCallable(int n){this.n = n;}@OverridepublicStringcall()throwsException{int sum =0;for(int i =1; i <= n; i++){
            sum+=i;}return sum+"";}}

线程方法

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

  • setPriority()更改线程的优先级
  • getPriority()获取线程的优先级
  • interrupt中断线程,并不是真正的结束线程 所以一般用于中断正在休眠的线程
  • yield线程的礼让,不一定礼让成功(和join相反,线程的插队)
publicclassDemo4{publicstaticvoidmain(String[] args)throwsInterruptedException{Thread t1 =newThread1("1号线程");//        t1.setName("1号线程");//启动之前取名字
        t1.start();
        t1.join();//        System.out.println(t1.getName());Thread t2 =newThread1("2号线程");//        t2.setName("2号线程");//启动之前取名字
        t2.start();
        t2.join();//t2线程执行完成之后才能继续往下执行//        System.out.println(t2.getName());Thread t3 =newThread1("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));}}}classThread1extendsThread{publicThread1(String name){super(name);}@Overridepublicvoidrun(){Thread t=Thread.currentThread();for(int i =0; i <3; i++){System.out.println("子线程"+t.getName()+"输出:"+(i+1));}}}

线程终止

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

守护线程

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

垃圾回收机制

publicclassTest{publicstaticvoidmain(String[] args){//子线程设置为守护线程
        myDaemonThread myDaemonThread =newmyDaemonThread();
        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){thrownewRuntimeException(e);}}}}/*
守护线程:
当用户线程退出后 子线程也自动退出
 */class myDaemonThread extendsThread{@Overridepublicvoidrun(){while(true){System.out.println(Thread.currentThread().getName()+" 正在执行");try{Thread.sleep(500);}catch(InterruptedException e){thrownewRuntimeException(e);}}}}

线程安全

概念

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

模拟线程安全问题

packageThread_;publicclassDemo5{publicstaticvoidmain(String[] args){Thread xiaoHong =newDrawThread("小红");Thread xiaoMing =newDrawThread("小明");
        xiaoMing.start();
        xiaoHong.start();}}classAccount{privatestaticdouble moneys =100000;privateAccount(){}publicstaticdoublegetMoneys(){return moneys;}publicstaticvoidsetMoneys(double moneys){Account.moneys = moneys;}publicstaticbooleandrawMoneys(double moneys){String name =Thread.currentThread().getName();if(moneys>Account.getMoneys()){System.out.println(name+"来取钱,钱不够");returnfalse;}Account.moneys-=moneys;System.out.println(name+"来取钱,取钱成功,剩余"+Account.moneys);returntrue;}}classDrawThreadextendsThread{publicDrawThread(String name){super(name);}@Overridepublicvoidrun(){Account.drawMoneys(100000.0);}}

线程同步

认识线程同步

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

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

方法一:同步代码块

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

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

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

锁对象的选择:

  • 实例对象:使用this
  • 静态对象:使用类型.class
publicclassDemo5{publicstaticvoidmain(String[] args)throwsInterruptedException{Account acc1 =newAccount(100000);Thread xiaoHong =newDrawThread("小红",acc1);Thread xiaoMing =newDrawThread("小明",acc1);
        xiaoMing.start();
        xiaoHong.start();Account acc2 =newAccount(100000);Thread daGang =newDrawThread("大纲",acc2);Thread daLi =newDrawThread("大力",acc2);
        daGang.start();
        daLi.start();}}classAccount{privatedouble moneys;publicAccount(){}publicAccount(double moneys){this.moneys = moneys;}publicdoublegetMoneys(){return moneys;}publicvoidsetMoneys(double moneys){this.moneys = moneys;}publicvoiddrawMoneys(double moneys)throwsInterruptedException{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);}}}}classDrawThreadextendsThread{privateAccount acc;publicDrawThread(String name,Account acc){super(name);this.acc = acc;}@Overridepublicvoidrun(){try{
            acc.drawMoneys(100000);}catch(InterruptedException e){thrownewRuntimeException(e);}}}

方法二:同步方法

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

修饰符 synchronized 返回值类型 方法名称(形参列表){
    操作共享资源的代码
}
publicclassDemo5{publicstaticvoidmain(String[] args)throwsInterruptedException{Account acc1 =newAccount(100000);Thread xiaoHong =newDrawThread("小红", acc1);Thread xiaoMing =newDrawThread("小明", acc1);
        xiaoMing.start();
        xiaoHong.start();Account acc2 =newAccount(100000);Thread daGang =newDrawThread("大纲", acc2);Thread daLi =newDrawThread("大力", acc2);
        daGang.start();
        daLi.start();}}classAccount{privatedouble moneys;publicAccount(){}publicAccount(double moneys){this.moneys = moneys;}publicdoublegetMoneys(){return moneys;}publicvoidsetMoneys(double moneys){this.moneys = moneys;}/*
    有一个隐含的锁 实例方法是 this  静态方法是 类型.class
     */publicsynchronizedvoiddrawMoneys(double moneys)throwsInterruptedException{String name =Thread.currentThread().getName();if(moneys >this.getMoneys()){System.out.println(name +"来取钱,钱不够");}else{this.moneys -= moneys;System.out.println(name +"来取钱,取钱"+ moneys +"成功,剩余"+this.moneys);}}}classDrawThreadextendsThread{privateAccount acc;publicDrawThread(String name,Account acc){super(name);this.acc = acc;}@Overridepublicvoidrun(){try{
            acc.drawMoneys(100000);}catch(InterruptedException e){thrownewRuntimeException(e);}}}

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

方法三:Lock锁

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

Lock是接口,不能直接实例化,可以采用它的实现类**

ReentrantLock

**来构建Lock锁对象。

packageThread_;importjava.util.concurrent.locks.Lock;importjava.util.concurrent.locks.ReentrantLock;publicclassDemo5{publicstaticvoidmain(String[] args)throwsInterruptedException{Account acc1 =newAccount(100000);Thread xiaoHong =newDrawThread("小红", acc1);Thread xiaoMing =newDrawThread("小明", acc1);
        xiaoMing.start();
        xiaoHong.start();Account acc2 =newAccount(100000);Thread daGang =newDrawThread("大纲", acc2);Thread daLi =newDrawThread("大力", acc2);
        daGang.start();
        daLi.start();}}classAccount{/*
    创建了一个锁对象 每一个账户都有一个自己的锁对象
    不允许二次赋值
    */privatefinalLock lk =newReentrantLock();privatedouble moneys;publicAccount(){}publicAccount(double moneys){this.moneys = moneys;}publicdoublegetMoneys(){return moneys;}publicvoidsetMoneys(double moneys){this.moneys = moneys;}publicvoiddrawMoneys(double moneys)throwsInterruptedException{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){thrownewRuntimeException(e);}finally{
            lk.unlock();//无论try中代码是否有错误 都会解锁}}}classDrawThreadextendsThread{privateAccount acc;publicDrawThread(String name,Account acc){super(name);this.acc = acc;}@Overridepublicvoidrun(){try{
            acc.drawMoneys(100000);}catch(InterruptedException e){thrownewRuntimeException(e);}}}

释放锁的时机

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

不释放锁

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

线程死锁

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

publicclassDemo{publicstaticvoidmain(String[] args){newThread(newMyDeadThread(false)).start();newThread(newMyDeadThread(true)).start();}}classMyDeadThreadimplementsRunnable{privateboolean flag;privatestaticObject o1 =newObject();privatestaticObject o2 =newObject();publicMyDeadThread(){}publicMyDeadThread(boolean flag){this.flag = flag;}@Overridepublicvoidrun(){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");}}}}}}

线程通信

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

生产者消费者模型

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

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

publicclassThreadTest{publicstaticvoidmain(String[] args){Desk desk =newDesk();//3个生产者newThread(()->{while(true){desk.put();}},"厨师1").start();newThread(()->{while(true){desk.put();}},"厨师2").start();newThread(()->{while(true){desk.put();}},"厨师3").start();//2个消费者newThread(()->{while(true){desk.get();}},"吃货1").start();newThread(()->{while(true){desk.get();}},"吃货2").start();}}importjava.util.ArrayList;importjava.util.List;publicclassDesk{privatefinalList<String>list =newArrayList<>();//这个五个人是同一把锁publicsynchronizedvoidput(){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){thrownewRuntimeException(e);}}publicsynchronizedvoidget(){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){thrownewRuntimeException(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 =newThreadPoolExecutor(3,5,8,TimeUnit.SECONDS,newArrayBlockingQueue<>(4),Executors.defaultThreadFactory(),newThreadPoolExecutor.AbortPolicy());

什么时候创建临时对象?

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

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

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

新任务拒绝策略

在这里插入图片描述

处理Runnable任务

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

importjava.util.concurrent.ArrayBlockingQueue;importjava.util.concurrent.BlockingQueue;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.RejectedExecutionHandler;importjava.util.concurrent.ThreadFactory;importjava.util.concurrent.ThreadPoolExecutor;importjava.util.concurrent.TimeUnit;publicclass _ThreadPool {publicstaticvoidmain(String[] args){/*
        ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
         */ExecutorService poolExecutor =newThreadPoolExecutor(3,5,8,TimeUnit.SECONDS,newArrayBlockingQueue<>(4),Executors.defaultThreadFactory(),newThreadPoolExecutor.CallerRunsPolicy());MyRunnable myRunnable1 =newMyRunnable();MyRunnable myRunnable2 =newMyRunnable();MyRunnable myRunnable3 =newMyRunnable();//三个核心线程在忙
        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();//立刻关闭线程池}}classMyRunnableimplementsRunnable{@Overridepublicvoidrun(){String name =Thread.currentThread().getName();System.out.println(name +"666");try{Thread.sleep(100000);}catch(InterruptedException e){thrownewRuntimeException(e);}}}

处理Callable任务

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

importjava.util.concurrent.ArrayBlockingQueue;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;importjava.util.concurrent.ThreadPoolExecutor;importjava.util.concurrent.TimeUnit;publicclass _ThreadPool {publicstaticvoidmain(String[] args)throwsException{/*
        ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue,
                              ThreadFactory threadFactory,
                              RejectedExecutionHandler handler)
         */ExecutorService poolExecutor =newThreadPoolExecutor(3,5,8,TimeUnit.SECONDS,newArrayBlockingQueue<>(4),Executors.defaultThreadFactory(),newThreadPoolExecutor.CallerRunsPolicy());Future<String>f1 =  poolExecutor.submit(newMyCallable(100));Future<String>f2 =  poolExecutor.submit(newMyCallable(200));Future<String>f3 =  poolExecutor.submit(newMyCallable(300));Future<String>f4 =  poolExecutor.submit(newMyCallable(400));System.out.println(f1.get());System.out.println(f2.get());System.out.println(f3.get());System.out.println(f4.get());}}classMyCallableimplementsCallable<String>{privateint n;publicMyCallable(int n){this.n = n;}@OverridepublicStringcall()throwsException{int sum =0;for(int i =1; i <= n; i++){
            sum+=i;}returnThread.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调度执行

线程生命周期

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

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

在这里插入图片描述

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

扩展:悲观锁和乐观锁

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

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

//乐观锁importjava.util.concurrent.atomic.AtomicInteger;publicclassDemo7{//一个静态变量,100个线程,每个线程对其加100次publicstaticvoidmain(String[] args){Runnable mRunnable =newMRunnable2();for(int i =0; i <100; i++){//100个线程执行相同的任务newThread(mRunnable).start();}}}classMRunnable2implementsRunnable{//    private int count;//整数修改的乐观锁:原子类,privateAtomicInteger count =newAtomicInteger();@Overridepublicvoidrun(){for(int i =0; i <100; i++){System.out.println("count====>"+(count.incrementAndGet()));}}}

多线程练习

importjava.util.ArrayList;importjava.util.Arrays;importjava.util.Random;publicclassTest1{publicstaticvoidmain(String[] args)throwsInterruptedException{/**
         * 目标:有100份礼品,小红,小明两人同时发送,当剩下的礼品小于10份的时候则不再送出,
         * 利用多线程模拟该过程并将线程的名称打印出来。并最后在控制台分别打印小红,小明各自送出多少分礼物。
         */ArrayList<String> gifts =newArrayList<>();String[] names ={"口红","包包","腰带","剃须刀","香水","衣服"};Random r =newRandom();for(int i =0; i <100; i++){
            gifts.add(names[r.nextInt(names.length)]+(i +1));}

        sendThread xm =newsendThread(gifts,"小明");
        sendThread xh =newsendThread(gifts,"小红");
        xm.start();
        xh.start();

        xm.join();
        xh.join();System.out.println("小明送出去"+ xm.getCount());System.out.println("小红送出去"+ xh.getCount());}}class sendThread extendsThread{privateArrayList<String> gifts;privateint count;publicintgetCount(){return count;}publicvoidsetCount(int count){this.count = count;}publicsendThread(){}publicsendThread(ArrayList<String> gifts,String name){super(name);this.gifts = gifts;}@Overridepublicvoidrun(){Random r =newRandom();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)
importjava.net.InetAddress;importjava.net.UnknownHostException;publicclassGetIP{publicstaticvoidmain(String[] args)throwsException{//本机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

importjava.net.DatagramPacket;importjava.net.DatagramSocket;importjava.net.InetAddress;publicclassClient{publicstaticvoidmain(String[] args)throwsException{//创建客户端 以及客户端端口DatagramSocket socket  =newDatagramSocket(6666);String data ="我是客户端,哈哈哈";byte[]bytes = data.getBytes();//创建数据包DatagramPacket packet =newDatagramPacket(bytes,bytes.length,InetAddress.getLocalHost(),5555);//发送数据
        socket.send(packet);System.out.println("客户端数据发送完毕");//释放资源
        socket.close();}}

Serve

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

可以多个用户同时发送

Client

importjava.net.DatagramPacket;importjava.net.DatagramSocket;importjava.net.InetAddress;importjava.util.Scanner;publicclassClient{publicstaticvoidmain(String[] args)throwsException{//创建客户端 以及客户端端口(默认随机分配)DatagramSocket socket  =newDatagramSocket();Scanner sc =newScanner(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 =newDatagramPacket(bytes,bytes.length,InetAddress.getLocalHost(),5555);//发送数据
            socket.send(packet);}
        socket.close();}}

Serve

importjava.net.DatagramPacket;importjava.net.DatagramSocket;publicclassServe{publicstaticvoidmain(String[] args)throwsException{System.out.println("===服务端启动===");//创建服务端 注册服务端端口DatagramSocket socket =newDatagramSocket(5555);byte[] buffer =newbyte[1024*64];//64KB  UDP一个数据包最大为64KB//创建一个用来接收数据的数据包对象DatagramPacket packet =newDatagramPacket(buffer, buffer.length);while(true){//接受数据
            socket.receive(packet);//从字节数组中获取接受的数据int len = packet.getLength();String data =newString(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

importjava.io.DataOutputStream;importjava.io.OutputStream;importjava.net.InetAddress;importjava.net.Socket;publicclassClientTCP{publicstaticvoidmain(String[] args)throwsException{//创建socket对象Socket socket =newSocket(InetAddress.getLocalHost(),5555);//从socket通信管道中得到一个字节输出流OutputStream os = socket.getOutputStream();//封装成数据输出流DataOutputStream dataOutputStream =newDataOutputStream(os);//写入数据
        dataOutputStream.writeUTF("你好呀!");//关闭数据流
        dataOutputStream.close();//关闭socket
        socket.close();}}

serve

importjava.io.DataInputStream;importjava.io.InputStream;importjava.net.ServerSocket;importjava.net.Socket;publicclassServeTCP{publicstaticvoidmain(String[] args)throwsException{System.out.println("--服务端启动--");//创建服务端对象 绑定端口ServerSocket serverSocket =newServerSocket(5555);//等待连接Socket socket = serverSocket.accept();//接受数据InputStream ds = socket.getInputStream();//封装DataInputStream dataInputStream =newDataInputStream(ds);//接受数据String s = dataInputStream.readUTF();System.out.println(s);//客户端ip地址System.out.println(socket.getRemoteSocketAddress());

        dataInputStream.close();
        socket.close();}}
多发多收

client

importjava.io.DataOutputStream;importjava.io.OutputStream;importjava.net.InetAddress;importjava.net.Socket;importjava.util.Objects;importjava.util.Scanner;publicclassClientTCP{publicstaticvoidmain(String[] args)throwsException{//创建socket对象Socket socket =newSocket(InetAddress.getLocalHost(),5555);//从socket通信管道中得到一个字节输出流OutputStream os = socket.getOutputStream();//封装成数据输出流DataOutputStream dataOutputStream =newDataOutputStream(os);Scanner sc =newScanner(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();//关闭socket
        socket.close();}}

serve

importjava.io.DataInputStream;importjava.io.IOException;importjava.io.InputStream;importjava.net.ServerSocket;importjava.net.Socket;publicclassServeTCP{publicstaticvoidmain(String[] args)throwsException{System.out.println("--服务端启动--");//创建服务端对象 绑定端口ServerSocket serverSocket =newServerSocket(5555);//等待连接Socket socket = serverSocket.accept();//接受数据InputStream ds = socket.getInputStream();//封装DataInputStream dataInputStream =newDataInputStream(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

importjava.io.DataOutputStream;importjava.io.OutputStream;importjava.net.Socket;importjava.util.Scanner;publicclassClientTCP{publicstaticvoidmain(String[] args)throwsException{Socket socket =newSocket("127.0.0.1",8888);OutputStream os = socket.getOutputStream();DataOutputStream dos =newDataOutputStream(os);Scanner sc =newScanner(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

importjava.io.DataInputStream;importjava.io.IOException;importjava.io.InputStream;importjava.net.ServerSocket;importjava.net.Socket;importjava.net.SocketAddress;publicclassServeTCP{publicstaticvoidmain(String[] args)throwsException{System.out.println("服务端开启...");ServerSocket serverSocket =newServerSocket(8888);while(true){Socket socket = serverSocket.accept();System.out.println(socket.getRemoteSocketAddress()+"上线了");newThread(newSocketThread(socket)).start();}}}classSocketThreadimplementsRunnable{privateSocket socket;publicSocketThread(Socket socket){this.socket = socket;}@Overridepublicvoidrun(){SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();try{InputStream is = socket.getInputStream();DataInputStream dis =newDataInputStream(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

importjava.io.DataInputStream;importjava.io.DataOutputStream;importjava.io.InputStream;importjava.io.OutputStream;importjava.net.InetAddress;importjava.net.Socket;importjava.util.Scanner;publicclassClientChat{publicstaticvoidmain(String[] args){try{Socket socket =newSocket("127.0.0.1",8888);newClientThread(socket).start();OutputStream os = socket.getOutputStream();DataOutputStream dos =newDataOutputStream(os);Scanner sc =newScanner(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();}}}classClientThreadextendsThread{privateSocket socket;publicClientThread(Socket socket){this.socket = socket;}@Overridepublicvoidrun(){try{InputStream is = socket.getInputStream();DataInputStream dis =newDataInputStream(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

importjava.io.DataInputStream;importjava.io.DataOutputStream;importjava.io.InputStream;importjava.io.OutputStream;importjava.net.ServerSocket;importjava.net.Socket;importjava.net.SocketAddress;importjava.util.ArrayList;importjava.util.List;importjava.util.Objects;publicclassServeChat{publicstaticfinalList<Socket> onlineUsers =newArrayList<>();publicstaticvoidmain(String[] args)throwsException{System.out.println("==服务器启动==");ServerSocket serverSocket =newServerSocket(8888);while(true){Socket socket = serverSocket.accept();
            onlineUsers.add(socket);newServeReaderThread(socket).start();}}}classServeReaderThreadextendsThread{privateSocket socket;publicServeReaderThread(Socket socket){this.socket = socket;}@Overridepublicvoidrun(){try{InputStream is = socket.getInputStream();DataInputStream dis =newDataInputStream(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();}}privatevoidsendAllOnlineUsers(Socket socket,String msg)throwsException{for(Socket onlineUser :ServeChat.onlineUsers){SocketAddress remoteSocketAddress = socket.getRemoteSocketAddress();if(Objects.equals(onlineUser.getRemoteSocketAddress(),remoteSocketAddress)){continue;}OutputStream os = onlineUser.getOutputStream();DataOutputStream dos =newDataOutputStream(os);
            dos.writeUTF(remoteSocketAddress+"说:"+msg);
            dos.flush();}}}

案例:简易BS架构

importjava.io.DataOutputStream;importjava.io.IOException;importjava.io.OutputStream;importjava.io.PrintStream;importjava.net.ServerSocket;importjava.net.Socket;publicclassServe{publicstaticvoidmain(String[] args)throwsException{ServerSocket serverSocket =newServerSocket(8080);while(true){Socket socket = serverSocket.accept();System.out.println(socket.getRemoteSocketAddress()+"上线了");newCThread(socket).start();}}}classCThreadextendsThread{privateSocket socket;publicCThread(Socket socket){this.socket=socket;}@Overridepublicvoidrun(){try{OutputStream os = socket.getOutputStream();PrintStream ps =newPrintStream(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();}}}

改进:线程池

importjava.io.DataOutputStream;importjava.io.IOException;importjava.io.OutputStream;importjava.io.PrintStream;importjava.net.ServerSocket;importjava.net.Socket;importjava.util.concurrent.ArrayBlockingQueue;importjava.util.concurrent.Executors;importjava.util.concurrent.ThreadPoolExecutor;importjava.util.concurrent.TimeUnit;publicclassServe{publicstaticvoidmain(String[] args)throwsException{ServerSocket serverSocket =newServerSocket(8080);ThreadPoolExecutor pool =newThreadPoolExecutor(16*2,16*2,0,TimeUnit.SECONDS,newArrayBlockingQueue<>(8),Executors.defaultThreadFactory(),newThreadPoolExecutor.AbortPolicy());while(true){Socket socket = serverSocket.accept();System.out.println(socket.getRemoteSocketAddress()+"上线了");
            pool.execute(newCThread(socket));}}}classCThreadimplementsRunnable{privateSocket socket;publicCThread(Socket socket){this.socket=socket;}@Overridepublicvoidrun(){try{OutputStream os = socket.getOutputStream();PrintStream ps =newPrintStream(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单元测试框架

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

具体使用

publicclassDemo{publicstaticvoidprintNumber(String name){if(name==null)return;System.out.println("名字长度:"+name.length());}publicstaticintgetMaxIndex(String data){if(data==null)return-1;return data.length();}}
importorg.junit.After;importorg.junit.AfterClass;importorg.junit.Assert;importorg.junit.Before;importorg.junit.BeforeClass;importorg.junit.Test;/*
测试类
 */publicclassDemoTest{@Beforepublicvoidtest1(){System.out.println("---------Before---------");}@Afterpublicvoidtest2(){System.out.println("---------After---------");}@AfterClasspublicstaticvoidtest3(){System.out.println("---------AfterClass---------");}@BeforeClasspublicstaticvoidtest4(){System.out.println("---------BeforeClass---------");}/*
    公开 无返回值
     */@Test//测试方法publicvoidtestPrintNumber(){Demo.printNumber("admin");Demo.printNumber(null);}@Test//测试方法publicvoidtestGetMaxIndex(){//断言机制:可以通过预测业务方法的结果来测试 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()

获取类的构造器

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

importjava.lang.reflect.Constructor;publicclassDemo1{publicstaticvoidmain(String[] args)throwsException{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);}}classCat{privateString name;privateint age;publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicintgetAge(){return age;}publicvoidsetAge(int age){this.age = age;}publicCat(){}privateCat(String name,int age){this.name = name;this.age = age;}publicCat(String name){this.name = name;}}

获取类的成员变量

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

importjava.lang.reflect.Field;publicclassDemo1{publicstaticvoidmain(String[] args)throwsException{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 =newCat();
        name.setAccessible(true);
        name.set(cat,"猫猫");System.out.println(name.get(cat));}}classCat{publicstaticint a;publicstaticfinalStringCOUNTRY="中国";privateString name;privateint age;publicStringgetName(){return name;}publicvoidsetName(String name){this.name = name;}publicintgetAge(){return age;}publicvoidsetAge(int age){this.age = age;}publicCat(){}privateCat(String name,int age){this.name = name;this.age = age;}publicCat(String name){this.name = name;}}

获取类的成员方法

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

作用、应用场景

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

importjava.io.FileOutputStream;importjava.io.PrintStream;importjava.lang.reflect.Field;publicclassTest{publicstaticvoidmain(String[] args)throwsException{Student stu =newStudent("小明",18,82.5);Teacher tea =newTeacher("大强",58);saveObject(stu);saveObject(tea);}publicstaticvoidsaveObject(Object obj)throwsException{Class o = obj.getClass();String cname = o.getSimpleName();PrintStream ps =newPrintStream(newFileOutputStream("./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();}}classStudent{privateString name;privateint age;privatedouble sorce;publicStudent(String name,int age,double sorce){this.name = name;this.age = age;this.sorce = sorce;}}classTeacher{privateString name;privateint age;publicTeacher(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接口,它们都拥有解析注解的能力。
外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

packageannotation;importjava.lang.annotation.ElementType;importjava.lang.annotation.Retention;importjava.lang.annotation.RetentionPolicy;importjava.lang.annotation.Target;@Target({ElementType.TYPE,ElementType.METHOD})//当前被修饰的注解只能使用在类上@Retention(RetentionPolicy.RUNTIME)public@interfaceMyTest{Stringvalue();doubleaaa()default100;String[]bbb();}
packageannotation;@MyTest(value ="大强",aaa =199.9,bbb={"css","java","html"})publicclassDemo{@MyTest(value ="小明",aaa =99.9,bbb={"java","html"})voidtest(){}}
packageannotation;importjava.lang.reflect.Method;importjava.util.Arrays;publicclassAnnotationTest{publicstaticvoidmain(String[] args)throwsException{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

packageannotation;importjava.lang.reflect.InvocationTargetException;importjava.lang.reflect.Method;publicclassTestTest{@MyTest2publicvoidtest1(){System.out.println("==test1==");}publicvoidtest2(){System.out.println("==test2==");}publicvoidtest3(){System.out.println("==test3==");}publicstaticvoidmain(String[] args)throwsException{Class c =TestTest.class;Method[] methods = c.getDeclaredMethods();for(Method method : methods){if(method.isAnnotationPresent(MyTest2.class)){
                method.invoke(newTestTest());}}}}

动态代理

概念

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

![外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传](https://img-blog.csdnimg.cn/direct/867cad296ec44d6385e47ae55f719acc.png)
packageproxy;importjava.lang.reflect.InvocationHandler;importjava.lang.reflect.Method;importjava.lang.reflect.Proxy;publicclassProxyUtil{publicstaticStarcreateProxy(BigStar bigStar){/*
        参数1:指定一个类加载器
        参数2:指定生成的代理是什么样子,也就是有什么方法
        参数3:指定生成的代理对象要干什么事情
         */return(Star)Proxy.newProxyInstance(ProxyUtil.class.getClassLoader(),newClass[]{Star.class},newInvocationHandler(){@OverridepublicObjectinvoke(Object proxy,Method method,Object[] args)throwsThrowable{//代理对象要做的事情 会在这里写代码if(method.getName().equals("sing")){System.out.println("准备话筒,收钱20w");}elseif(method.getName().equals("dance")){System.out.println("准备场地,收钱1000w");}return method.invoke(bigStar,args);}});}}
packageproxy;publicclassBigStarimplementsStar{privateString name;publicBigStar(){}publicBigStar(String name){this.name = name;}@OverridepublicStringsing(String name){System.out.println(this.name+"正在唱"+name+"歌~~~");return"谢谢!谢谢~";}@Overridepublicvoiddance(){System.out.println(name+"正在跳舞~~~");}}
packageproxy;publicinterfaceStar{publicStringsing(String name);publicvoiddance();}
packageproxy;publicclassTest{publicstaticvoidmain(String[] args){BigStar s =newBigStar("杨超越");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个像素。

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

packagetankeGame;importjavax.swing.*;importjava.awt.*;publicclassDrawextendsJFrame{//JFrame 对应窗口 可以理解为一个画框privateMyPanel mp =null;//定义一个画板publicDraw(){//初始化画板
        mp =newMyPanel();//画板放入窗口this.add(mp);//设置窗口大小this.setSize(1000,800);//可以显示this.setVisible(true);//点窗口的× 程序退出this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}publicstaticvoidmain(String[] args){newDraw();}}//1.定义一个MyPanel继承JPanel,这个就是画板  画图形classMyPanelextendsJPanel{/*
    MyPanel:画板(面板)对象
    Graphics g:画笔

    paint调用时机:
    1.组件第一次在屏幕中显示的时候,系统自动调用
    2.窗口最小化 再最大化
    3.窗口大小发生变化
    4.repaint函数被调用
     */@Overridepublicvoidpaint(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(newFont("隶书",Font.BOLD,50));//位置是字体的左下角
        g.drawString("yb0os1",500,100);}}

事件处理机制

委派事件模型

importjavax.swing.*;importjava.awt.*;importjava.awt.event.KeyEvent;importjava.awt.event.KeyListener;//事件控制 键盘控制小球的移动//画笔publicclassBallMoveextendsJFrame{privateDrawBall ball =null;publicBallMove(){
        ball =newDrawBall();this.add(ball);this.setVisible(true);this.setSize(500,400);this.addKeyListener(ball);//JFame对象可以监听ball上面发生的键盘事件this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);}publicstaticvoidmain(String[] args){newBallMove();}}//画板//KeyListener 监听器 监听键盘事件classDrawBallextendsJPanelimplementsKeyListener{int x =10;int y =10;@Override//有字符输出时 该方法会触发publicvoidkeyTyped(KeyEvent e){}@Override//当某个键被按下时 该方法会触发publicvoidkeyPressed(KeyEvent e){//        System.out.println((char) e.getKeyChar() + "被按下");//根据用户按下的不同键,来处理小球的移动//java中给每一个键分配一个值switch(e.getKeyCode()){caseKeyEvent.VK_DOWN://向下的箭头
                ++y;break;caseKeyEvent.VK_UP://向上的
                --y;break;caseKeyEvent.VK_LEFT://向左
                --x;break;caseKeyEvent.VK_RIGHT://向右
                ++x;break;}//重绘面板this.repaint();}@Override//当某个键被松开时 该方法会触发publicvoidkeyReleased(KeyEvent e){}@Overridepublicvoidpaint(Graphics g){super.paint(g);
        g.fillOval(x, y,20,20);}}

本文转载自: https://blog.csdn.net/bossDDYY/article/details/139155396
版权归原作者 yb0os1 所有, 如有侵权,请联系我们删除。

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

还没有评论