作业解析
  1. 利用白富美接口案例,土豪征婚使用匿名内部类对象实现。
interface White{
     public void white();
 }

 interface Rich{
     public void rich();
 }

 interface Beauty{
     public void beauty();
 }

 interface WRB extends White, Rich, Beauty{
 }

 class TuHao{
     public void getMarry(WRB wrb){
         wrb.white();
         wrb.rich();
         wrb.beauty();
     }
 }

 class Demo{
     public static void main(String[] args){
         TuHao wsc = new TuHao();
         wsc.getMarry(new WRB(){
             public void white(){
                 System.out.println("white");
             }
             public void rich(){
                 System.out.println("rich");
             }
             public void beauty(){
                 System.out.println("beauty");
             }    
         });
     }
 }
  1. 定义三角形类Trianle,里面包含三个int类型属性,分别表示三条边的长度,
    构造三角形对象时,任意两边之和是否大于第三边,如若不成立,抛出自定义异常。
class Triangle{
     private int a;
     private int b;
     private int c;
     public Triangle(int a, int b, int c){
         try{
             if(a>=b+c || b>=a+c || c>=a+b){
                 throw new TriangleLengthException("Invalid Length");
             }
             else{
                 this.a = a;
                 this.b = b;
                 this.c = c;
             }
         }
         catch(TriangleLengthException e){
             e.printStackTrace();
         }
     }
 }

 class TriangleLengthException extends Exception{
     String exceptionInfo;
     public TriangleLengthException(String info){
         exceptionInfo = info;
     }

     public void printStackTrace(){
         System.out.println(exceptionInfo);
     }
 }

 class TriExceptionDemo{
     public static void main(String[] args){
         Triangle t1 = new Triangle(2,3,4);
         Triangle t2 = new Triangle(2,2,4);
         Triangle t3 = new Triangle(2,7,4);
     }
 }
  1. Person类中增加birthday属性,对setBirthday(int ,int , int )方法进行异常处理,
    要求年有效、月有效、日有效、年月日指定的具体日期有效,对不同情况分别抛出不同的异常。
    year:>1970, month:1-12, day:1-31
class Person{
     private int year;
     private int month;
     private int day;
     public void setBirthday(int year, int month, int day){
         try{
             if(year<1970){
                 throw new YearException("Invalid Year");
             }
             else{
                 if(month<1 || month > 12){
                     throw new MonthException("Invalid Month");
                 }
                 else{
                     if(day<1 || day>31){
                         throw new DayException("Invalid Day");
                     }
                     else{
                         switch(month){
                             case 1:
                             case 3:
                             case 5:
                             case 7:
                             case 8:
                             case 10:
                             case 12:
                                 break;
                             case 2:
                                 if((year%400==0) || (year%4==0 && year%100!=0)){
                                     if(day>29){
                                         throw new DateException("Invalid Date");
                                     }
                                 }
                                 else{
                                     if(day>28){      
                                         throw new DateException("Invalid Date");
                                     }
                                 }
                             case 4:
                             case 6:
                             case 9:
                             case 11:
                                 if(day==31){
                                     throw new DateException("Invalid Date");
                                 }
                             }
                         }
                     }
                 }
             }
         catch(Exception e){
             e.printStackTrace();
         }
     }
 }

 class YearException extends Exception{
     String exceptionInfo;
     public YearException(String info){
         exceptionInfo = info;
     }
     public void printStackTrace(){
         System.out.println(exceptionInfo);
     }
 }

 class MonthException extends Exception{
     String exceptionInfo;
     public MonthException(String info){
         exceptionInfo = info;
     }
     public void printStackTrace(){
         System.out.println(exceptionInfo);
     }
 }

 class DayException extends Exception{
     String exceptionInfo;
     public DayException(String info){
         exceptionInfo = info;
     }
     public void printStackTrace(){
         System.out.println(exceptionInfo);
     }
 }

 class DateException extends Exception{
     String exceptionInfo;
     public DateException(String info){
         exceptionInfo = info;
     }
     public void printStackTrace(){
         System.out.println(exceptionInfo);
     }
 }

 class BirthdayExceptionDemo{
     public static void main(String[] args){
     Person p1 = new Person();
     p1.setBirthday(12,1,22);
     p1.setBirthday(1970,13,22);
     p1.setBirthday(2000,1,32);
     p1.setBirthday(2000,2,28);
     p1.setBirthday(2000,2,29);
     p1.setBirthday(2016,2,30);
     p1.setBirthday(2100,2,29);
     }
 }
  1. 将类定义到指定的包下。com.xkzhai.jar,编译之后,打成jar文件。
  • 编写源文件jarDemo.java
package com.xkzhai.jar;
  class Person{
      private String name;
      private String sex;
      public void run(){
          System.out.println("run");
      }
  }

  class jarDemo{
      public static void main(String[] args){
          Person p1 = new Person();
          p1.run();
      }
  }
  • 编译到指定的位置
javac -d classes2 jarDemo.java
  • 归档
jar cvf test.jar -C classes2/ .
  jar cvfe test2.jar com.xkzhai.jar.jarDemo -C classes2/ . //在清单文件中增加入口点
  • 运行程序
java -cp classes2 com.xkzhai.jar.jarDemo
  java -cp test.jar com.xkzhai.jar.jarDemo
  java -jar test2.jar//定义好入口点的jar包
  1. 相互之间使用jar包,放置cp下,对class进行重用
  • 编写第一个java程序Person.java
package com.xkzhai.jar1;
  //不同包下的类重用,需定义为public
  public class Person{
      private String name;
      private String sex;
      private int age;
      public void setAge(int age){
          this.age = age;
      }
      public int getAge(){
          return age;
      }
  }
  • 编译上述文件,放置到classes3文件夹下
javac -d classes3 Person.java
  • 将类文件打包归档为jar1.jar,放置在lib文件夹下
jar cvf jar1.jar -C classes3/ .
  • 重用Person类,编写第二个java程序jarDemo2.java,放置在src文件夹下
package cn.xkzhai;
  import com.xkzhai.jar1.Person;
  class Student extends Person{
      private String ID;
  }

  class jarDemo2{
      public static void main(String[] args){
          Student s1 = new Student();
          s1.setAge(20);
          System.out.println(s1.getAge());
      }
  }
  • 编译jarDemo2.java,生成的类文件放置在classes中
javac -cp lib/jar1.jar -d classes src/jarDemo2.java
  • 执行
java -cp lib/jar1.jar;classes cn.xkzhai.jarDemo2
  1. 设计程序,考查修饰符。public -> protected -> default -> private(选做题)
  2. 编写ArrayTool,把冒泡排序,选择排序,二分法查找等打成jar包。
  • 编写java源文件ArrayTool3.java
package com.xkzhai.array;

  class ArrayTool3{
      int[] arrayData;

      public ArrayTool3(){
      }

      public ArrayTool3(int[] arrayData){
          this.arrayData = arrayData;
      }

      //1. 打印数组元素
      public void outArray(){
          for(int i: arrayData){
              System.out.println(i);
          }
      }

      //2. 冒泡排序
      // 5 4 3 2 1
      // 4 3 2 1 5
      // 3 2 1 4 5
      // 2 1 3 4 5
      // 1 2 3 4 5
      public void bubbleSort(){
          for(int i = arrayData.length-1;i>0;i--){
              for(int j=0;j<i;j++){
                  if(arrayData[j]>=arrayData[j+1]){
                      int tmp = arrayData[j];
                      arrayData[j] = arrayData[j+1];
                      arrayData[j+1] = tmp;
                  }
              }
          }
      }

      //3. 选择排序
      //5 4 3 2 1
      //1 5 4 3 2
      //1 2 5 4 3
      //1 2 3 5 4
      //1 2 3 4 5
      public void selectSort(){
          for(int i=0;i<arrayData.length-1;i++){
              for(int j=i;j<=arrayData.length-1;j++){
                  if(arrayData[j]<=arrayData[i]){
                      int tmp = arrayData[j];
                      arrayData[j] = arrayData[i];
                      arrayData[i] = tmp;
                  }
              }
          }
      }

      //4. 选择排序
      public int halfFind(int c){
          int min = 0;
          int max = arrayData.length-1;
          int index = 0;

          while(min<=max){
              index = (min+max)/2;
              if(arrayData[index]>c){
                  max = index-1;
              }
              else if(arrayData[index]<c){
                  min = index+1;
              }
              else{
                  return index;
              }
          }
          return -1;
      }
  }

  class ArrayDemo{
      public static void main(String[] args){
          ArrayTool3 arr = new ArrayTool3(new int[]{1,3,2,20,12});
          arr.outArray();
          arr.bubbleSort();
          arr.outArray();

          ArrayTool3 arr2 = new ArrayTool3(new int[]{1,3,2,20,12,23,21,19});
          arr2.outArray();
          arr2.selectSort();
          arr2.outArray();
          System.out.println(arr2.halfFind(-1));
          System.out.println(arr2.halfFind(12));
      }
  }
  • 编译,打包
javac -d classes4 ArrayTool3.java
  //java -cp classes4 com.xkzhai.array.ArrayDemo
  jar cvf ArrayTool.jar -C classes4/ .
  1. 预习多线程。
进程
  1. 运行时(runtime)的应用程序
  2. 进程之间的内存不是共享(独占)
  3. 进程间通信使用的socket(套接字)
    进程之间内存是隔离的。内存不共享。
多线程
  1. 程序(进程)执行过程中,并发执行的代码段
  2. 线程之间共享内存
  3. 创建灵活响应的桌面程序
  4. 每个运行着的线程对应一个stack(方法栈)
  5. 应用程序至少有一个线程(主线程)
java.lang.Thread
  1. Thread.yield()方法:让当前线程让出CPU抢占权,具有谦逊之意,瞬时的动作
  2. Thread.sleep(int mils)方法:让当前线程休眠指定毫秒数,放弃cpu抢占权,和锁旗标(监控权)没有关系
  3. Thread.join():当前线程等待指定的线程结束后才能继续运行
  4. daemon:守护线程,服务员 Thread.setDaemon(true),为其他线程提供服务的线程。若进程中剩余的线程都是守护线程的话,则进程终止了。
  5. \(--\)
  6. 线程间通信,共享资源的问题。锁, 将并行转串行,防止并发访问。参照物,锁旗标
//同步代码块
 synchronized(object lock){
 ...
 }

同步代码块执行期间,线程始终持有对象的监控权,其他线程处于阻塞状态,只能等待

  1. 同步代码块是以当前所在对象做锁旗标
    synchronized(this) === 同步方法
  2. 同步静态方法,使用类作为同步标记
    public static synchronized xxxx(...){
    }
  3. wait()
    让当前线程进入到锁旗标的等待队列,释放cpu抢占权,还释放锁旗标的监控权。
    wait(1000); 设定等待时间,可以避免死锁
  4. notify()
    唤醒在等待队列中的线程,一次只通知一个线程
  5. notifyAll()
    通知所有线程可以抢占cpu和锁旗标监控权,解决死锁问题
class ThreadDemo10{
    public static void main(String[] args){

        Pool pool = new Pool();

        Productor p1 = new Productor("生产者1",pool);
        p1.setName("p1");
        //Productor p2 = new Productor("生产者2",pool);
        Consumer c1 = new Consumer("消费者1",pool);
        c1.setName("c1");
        Consumer c2 = new Consumer("消费者2",pool);
        c2.setName("c2");

        p1.start();
        //p2.start();
        c1.start();
        c2.start();
    }
}

//生产者
class Productor extends Thread{
    private String name;
    private  Pool pool;
    static int i = 0;

    public Productor(String name, Pool pool){
        this.name = name;
        this.pool = pool;
    }

    public void run(){
        //int i=0;
        while(true){
            pool.add(i++);
        }
    }
}

//消费者
class Consumer extends Thread{
    private String name;
    private Pool pool;
    public Consumer(String name, Pool pool){
        this.name = name;
        this.pool = pool;
    }

    public void run(){
        while(true){
            pool.remove();
        }
    }
}

//票池
class Pool{
    private java.util.List<Integer> list = new java.util.ArrayList<Integer>();
    //容器最大值
    private int MAX = 1;

    //添加元素
    public void add(int n){

        synchronized(this){
            try{
                String name = Thread.currentThread().getName();
                while(list.size() == MAX){
                    System.out.println(name+".wait()");
                    this.wait();
                }
                list.add(n);
                System.out.println(name+"+: "+n);
                System.out.println(name+".notify()");
                this.notifyAll();
            }
            catch(Exception e){
                e.printStackTrace();
            }
        }
    }

    //删除元素
    public int remove(){

        synchronized(this){
            try{
                String name = Thread.currentThread().getName();
                while(list.size() == 0){
                    System.out.println(name+".wait()");
                    this.wait();
                }
                int i = list.remove(0);
                System.out.println(name+"-:"+i);
                System.out.println(name+".notify()");
                this.notifyAll();
                return i;
            }
            catch(Exception e){
                e.printStackTrace();
            }
            return -1;
        }
    }
}
作业
  1. 一共100个馒头,40个工人,每个工人最多能吃3个馒头,使用多线程输出所有工人吃馒头的情况
  2. 5辆汽车过隧道,隧道一次只能通过一辆汽车。每辆汽车通过时间不固定,
    机动车通过时间3秒,三轮车通过时间5秒,畜力车通过时间10秒,5辆车分别是2辆机动车,2辆畜力车,1辆三轮车,通过多线程模拟通过隧道的情况。提示:Car ThreeCar CowCar
  3. 用多线程模拟蜜蜂和熊的关系
    蜜蜂是生产者,熊是消费者,蜜蜂生产蜂蜜是累加的过程,熊吃蜂蜜是批量(满20吃掉)的过程,生产者和消费者之间使用通知方式告知对方,注意不能出现死锁现象。
    100只蜜蜂,每次生产的蜂蜜是1
    熊吃蜂蜜是20(批量的情况)