传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)

day24
1.多线程(JDK5之后的Lock锁的概述和使用)
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第1张图片
 
Lock:
          void lock(): 获取锁。
          void unlock():释放锁。  
  ReentrantLock是Lock的实现类.
 
Re---entrant---Lock
 
SellTicket类
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
 
public class SellTicket implements Runnable {
 
    // 定义票
    private int tickets = 100;
 
    // 定义锁对象
    private Lock lock = new ReentrantLock();
 
    @Override
    public void run() {
        while (true) {
            try {//没有catch的try……finally块
                // 加锁
                lock.lock();
                if (tickets > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName()
                            + "正在出售第" + (tickets--) + "张票");
                }
            } finally {
                // 释放锁
                lock.unlock();
            }
        }
    }
 
}
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第2张图片
 
测试类略,与前一天的一样。
 
2.死锁问题概述和使用
同步的弊端:
          A:效率低
          B:容易产生死锁
  
  死锁:
          两个或两个以上的线程在争夺资源的过程中,发生的一种相互等待的现象。
  
  举例:
          中国人,美国人吃饭案例。
          正常情况:
              中国人:筷子两支
              美国人:刀和叉
          现在:
              中国人:筷子1支,刀一把(在等待美国人的筷子1支)
              美国人:筷子1支,叉一把(在等待中国人的叉一把)
                互相等待,但是互相不会放弃手中的筷子和刀(叉)
 
下面为示例
============================================================
首先,新建一个MyLock 类(作用是创建两个永不变的锁,为DieLock类提供锁,静态是为了调用方便)
public class MyLock {
    // 创建两把锁对象
    public static final Object objA = new Object();
    public static final Object objB = new Object();
    //注意,是public而不是private,否则同一个包的不同类调用不了这两把锁
}
 
==========================================================
接着是核心---DieLock类(选其中一种方法:继承Thread类)
public class DieLock extends Thread {
 
    private boolean flag;//作用是能在测试类中手动规定是执行if语句的内容还是else语句的内容,
//从而方便做出死锁的效果(两个线程,一个设为true,一个设为false,刚好两条不同的路)
 
    public DieLock(boolean flag) {
        this.flag = flag;
    }
 
    @Override
    public void run() {
        if (flag) {
            synchronized (MyLock.objA) {
                System.out.println("if objA");
                synchronized (MyLock.objB) {
                    System.out.println("if objB");
                }
            }
        } else {
            synchronized (MyLock.objB) {
                System.out.println("else objB");
                synchronized (MyLock.objA) {
                    System.out.println("else objA");
                }
            }
        }
    }
}
再次提醒一下关键代码
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第3张图片
 
//其实,synchronized嵌套使用一不小心会有死锁现象
======================================================
最后是测试类
public class DieLockDemo {
    public static void main(String[] args) {
        DieLock dl1 = new DieLock(true);
        DieLock dl2 = new DieLock(false);
 
        dl1.start();
        dl2.start();
    }
}
 
运行示例
 
停不下来(其实是卡住了),成功出现了死锁现象
 
3.生产者消费者问题描述图
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第4张图片
 
4.生产者消费者问题代码1
 
分析:
          资源类:Student    
          设置学生数据:SetThread(生产者)
          获取学生数据:GetThread(消费者)
          测试类:StudentDemo
 
初步想法
先建Student类
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第5张图片
 
然后SetThread类
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第6张图片
 
然后GetThread类
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第7张图片
 
测试类
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第8张图片
 
如上图所示,这样的初始思路是有问题的
 
  问题1:按照思路写代码,发现数据每次都是:null---0
  原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
  如何实现呢?
          在外界把这个数据创建出来,通过构造方法传递给其他的类。
改进后代码如下
===========================
Student类(不变)
public class Student {
    String name;
    int age;
}
==============================
SetThread类
public class SetThread implements Runnable {
 
    private Student s;
 
    public SetThread(Student s) {
        this.s = s;
    }
 
    @Override
    public void run() {
        // Student s = new Student();
        s.name = "林青霞";
        s.age = 27;
    }
 
}
 
=================================
GetThread类
public class GetThread implements Runnable {
    private Student s;
 
    public GetThread(Student s) {
        this.s = s;
    }
 
    @Override
    public void run() {
        // Student s = new Student();
        System.out.println(s.name + "---" + s.age);
    }
 
}
====================================
测试类StudentDemo 
public class StudentDemo {
    public static void main(String[] args) {
        //创建资源
        Student s = new Student();
 
        //设置和获取的类
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
 
        //线程类
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
 
        //启动线程
        t1.start();
        t2.start();
    }
}
 
5.生产者消费者题代码2并解决线程安全问题
上一次的代码有潜在的问题
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第9张图片
 
错乱的姓名年龄匹配
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第10张图片
 
原因
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第11张图片
 
下面总结问题:
 
  问题1:按照思路写代码,发现数据每次都是:null---0
  原因:我们在每个线程中都创建了新的资源,而我们要求的时候设置和获取线程的资源应该是同一个
  如何实现呢?
          在外界把这个数据创建出来,通过构造方法传递给其他的类。
  
  问题2:为了数据的效果好一些,我加入了循环和判断,给出不同的值,这个时候产生了新的问题
          A:同一个数据出现多次
          B:姓名和年龄不匹配
  原因:
          A:同一个数据出现多次
              CPU的一点点时间片的执行权,就足够你执行很多次。
         B:姓名和年龄不匹配
              线程运行的随机性
  线程安全问题:
          A:是否是多线程环境        是
          B:是否有共享数据        是
          C:是否有多条语句操作共享数据    是
  解决方案:
          加锁。
           注意:
             A:不同种类的线程都要加锁。
              B:不同种类的线程加的锁必须是同一把
 
Student类,测试类一样,没变
加锁要注意的问题
当set和get的锁都是new Object()的时候
由于独立都new 了一次,因此锁是不一样的
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第12张图片
 
 
这样还不能达到效果。锁必须是同一把才有意义
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第13张图片
 
上图的s实际上是指通过构造方法传进来的s对象。
 
6.生产者消费者之等待唤醒机制思路图解以及生产者消费者之等待唤醒机制代码实现,分析
上一节的代码其实不太好
 
  问题3:虽然数据安全了,但是呢,一次一大片不好看(获取同一个数据一次而输出多次,也就是set一次却get了多次),我就想依次的一次一个输出(也就是set一次get一次)。
  如何实现呢?
          通过Java提供的等待唤醒机制解决。
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第14张图片
 
等待唤醒:
          Object类中提供了三个方法:
              wait():等待
              notify():唤醒单个线程
              notifyAll():唤醒所有线程
            这三个方法都必须在同步代码块中执行(例如synchronized块)
        为什么这些方法不定义在Thread类中呢?
              这些方法的调用必须通过锁对象调用,而我们刚才使用的锁对象是任意锁对象
              所以,这些方法必须定义在Object类中。
 
以下是生产者消费者之等待唤醒机制代码实现
=====================================
Student类(增加了一个成员变量)
public class Student {
    String name;
    int age;
    boolean flag; // 默认情况是没有数据(false),如果是true,说明有数据
}
======================================
SetThread 类
public class SetThread implements Runnable {
 
    private Student s;
    private int x = 0;
 
    public SetThread(Student s) {
        this.s = s;
    }
 
    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                //判断有没有
                if(s.flag){//如果有数据的话,就wait着
                    try {
                        s.wait(); //t1等着,释放锁
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
 
                if (x % 2 == 0) {
                    s.name = "林青霞";
                    s.age = 27;
                } else {
                    s.name = "刘意";
                    s.age = 30;
                }
                x++; //x=1
 
                //修改标记
                s.flag = true;
                //唤醒线程
                s.notify(); //唤醒t2,唤醒并不表示你立马可以执行,必须还得抢CPU的执行权。
            }
            //t1有,或者t2有
        }
    }
}
=====================================================
GetThread 类
public class GetThread implements Runnable {
    private Student s;
 
    public GetThread(Student s) {
        this.s = s;
    }
 
    @Override
    public void run() {
        while (true) {
            synchronized (s) {
                if(!s.flag){//如果没有数据的话,就等着(没有数据没法get,只能等着)
                    try {
                        s.wait(); //t2就等待了。立即释放锁。将来醒过来的时候,是从这里醒过来的时候
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
 
                System.out.println(s.name + "---" + s.age);
                //林青霞---27
                //刘意---30
 
                //修改标记
                s.flag = false;
                //唤醒线程
                s.notify(); //唤醒t1
            }
        }
    }
}
 
======================================================
测试类 StudentDemo 
public class StudentDemo {
    public static void main(String[] args) {
        //创建资源
        Student s = new Student();
 
        //设置和获取的类
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
 
        //线程类
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
 
        //启动线程
        t1.start();
        t2.start();
    }
}
=====================================================
运行如下
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第15张图片
 
注意:如果没有以下代码
                s.flag = true;
                s.notify(); 
的话,会进入死锁状态
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第16张图片
 
等待唤醒机制代码分析
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第17张图片
==================================================================

 传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第18张图片

 

7.线程的状态转换图及常见执行情况

传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第19张图片

8.线程组的概述和使用

传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第20张图片

 

线程组: 把多个线程组合到一起。
  它可以对一批线程进行分类管理,Java允许程序直接对线程组进行控制。
(MyRunnable类省略)
默认情况下
MyRunnable my = new MyRunnable();
        Thread t1 = new Thread(my, "林青霞");
        Thread t2 = new Thread(my, "刘意");
        // 我不知道他们属于那个线程组,我想知道,怎么办
        // 线程类里面的方法:public final ThreadGroup getThreadGroup()
        ThreadGroup tg1 = t1.getThreadGroup();//查看这个线程属于哪个线程组
        ThreadGroup tg2 = t2.getThreadGroup();
        // 线程组里面的方法:public final String getName()
        String name1 = tg1.getName();//get这个线程组的名称
        String name2 = tg2.getName();
        System.out.println(name1);
        System.out.println(name2);
        // 通过结果我们知道了:线程默认情况下属于main线程组
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第21张图片
 
  // 通过下面的测试,你应该能够看到,默任情况下,所有的线程都属于同一个组
        System.out.println(Thread.currentThread().getThreadGroup().getName());
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第22张图片
那么,我们如何修改线程所在的组呢?
        // 创建一个线程组
        // 创建其他线程的时候,把其他线程的组指定为我们自己新建线程组
// ThreadGroup(String name)
        ThreadGroup tg = new ThreadGroup("这是一个新的组");
 
        MyRunnable my = new MyRunnable();
        // Thread(ThreadGroup group, Runnable target, String name)
        Thread t1 = new Thread(tg, my, "林青霞");
        Thread t2 = new Thread(tg, my, "刘意");
 
        System.out.println(t1.getThreadGroup().getName());
        System.out.println(t2.getThreadGroup().getName());
 
        //通过组名称设置后台线程,表示该组的线程都是后台线程
        tg.setDaemon(true);
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第23张图片
==================================================================
注意:Thread(ThreadGroup group, Runnable target, String name)----三个参数
Thread t1 = new Thread(tg, my, "林青霞");
        Thread t2 = new Thread(tg, my, "刘意");
Thread三个构造方法
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第24张图片
 
9.生产者消费者之等待唤醒机制代码优化
也就是,最终版代码(在Student类中有大改动,然后GetThread类和SetThread类简洁很多)
=======================================
Student类
public class Student {
    private String name;
    private int age;
    private boolean flag; // 默认情况是没有数据,如果是true,说明有数据
 
    public synchronized void set(String name, int age) {
        // 如果有数据,就等待
        if (this.flag) {//锁是this对象
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
 
        // 设置数据
        this.name = name;
        this.age = age;
 
        // 修改标记
        this.flag = true;
        this.notify();
    }
 
    public synchronized void get() {
        // 如果没有数据,就等待
        if (!this.flag) {
            try {
                this.wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
 
        // 获取数据
        System.out.println(this.name + "---" + this.age);
 
        // 修改标记
        this.flag = false;
        this.notify();
    }
}
 
========================================
SetThread 类
public class SetThread implements Runnable {
 
    private Student s;
    private int x = 0;
 
    public SetThread(Student s) {
        this.s = s;
    }
 
    @Override
    public void run() {
        while (true) {
            if (x % 2 == 0) {
                s.set("林青霞", 27);//这里直接调用方法而不用考虑同步的问题了----因为Student类搞定一切同步问题
            } else {
                s.set("刘意", 30);//同上
            }
            x++;
        }
    }
}
 
=========================================================
GetThread 类
public class GetThread implements Runnable {
    private Student s;
 
    public GetThread(Student s) {
        this.s = s;
    }
 
    @Override
    public void run() {
        while (true) {
            s.get();//直接调用方法,无需考虑同步问题
        }
    }
}
======================================================
测试类 StudentDemo (没变)
public class StudentDemo {
    public static void main(String[] args) {
        //创建资源
        Student s = new Student();
 
        //设置和获取的类
        SetThread st = new SetThread(s);
        GetThread gt = new GetThread(s);
 
        //线程类
        Thread t1 = new Thread(st);
        Thread t2 = new Thread(gt);
 
        //启动线程
        t1.start();
        t2.start();
    }
}
=========================================================
 最终版代码中:
          把Student的成员变量给私有的了。
          把设置和获取的操作给封装成了功能,并加了同步。
          设置或者获取的线程里面只需要调用方法即可。
 
10.线程池的概述和使用
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第25张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第26张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第27张图片

public static ExecutorServicenewCachedThreadPool()

  创建一个具有缓存功能的线程池

  缓存:百度浏览过的信息再次访问

public static ExecutorServicenewFixedThreadPool(intnThreads)

  创建一个可重用的,具有固定线程数的线程池

public static ExecutorServicenewSingleThreadExecutor()

  创建一个只有单线的线程池,相当于上个方法的参数是1 

 

==============================================
  线程池的好处:线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。
  
  如何实现线程的代码呢?
          A:创建一个线程池对象,控制要创建几个线程对象。
              public static ExecutorService newFixedThreadPool(int nThreads)
          B:这种线程池的线程可以执行:
             可以执行Runnable对象或者Callable对象代表的线程
              做一个类实现Runnable接口。
          C:调用如下方法即可
               Future submit(Runnable task)
             Future submit(Callable task)
         D:我就要结束,可以吗?
             可以。
=====================================
代码区
首先,MyRunnable类
public class MyRunnable implements Runnable {
 
    @Override
    public void run() {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
    }
 
}
======================================
ExecutorsDemo 类
public class ExecutorsDemo {
    public static void main(String[] args) {
        // 创建一个线程池对象,控制要创建几个线程对象
        // public static ExecutorService newFixedThreadPool(int nThreads)
        ExecutorService pool = Executors.newFixedThreadPool(2);
 
        // 可以执行Runnable对象或者Callable对象代表的线程
        pool.submit(new MyRunnable());
        pool.submit(new MyRunnable());
 
        //结束线程池
        pool.shutdown();
    }
}
===========================================
如果没有   pool.shutdown(); ----根本停不下来
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第28张图片
 
如果有  pool.shutdown();---可以停下来
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第29张图片
 
11.多线程方式3的思路及代码实现(先忽略泛型)
  多线程实现的方式3:
       A:创建一个线程池对象,控制要创建几个线程对象。
              public static ExecutorService newFixedThreadPool(int nThreads)
          B:这种线程池的线程可以执行:
              可以执行Runnable对象或者Callable对象代表的线程
              做一个类实现Runnable接口。
          C:调用如下方法即可
              Future submit(Runnable task)
              Future submit(Callable task)
         D:我就要结束,可以吗?
             可以。
 ==============================================
callable---是接口,有返回值,而且依赖于线程池才能使用,一般很少用
 
Callable:是带泛型的接口。
这里指定的泛型其实是call()方法的返回值类型。
MyCallable 类
public class MyCallable implements Callable {
 
    @Override
    public Object call() throws Exception {
        for (int x = 0; x < 100; x++) {
            System.out.println(Thread.currentThread().getName() + ":" + x);
        }
        return null;
    }
 
}
================================================
测试类
 
public class CallableDemo {
    public static void main(String[] args) {
        //创建线程池对象
        ExecutorService pool = Executors.newFixedThreadPool(2);
 
        //可以执行Runnable对象或者Callable对象代表的线程
        pool.submit(new MyCallable());
        pool.submit(new MyCallable());
 
        //结束
        pool.shutdown();
    }
}
=================================================
12.多线程方式3的求和案例(用上泛型和返回值)
 
MyCallable 类
新建界面修改一下T
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第30张图片
 
public class MyCallable implements Callable<Integer> {
 
    private int number;//限定范围的变量
 
    public MyCallable(int number) {
        this.number = number;
    }
 
    @Override
    public Integer call() throws Exception {
        int sum = 0;
        for (int x = 1; x <= number; x++) {
            sum += x;
        }
        return sum;
    }
 
}
====================================
测试类

传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第31张图片

public class CallableDemo {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        // 创建线程池对象
        ExecutorService pool = Executors.newFixedThreadPool(2);
 
        // 可以执行Runnable对象或者Callable对象代表的线程
        Future f1 = pool.submit(new MyCallable(100));
        Future f2 = pool.submit(new MyCallable(200));
 
        // V get()
        Integer i1 = f1.get();
        Integer i2 = f2.get();
 
        System.out.println(i1);
        System.out.println(i2);
 
        // 结束
        pool.shutdown();
    }
}
=============================================================
13.匿名内部类的方式实现多线程程序
 
匿名内部类的格式:
          new 类名或者接口名( ) {
              重写方法;
          };
          本质:是该类或者接口的子类对象
===============================================
public class ThreadDemo {
    public static void main(String[] args) {
        // 继承Thread类来实现多线程
        new Thread() {
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println(Thread.currentThread().getName() + ":"
                            + x);
                }
            }
        }.start();
 
        // 实现Runnable接口来实现多线程
        new Thread(new Runnable() {
            @Override
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println(Thread.currentThread().getName() + ":"
                            + x);
                }
            }
        }) {
        }.start();
 
        // 更有难度的
        new Thread(new Runnable() {//实际上是匿名内部类的嵌套??
            @Override
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println("hello" + ":" + x);
                }
            }
        }) {
            public void run() {
                for (int x = 0; x < 100; x++) {
                    System.out.println("world" + ":" + x);
                }
            }
        }.start();
    }
}
=======================================================
以下是解析
可以先写以下框架在扩充代码
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第32张图片
 
匿名内部类的嵌套???我也不清楚,视频里也没说,不过应该是
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第33张图片
子类重写run方法
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第34张图片
以下是一个复杂的,只有面试题才会出的恶性写法
这个子类对象继承了Thread类而且重写父类的run()方法,同时还实现了Runnable接口同时重写了接口中的run()方法
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第35张图片
 
那么问题来了,究竟执行哪个呢?答案是"world"这个run方法(用单词hello和world是为了好区分)
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第36张图片
14.定时器的概述和使用
 
  定时器:可以让我们在指定的时间做某件事情,还可以重复的做某件事情。
  依赖Timer和TimerTask这两个类:
  Timer:定时
          public Timer()
          public void schedule(TimerTask task,long delay)
          public void schedule(TimerTask task,long delay,long period)
          public void cancel()
  TimerTask:任务
在开发中一般不会用Timer,因为太弱,开发中一般用框架(见下图)
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第37张图片
 
===================================
public class TimerDemo {
    public static void main(String[] args) {
        // 创建定时器对象
        Timer t = new Timer();
        // 3秒后执行爆炸任务
        // t.schedule(new MyTask(), 3000);
        //结束任务
        t.schedule(new MyTask(t), 3000);
    }
}
 
// 做一个任务
class MyTask extends TimerTask {
 
    private Timer t;
 
    public MyTask(){}
 
    public MyTask(Timer t){
        this.t = t;
    }
 
 
 
    @Override
    public void run() {
        System.out.println("beng,爆炸了");
        t.cancel();
    }
 
}
=============================================
注意,cancel方法放在run方法执行
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第38张图片
 
如果要不止炸一次怎么办??
下面--------
定时任务的多次执行代码体现
public class TimerDemo2 {
    public static void main(String[] args) {
        // 创建定时器对象
        Timer t = new Timer();
        // 3秒后执行爆炸任务第一次,如果不成功,每隔2秒再继续炸
        t.schedule(new MyTask2(), 30002000);
    }
}
 
// 做一个任务
class MyTask2 extends TimerTask {//同一个包下MyTask类只有一个,所以改为MyTask2
    @Override
    public void run() {
        System.out.println("beng,爆炸了");
    }
}
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第39张图片
15.案例---定时删除指定的带内容目录
需求:在指定的时间删除我们的指定目录(你可以指定c盘,但是我不建议,我使用项目路径下的demo)
=======================================================
class DeleteFolder extends TimerTask {
 
    @Override
    public void run() {
        File srcFolder = new File("demo");
        deleteFolder(srcFolder);
    }
 
    // 递归删除目录
    public void deleteFolder(File srcFolder) {
        File[] fileArray = srcFolder.listFiles();
        if (fileArray != null) {//使用for循环必须考虑这个问题
            for (File file : fileArray) {
                if (file.isDirectory()) {
                    deleteFolder(file);//递归
                } else {
                    System.out.println(file.getName() + ":" + file.delete());//其实这里可以直接 file.delete();输出是为了方便查看结果
                }
            }
            System.out.println(srcFolder.getName() + ":" + srcFolder.delete());//输出原因同上
        }
    }
}
 
public class TimerTest {
    public static void main(String[] args) throws ParseException {
        Timer t = new Timer();
 
        String s = "2014-11-27 15:45:00";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date d = sdf.parse(s);
 
        t.schedule(new DeleteFolder(), d);
    }
}
===========================================================
16.多线程常见的面试题
    1:多线程有几种实现方案,分别是哪几种?
    两种。
 
    继承Thread类
    实现Runnable接口
 
    扩展一种:实现Callable接口。这个得和线程池结合。(一般可以不答)
 
  2:同步有几种方式,分别是什么?
    两种。
 
    同步代码块
    同步方法
 
  3:启动一个线程是run()还是start()?它们的区别?
    start();
 
    run():封装了被线程执行的代码,直接调用仅仅是普通方法的调用
    start():启动线程,并由JVM自动调用run()方法
 
  4:sleep()和wait()方法的区别
    sleep():必须指时间;不释放锁
    wait():可以不指定时间,也可以指定时间;释放锁
 
  5:为什么wait(),notify(),notifyAll()等方法都定义在Object类中
    因为这些方法的调用是依赖于锁对象的,而同步代码块的锁对象是任意锁。
    而Object代码任意的对象,所以,定义在这里面。
 
  6:线程的生命周期图
    新建 -- 就绪 -- 运行 -- 死亡
    新建 -- 就绪 -- 运行 -- 阻塞 -- 就绪 -- 运行 -- 死亡
    建议:画图解释。
 
17.面向对象的常见设计原则概述
 
面向对象思想设计原则
•在实际的开发中,我们要想更深入的了解面向对象思想,就必须熟悉前人总结过的面向对象的思想的设计原则
•单一职责原则
•开闭原则
•里氏替换原则
•依赖注入原则
•接口分离原则
•迪米特原则
 
l单一职责原则
•其实就是开发人员经常说的”高内聚,低耦合”
•也就是说,每个类应该只有一个职责,对外只能提供一种功能,而引起类变化的原因应该只有一个。在设计模式中,所有的设计模式都遵循这一原则。
 
l开闭原则
•核心思想是:一个对象对扩展开放,对修改关闭。
•其实开闭原则的意思就是:对类的改动是通过增加代码进行的,而不是修改现有代码。
•也就是说软件开发人员一旦写出了可以运行的代码,就不应该去改动它,而是要保证它能一直运行下去,如何能够做到这一点呢?这就需要借助于抽象和多态,即把可能变化的内容抽象出来,从而使抽象的部分是相对稳定的,而具体的实现则是可以改变和扩展的。
l里氏替换原则
•核心思想:在任何父类出现的地方都可以用它的子类来替代。
•其实就是说:同一个继承体系中的对象应该有共同的行为特征。
 
l依赖注入原则
•核心思想:要依赖于抽象,不要依赖于具体实现。
•其实就是说:在应用程序中,所有的类如果使用或依赖于其他的类,则应该依赖这些其他类的抽象类,而不是这些其他类的具体类。为了实现这一原则,就要求我们在编程的时候针对抽象类或者接口编程,而不是针对具体实现编程。
l接口分离原则
•核心思想:不应该强迫程序依赖它们不需要使用的方法。
•其实就是说:一个接口不需要提供太多的行为,一个接口应该只提供一种对外的功能,不应该把所有的操作都封装到一个接口中。
l迪米特原则
•核心思想:一个对象应当对其他对象尽可能少的了解
•其实就是说:降低各个对象之间的耦合,提高系统的可维护性。在模块之间应该只通过接口编程,而不理会模块的内部工作原理,它可以使各个模块耦合度降到最低,促进软件的复用
18.设计模式的概述和分类
l设计模式概述
•设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。
•设计模式不是一种方法和技术,而是一种思想
•设计模式和具体的语言无关,学习设计模式就是要建立面向对象的思想,尽可能的面向接口编程,低耦合,高内聚,使设计的程序可复用
•学习设计模式能够促进对面向对象思想的理解,反之亦然。它们相辅相成
 
l设计模式的几个要素
•名字 必须有一个简单,有意义的名字
•问题 描述在何时使用模式
•解决方案 描述设计的组成部分以及如何解决问题
•效果 描述模式的效果以及优缺点
l设计模式的分类
创建型模式 对象的创建
结构型模式 对象的组成(结构)
行为型模式 对象的行为
 
常见23个设计模式

创建型模式:简单工厂模式,工厂方法模式,抽象工厂模式,建造者模式,原型模式,单例模式。(6个)

结构型模式:外观模式、适配器模式、代理模式、装饰模式、桥接模式、组合模式、享元模式。(7个)

行为型模式:模版方法模式、观察者模式、状态模式、职责链模式、命令模式、访问者模式、策略模式、备忘录模式、迭代器模式、解释器模式。(10个)

19.简单工厂模式概述和使用
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第40张图片
猫狗举例
==================
先不考虑设计模式的话,
先建一个Animal抽象类
public abstract class Animal {
    public abstract void eat();
}
==================
Dog类
public class Dog extends Animal {
 
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
 
}
======================
Cat类
public class Cat extends Animal {
 
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
 
}
===========================
测试类
public class AnimalDemo {
    public static void main(String[] args) {
        // 具体类调用
        Dog d = new Dog();
        d.eat();
        Cat c = new Cat();
        c.eat();
        System.out.println("------------");
}
=======================================
但是在实际开发中,创建一个对象可能没那么容易,所以new一个对象的过程交给一个单独的类来做
即在同一个包下新建一个工厂类专门生产动物对象
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第41张图片
public class AnimalFactory {
 
    private AnimalFactory() {
    }
 
     public static Dog createDog() {
     return new Dog();
     }
    
     public static Cat createCat() {
     return new Cat();
     }
}
=========================
测试类测试代码
 
        // 工厂有了后,通过工厂给造
         Dog dd = AnimalFactory.createDog();
         Cat cc = AnimalFactory.createCat();
         dd.eat();
         cc.eat();
         System.out.println("------------");
==================================
对工厂类进行改进
public class AnimalFactory {
 
    private AnimalFactory() {
    }
 
    public static Animal createAnimal(String type) {
        if ("dog".equals(type)) {
            return new Dog();
        } else if ("cat".equals(type)) {
            return new Cat();
        } else {
            return null;//不能漏
        }
    }
}
=================================
测试类测试代码
// 工厂改进后
        Animal a = AnimalFactory.createAnimal("dog");//只能用Animal接收
        a.eat();
        a = AnimalFactory.createAnimal("cat");
        a.eat();
 
        // NullPointerException
        a = AnimalFactory.createAnimal("pig");
        if (a != null) {//防止空指针异常
            a.eat();
        } else {
            System.out.println("对不起,暂时不提供这种动物");
        }
 
=======================================
 
20.工厂方法模式的概述和使用
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第42张图片
 
新建一个包
然后先写Animal类(抽象类)
public abstract class Animal {
    public abstract void eat();
}
====================================
然后写一个总的工厂接口Factory
public interface Factory {
    public abstract Animal createAnimal();
}
===================================
接着,新建一个空的测试类,假如有需求:我要买只狗
那么,首先需要有Dog类
public class Dog extends Animal {
 
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
 
}
====================================
然后,建一个生产狗的工厂类
public class DogFactory implements Factory {
 
    @Override
    public Animal createAnimal() {//多态
        return new Dog();
    }
 
}
=======================================
在测试类中
public static void main(String[] args) {
        // 需求:我要买只狗
        Factory f = new DogFactory();
        Animal a = f.createAnimal();
        a.eat();
        System.out.println("-------");
    }
========================================
接着,我要买只猫,同理
猫类
public class Cat extends Animal {
 
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
 
}
 
====================================
猫工厂
public class CatFactory implements Factory {
 
    @Override
    public Animal createAnimal() {
        return new Cat();
    }
 
}
 
=================================
测试类
public class AnimalDemo {
    public static void main(String[] args) {
        // 需求:我要买只狗
        Factory f = new DogFactory();
        Animal a = f.createAnimal();
        a.eat();
        System.out.println("-------");
 
        //需求:我要买只猫
        f = new CatFactory();
        a = f.createAnimal();
        a.eat();
    }
}
 
==========================================================
21.单例模式之饿汉式
饿汉的意思:类一加载就造对象
引入:先新建一个空的Student类
测试
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第43张图片
单例模式:保证类在内存中只有一个对象。
  
  如何保证类在内存中只有一个对象呢?
          A:把构造方法私有
          B:在成员位置自己创建一个对象
          C:通过一个公共的方法提供访问
===============================
Student类
public class Student {
    // 构造私有
    private Student() {
    }
 
    // 自己造一个
    // 静态方法只能访问静态成员变量,加静态
    // 为了不让外界直接访问修改这个值,加private
    private static Student s = new Student();
 
    // 提供公共的访问方式
    // 为了保证外界能够直接使用该方法,加静态
    public static Student getStudent() {
        return s;
    }
}
===============================
测试类
public class StudentDemo {
    public static void main(String[] args) {
        // Student s1 = new Student();
        // Student s2 = new Student();
        // System.out.println(s1 == s2); // false
 
        // 通过单例如何得到对象呢?
 
        // Student.s = null;
 
        Student s1 = Student.getStudent();
        Student s2 = Student.getStudent();
        System.out.println(s1 == s2);
 
        System.out.println(s1); // null,cn.itcast_03.Student@175078b
        System.out.println(s2);// null,cn.itcast_03.Student@175078b
    }
}
============================================
 
注意这行代码
 private static Student s = new Student();
没有private会很危险,会导致同一个包的其它类修改s的值
而static则保证个体Student()方法的执行(因为这个方法是静态的)
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第44张图片
成功运行单例模式
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第45张图片
21.单例模式之懒汉式
 
  单例模式:
          饿汉式:类一加载就创建对象
          懒汉式:用的时候,才去创建对象
==============================
先创一个Teacher类
public class Teacher {
    private Teacher() {
    }
 
    private static Teacher t = null;
 
    public synchronized static Teacher getTeacher() {
        if (t == null) {//当t为null时才去创建
            t = new Teacher();
        }
        return t;
    }
}
 
=========================================
测试类
public class TeacherDemo {
    public static void main(String[] args) {
        Teacher t1 = Teacher.getTeacher();//t为null,因此创建对象
        Teacher t2 = Teacher.getTeacher();//前面已经创建对象了,这一次直接用那个对象
        System.out.println(t1 == t2);
        System.out.println(t1); // cn.itcast_03.Teacher@175078b
        System.out.println(t2);// cn.itcast_03.Teacher@175078b
    }
}
=========================================
注意:
 
  面试题:单例模式的思想是什么?请写一个代码体现
  
          开发:饿汉式(是不会出问题的单例模式)
          面试:懒汉式(可能会出问题的单例模式)
              A:懒加载(延迟加载)    
              B:线程安全问题
                  a:是否多线程环境    是
                  b:是否有共享数据    是
                  c:是否有多条语句操作共享数据     是
 
下图表示Teacher类的方法符合出现线程安全问题的条件
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第46张图片
 
改进关键:synchronized
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第47张图片
 
22.单例模式的Java代码体现Runtime类
=====================================
Runtime源码
/*
 * class Runtime {
 *         private Runtime() {}
 *         private static Runtime currentRuntime = new Runtime();
 *         public static Runtime getRuntime() {
 *           return currentRuntime;
 *       }
 * }
 */
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第48张图片
===========================================
Runtime:每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其运行的环境相连接。
  exec(String command)
=================================================
public class RuntimeDemo {
    public static void main(String[] args) throws IOException {
        Runtime r = Runtime.getRuntime();
        // r.exec("notepad");
        // r.exec("calc");
//        r.exec("shutdown -s -t 10000");
        r.exec("shutdown -a");
    }
}
================================================
一些解析
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第49张图片
 
一运行
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第50张图片
 
shutdown -a 取消关机
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第51张图片
 

其实简单来讲就是以下作用
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第52张图片
 
day24笔记补充
等待唤醒机制改进该程序,让数据能够实现依次的出现
                wait()
                notify()
                notifyAll() (多生产多消费)
特别注意单例模式  
 单例模式(掌握)
            a:饿汉式
            b:懒汉式
 
Runtime
        JDK提供的一个单例模式应用的类。
        还可以调用dos命令
 

day25

1.GUI概述和GUI与CLI的区别
 
day25
 
1.GUI概述和GUI与CLI的区别
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第53张图片
 
2.java.awt和javax.swing包的区别

Java为GUI提供的对象都存在java.Awt和javax.Swing两个包中。

 

 

java.awt:Abstract Window ToolKit (抽象窗口工具包),需要调用本地系统方法实现功能。属重量级控件。
 
javax.swing:在AWT的基础上,建立的一套图形界面系统,其中提供了更多的组件,而且完全由Java实现。增强了移植性,属轻量级控件。

 

javax--- java扩展包
 
轻量级(移植性好),重量级(移植性差)说的是与系统的关联性的大小
 
3.GUI中组件继承图
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第54张图片
 
那么,从哪里学起呢??
Component??Container??
都不是,应该从Frame学起。
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第55张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第56张图片
 
Frame继承的方法太多了,,,,但是Frame本身的方法不多。
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第57张图片
 
4.HelloWorld窗体案例
===============================================
public class FrameDemo {
    public static void main(String[] args) {
        // 创建窗体对象
        // Frame f = new Frame();
        // Frame(String title)
        Frame f = new Frame("林青霞");//设置窗体标题可以用构造方法
 
        // 设置窗体标题
        f.setTitle("HelloWorld");//设置窗口标题的第二个方法
        // 设置窗体大小
        f.setSize(400, 300); // 单位:像素
        // 设置窗体位置(就是设置程序一运行就弹出窗口的位置,默认左上角)
        f.setLocation(400, 200);
 
        // 调用一个方法,设置让窗体可见
        // f.show();//已过时
        f.setVisible(true);//setVisible一般放在最后写,因为设置好窗体才看到窗体比较好(就好像穿好衣服化好妆出门才好)
 
        // System.out.println("helloworld");
    }
}
==================================================
以下是一些解析以及注意的问题
窗体直接点右上角(如图红色关闭区域)关闭不了,而是要强制关闭程序才可以。
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第58张图片
 
窗体太小,调大一点
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第59张图片
 
改变打开时窗体弹出的位置
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第60张图片
 
5.优化HelloWorld窗体案例代码
public class FrameDemo2 {
    public static void main(String[] args) {
        // 创建对象
        Frame f = new Frame("方法调用的前后关系");
 
        // f.setVisible(true);
        // try {
        // Thread.sleep(3000);//让线程睡一会的目的就是说setVisible要放到最后而不要放在前面,也就是先设置窗体位置大小,再显示窗体,就好像先穿衣服,打扮再出门。
        // } catch (InterruptedException e) {
        // e.printStackTrace();
        // }
 
        // // f.setSize(400, 300);
        // // Dimension(int width, int height)
        // Dimension d = new Dimension(400, 300);
        // f.setSize(d);
        // // f.setLocation(400, 200);
        // // Point(int x, int y)
        // Point p = new Point(400, 200);
        // f.setLocation(p);
        // 一个方法搞定
        f.setBounds(400, 200, 400, 300);
 
        f.setVisible(true);
    }
}
============================================
以下是解析
 
 f.setSize(400, 300);
等价于
// Dimension(int width, int height)
        // Dimension d = new Dimension(400, 300);
        // f.setSize(d);
=================================
f.setLocation(400, 200);
等价于
// Point(int x, int y)//point是点的意思
        // Point = new Point(400, 200);
        // f.setLocation(p);
====================================
其实,
// 设置窗体大小
        f.setSize(400, 300); // 单位:像素
        // 设置窗体位置
        f.setLocation(400, 200);
以上两行代码直接可以用一句来代替
// 一个方法搞定
        f.setBounds(400, 200, 400, 300);
 
也就是,最终三行代码搞掂
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第61张图片
 
============================================================
6.事件监听机制原理概述及举例
事件监听机制:
    A:事件源    事件发生的地方
    B:事件    就是要发生的事情
    C:事件处理    就是针对发生的事情做出的处理方案
    D:事件监听 就是把事件源和事件关联起来
 
举例:人受伤事件。
 
    事件源:人(具体的对象)
        Person p1 = new Person("张三");
        Person p2 = new Person("李四");
    事件:受伤
        interface 受伤接口 {
            一拳();
            一脚();
            一板砖();
        }
    事件处理:
        受伤处理类 implements 受伤接口 {
            一拳(){ System.out.println("鼻子流血了,送到卫生间洗洗"); }
            一脚(){ System.out.println("晕倒了,送到通风处"); }
            一板砖(){ System.out.println("头破血流,送到太平间"); }
        }
    事件监听:
        p1.注册监听(受伤接口)
 
7.窗体关闭案例
public class FrameDemo {
    public static void main(String[] args) {
        // 创建窗体对象
        Frame f = new Frame("窗体关闭案例");
 
        // 设置窗体属性
        f.setBounds(400, 200, 400, 300);
 
        // 让窗体关闭
        //事件源---f为事件源
        //事件:对窗体的处理
        //事件处理:关闭窗口(System.exit(0));//退出虚拟机
        //事件监听
        f.addWindowListener(new WindowListener() {//匿名内部类
            @Override
            public void windowOpened(WindowEvent e) {
            }
            
            @Override
            public void windowIconified(WindowEvent e) {
            }
            
            @Override
            public void windowDeiconified(WindowEvent e) {
            }
            
            @Override
            public void windowDeactivated(WindowEvent e) {
           }
          
           @Override
           public void windowClosing(WindowEvent e) {
               System.exit(0);//退出虚拟机
            }
           
            @Override
            public void windowClosed(WindowEvent e) {
           }
            
           @Override
            public void windowActivated(WindowEvent e) {
            }
        });
 
        // 设置窗体可见
        f.setVisible(true);
    }
}
添加事件监听后窗体就可以通过点右上角红色的关闭按钮关闭了
 
8.适配器设计模式讲解
如上面代码可以看见,代码非常多且累赘,那些并不需要(甚至说不应该或者说不能)实现的方法也强迫要实现
 
问题:
 *         接口(方法比较多) -- 实现类(仅仅使用一个,也得把其他的实现给提供了,哪怕是空实现)
 *         太麻烦了。
 * 解决方案:
 *         接口(方法比较多) -- 适配器类(实现接口,仅仅空实现) -- 实现类(用哪个重写哪个)//适配器类实现了分离
================================================
首先新建一个接口
/*
 * 针对用户操作的四种功能
 */
public interface UserDao {
    public abstract void add();
 
    public abstract void delete();
 
    public abstract void update();
 
    public abstract void find();
}
=========================================
然后实现这个接口//这个实现类需要实现全部方法比较麻烦
public class UserDaoImpl implements UserDao {
 
    @Override
    public void add() {
        System.out.println("添加功能");
    }
 
    @Override
    public void delete() {
        System.out.println("删除功能");
    }
 
    @Override
    public void update() {
        System.out.println("修改功能");
    }
 
    @Override
    public void find() {
        System.out.println("查找功能");
    }
 
}
====================================================
测试类中
public class UserDaoDemo {
    public static void main(String[] args) {
        UserDao ud = new UserDaoImpl();
        ud.add();//为了用add方法必须把其余三个方法也实现了,不太合理
    }
}
=====================================================
 
下面,加入适配器
 
先建一个抽象类(适配器)实现UserDao接口(空实现)
public abstract class UserAdapter implements UserDao {
 
    @Override
    public void add() {
    }
 
    @Override
    public void delete() {
    }
 
    @Override
    public void update() {
    }
 
    @Override
    public void find() {
    }
 
}
===========================================================
然后,新建一个类实现UserDao接口,但是不直接实现UserDao,而是继承UserAdapter (因为它实现了那个接口)
public class UserDaoImpl2 extends UserAdapter {
    @Override
    public void add() {
        System.out.println("添加功能");
    }
}
//UserDaoImpl2 比UserDapImpl1简洁多了
================================================
测试类中
public class UserDaoDemo {
    public static void main(String[] args) {
       // UserDao ud = new UserDaoImpl();
       // ud.add();
        // 我没有说我们需要四种功能都实现啊。
        UserDao ud2 = new UserDaoImpl2();
        ud2.add();
    }
}
============================================
附上新建截图
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第62张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第63张图片
 
 
9.适配器类改进窗体关闭案例
原来代码是这样的
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第64张图片
 
用适配器改进后
 
        //用适配器类改进
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
 
简洁了很多
==================================================
 
10窗体添加按钮并对按钮添加事件案例
需求:把按钮添加到窗体,并对按钮添加一个点击事件。
  A:创建窗体对象
  B:创建按钮对象
  C:把按钮添加到窗体
  D:窗体显示
==============================================
public class FrameDemo {
    public static void main(String[] args) {
        // 创建窗体对象
        Frame f = new Frame("添加按钮");
        // 设置属性
        f.setBounds(400, 200, 400, 300);
        // 设置布局为流式布局
        f.setLayout(new FlowLayout());
 
        // 创建按钮对象
        Button bu = new Button("点我啊");
        // bu.setSize(20, 10);
 
        // 把按钮添加到窗体
        f.add(bu);
 
        // 设置窗体可以关闭
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
 
        bu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("你再点试试");
            }
        });
 
        // 窗体显示
        f.setVisible(true);
    }
}
=================================================
下面是一些解析
首先讲一下为什么要f.setLayout(new FlowLayout());
这个涉及窗体布局方案的问题
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第65张图片
 
如果不设置布局的话,默认是边界布局(BoderLayout),但是可以看到,这个按钮填充了整个窗体
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第66张图片
 
因为边界布局分东,南,西,北,中按钮默认在中间,而其它位置有没有任何东西,所以它填充满了
整个窗体
还有名字忘了不要紧,会查就行---setLayout传的参数就是LayoutManager(接口)
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第67张图片
 
 
还有适配器的问题,为什么ActionListener不用适配器呢?---原因是,整个接口本来就只需要实现一个方法,没必要动用到适配器类
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第68张图片
 
运行示例
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第69张图片
 
11.把文本框的值转移到文本域案例
案例预览
需求:如下图
把文本框数据转移到文本域
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第70张图片
 
=======================================================
public class FrameDemo {
    public static void main(String[] args) {
        // 创建窗体对象
        Frame f = new Frame("数据转移");
        // 设置窗体属性和布局
        f.setBounds(400, 200, 400, 300);
        f.setLayout(new FlowLayout());
 
        // 创建文本框
        final TextField tf = new TextField(20);
        // 创建按钮
        Button bu = new Button("数据转移");
        // 创建文本域
        final TextArea ta = new TextArea(10, 40);
 
        // 把组件添加到窗体
        f.add(tf);
        f.add(bu);
        f.add(ta);
 
        // 设置窗体关闭
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
 
        // 对按钮添加事件
        bu.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                // 获取文本框的值
                String tf_str = tf.getText().trim();//trim防止多余空格的输入
                // 清空数据
                tf.setText("");
 
                // 设置给文本域
                // ta.setText(tf_str);
                // 追加和换行
                ta.append(tf_str + "\r\n");//\r\n起到换行的作用,但是直接\n也可以??
 
                //获取光标
                tf.requestFocus();//点击按钮后光标自动回到TextField中
            }
        });
 
        // 设置窗体显示
        f.setVisible(true);
    }
}
=================================================
以下为解析以及一些注意事项
TextField一般用列数那个构造方法
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第71张图片
 
以下的问题在eclipse3.7(JDK1.7)报错,但是在eclipse4.4(JDK1.8)却不报错,我也不知道为什么
附上网上解析:
局部内部类,只能访问被final修饰的局部变量
内部类绝对不能访问非final的成员变量
  因为内部类 也是类,他们实例化后存储在堆中局部变量存储在栈中,所以一般情况而言内部类的声明周期长于局部变量。
试想一个活着的内部类去访问一个声明周期已经结束的局部变量~ 
所以,极有可能的原因是: jdk1.8版本内部类成员变量不用final修饰也能访问
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第72张图片
 
以前关于局部内部类的笔记
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第73张图片
 
解决后
// 创建文本框
        final TextField tf = new TextField(20);
       
        // 创建文本域
        final TextArea ta = new TextArea(10, 40);
=============================================
获取光标的意图
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第74张图片
 
12.通过鼠标移动到按钮上更改背景色案例
需求:
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第75张图片
 
public class FrameDemo {
    public static void main(String[] args) {
        // 创建窗体对象
        final Frame f = new Frame("更改背景色");
        // 设置窗体属性和布局
        f.setBounds(400, 200, 400, 300);
        f.setLayout(new FlowLayout());
 
        // 创建四个按钮
        Button redButton = new Button("红色");
        Button greenButton = new Button("绿色");
        Button buleButton = new Button("蓝色");
 
        // 添加按钮
        f.add(redButton);
        f.add(greenButton);
        f.add(buleButton);
 
        // 设置窗体关闭
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
 
        // 对按钮添加动作事件
        // redButton.addActionListener(new ActionListener() {
        // @Override
        // public void actionPerformed(ActionEvent e) {
        // f.setBackground(Color.RED);
        // }
        // });
 
        // 对按钮添加鼠标点击事件
        // redButton.addMouseListener(new MouseAdapter() {
        // @Override
        // public void mouseClicked(MouseEvent e) {
        // f.setBackground(Color.RED);
        // }
        // });
 
        // 对按钮添加鼠标的进入事件
        redButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                f.setBackground(Color.RED);
            }
        });
 
        redButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                f.setBackground(Color.WHITE);
            }
        });
 
        greenButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                f.setBackground(Color.GREEN);
            }
        });
 
        greenButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                f.setBackground(Color.WHITE);
            }
        });
 
        buleButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                f.setBackground(Color.BLUE);
            }
        });
 
        buleButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                f.setBackground(Color.WHITE);
            }
        });
 
        // 设置窗体显示
        f.setVisible(true);
    }
}
==============================================
解析
代码看着很长,其实很多重复的内容
动作事件和鼠标事件
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第76张图片
 
redButton.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseEntered(MouseEvent e) {
                f.setBackground(Color.RED);
            }
        });
鼠标事件用了适配器,因为原监听器接口要实现的方法挺多
 mouseEntered: 鼠标移动到按钮区域就变颜色(移动到但是没有点按钮)
mouseExited: 鼠标离开按钮区域就变颜色(离开但是没有点按钮)
====================================================
13.如何控制在文本框里面只能输入数字字符案例
需求:
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第77张图片
 
/*
 * 你输入的如果是非数字字符,就取消你键盘录入的效果
 */
public class FrameDemo {
    public static void main(String[] args) {
        // 创建窗体对象并设置属性
        Frame f = new Frame("不能输入非数字字符");
        f.setBounds(400, 200, 400, 300);
        f.setLayout(new FlowLayout());
 
        // 创建Label标签对象
        Label label = new Label("请输入你的QQ号码,不能是非数字,不信你试试");
        TextField tf = new TextField(40);
 
        // 添加到窗体上
        f.add(label);
        f.add(tf);
 
        // 设置窗体关闭
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
 
        // 给文本框添加事件
        tf.addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                // 如果你取得的字符不是数字字符就取消事件
                // 思路:先获取字符,判断字符,取消事件
                // char getKeyChar()  
                char ch = e.getKeyChar();
//                System.out.println(ch);
                if(!(ch>='0' && ch<='9')){
                    e.consume();//取消该键盘录入事件
                }
            }
        });
 
        // 设置窗体可见
        f.setVisible(true);
    }
}
===============================================
以下为解析
keyPressed---keyAdapter接口中
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第78张图片
 
可以看见,有三个方法,所以适配器替代了原来的监听器
 
 
还有,注意几个方法,getKeyChar(),consume() ----都在KeyEvent 类中
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第79张图片
 
consume在代码中意思是取消该事件,让事件不再发生。在本案例中是当检测到非法字符时不输入(忽略输入非法字符)

 

传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第80张图片

14.一级菜单案例

传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第81张图片

需求:

传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第82张图片

/*
 * 一级菜单
 */
public class FrameDemo {
    public static void main(String[] args) {
        // 创建窗体对象并设置属性
        Frame f = new Frame("一级菜单");
        f.setBounds(400, 200, 400, 300);
        f.setLayout(new FlowLayout());
 
        // 创建菜单栏
        MenuBar mb = new MenuBar();
        // 创建菜单
        Menu m = new Menu("文件");
        // 创建菜单项
        MenuItem mi = new MenuItem("退出系统");
 
        // 谁添加谁呢
        m.add(mi);
        mb.add(m);
 
        // 设置菜单栏
        f.setMenuBar(mb);
 
        // 设置窗体关闭
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
 
        mi.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
 
        // 设置窗体可见
        f.setVisible(true);
    }
}
===============================================
一个注意的问题
setMenuBar而不是add
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第83张图片
15.多级菜单案例
需求
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第84张图片
*
 * 多级菜单
 */
public class FrameDemo {
    public static void main(String[] args) {
        // 创建窗体对象并设置属性
        final Frame f = new Frame("多级菜单");
        f.setBounds(400, 200, 400, 300);
        f.setLayout(new FlowLayout());
 
        final String name = f.getTitle();
 
        // 创建菜单栏
        MenuBar mb = new MenuBar();
        // 创建菜单
        Menu m1 = new Menu("文件");
        Menu m2 = new Menu("更改名称");
        // 创建菜单项
        final MenuItem mi1 = new MenuItem("好好学习");
        final MenuItem mi2 = new MenuItem("天天向上");
        MenuItem mi3 = new MenuItem("恢复标题");
        MenuItem mi4 = new MenuItem("打开记事本");
        MenuItem mi5 = new MenuItem("退出系统");
 
        // 谁添加谁呢
        m2.add(mi1);
        m2.add(mi2);
        m2.add(mi3);
 
        m1.add(m2);
        m1.add(mi4);
        m1.add(mi5);
 
        mb.add(m1);
 
        // 设置菜单栏
        f.setMenuBar(mb);
 
        // 设置窗体关闭
        f.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        });
 
        mi1.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                f.setTitle(mi1.getLabel());//getLabel表示这个Item的名称是什么就把它设置为Frame的标题
            }
        });
 
        mi2.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                f.setTitle(mi2.getLabel());
            }
        });
 
        mi3.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                f.setTitle(name);//name为最初的标题
            }
        });
 
        mi4.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Runtime r = Runtime.getRuntime();//打开记事本,单例模式
                try {
                    r.exec("notepad");
                } catch (IOException e1) {
                    e1.printStackTrace();
                }
            }
        });
 
        mi5.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
 
        // 设置窗体可见
        f.setVisible(true);
    }
}
=======================================================
一些注意事项
前面写final String name = f.getTitle();的作用(原因)
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第85张图片
 
初始默认值为"多级菜单",如上图所示,窗体标题已经被改为"天天向上",所以要恢复初始值不能直接getTitle
 
16.Netbeans的概述和使用
首先解决安装问题
安装成功的前提是有JDK
配好环境变量
然后,发现还是安装不了
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第86张图片

 

用命令行
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第87张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第88张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第89张图片
 
然后就可以安装了
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第90张图片
 
NetBeans主要用来做GUI方便,其它并不常用
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第91张图片
 
仅有的优点
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第92张图片
 
拖放使用非常方便
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第93张图片
常用快捷键(不用记)
完成代码:ctrl+\ //任何地方按下此组合键,均会提示相应的参考字段; 
导入所需包:ctrl+shift+i 
格式化代码:alt+shift+F 
psvm+Tab 生成Main方法 
sout + Tab //生成输出语句
 
================================
17.模拟四则运算案例
具体内容看视频
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第94张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第95张图片
 
在NetBeans中需要手动改动的代码
默认是没有标题的,所以编写初始化标题的代码
public NewJFrameDemo() {
        initComponents();
        init();
    }
 
    private void init() {
        this.setTitle("模拟四则运算");
    }
// 红字为手写的方法,初始化标题
====================================================
事件监听的代码(计算器四则运算)
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
        //获取第一个操作数
        String firstNumberString = this.firstNumber.getText().trim();
        //获取运算符
        String selectOperator = this.selectOperator.getSelectedItem().toString();
        //获取第二个操作数
        String secondNumberString = this.secondNumber.getText().trim();
        //        System.out.println(firstNumberString);
        //        System.out.println(selectOperator);
        //        System.out.println(secondNumberString);
 
        int firstNumber = Integer.parseInt(firstNumberString);
        int secondNumber = Integer.parseInt(secondNumberString);
 
        int resultNumber = 0;
 
        switch (selectOperator) {
            case "+":
                resultNumber = firstNumber + secondNumber;
                break;
            case "-":
                resultNumber = firstNumber - secondNumber;
                break;
            case "*":
                resultNumber = firstNumber * secondNumber;
                break;
            case "/":
                resultNumber = firstNumber / secondNumber;
                break;
        }
 
        //把结果赋值给结果框
        this.resultNumber.setText(String.valueOf(resultNumber));
 
 
    }                                        
 
 
然后修改窗体的图标代码
看图就好
首先建一个cn.itcast.util包
Uiutil类
然后建一个resource包,把图标图片放进包里
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第96张图片
Toolkit是抽象类
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第97张图片
在NewJFrame类中改代码
this代表当前对象(窗体)
修改后运行
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第98张图片
再设置一下初始运行时窗体的默认位置为居中
在UiUtil类中
//设置窗体居中
    public static void setFrameCenter(JFrame jf) {
        /*
         思路:
         A:获取屏幕的宽和高
         B:获取窗体的宽和高
         C:(用屏幕的宽-窗体的宽)/2,(用屏幕的高-窗体的高)/2作为窗体的新坐标。
         */
        //获取工具对象
        Toolkit tk = Toolkit.getDefaultToolkit();
 
        //获取屏幕的宽和高
        Dimension d = tk.getScreenSize();
        double srceenWidth = d.getWidth();
        double srceenHeigth = d.getHeight();
 
        //获取窗体的宽和高
        int frameWidth = jf.getWidth();
        int frameHeight = jf.getHeight();
 
        //获取新的宽和高
        int width = (int) (srceenWidth - frameWidth) / 2;
        int height = (int) (srceenHeigth - frameHeight) / 2;
 
        //设置窗体坐标
        jf.setLocation(width, height);
    }
=======================================
在NewJFrame类中
public NewJFrame() {
        initComponents();
        init();
    }
 
    private void init() {
        this.setTitle("模拟四则运算");
        UiUtil.setFrameImage(this,"jjcc.jpg");
        UiUtil.setFrameCenter(this);
    }
 
 
附上UiUtil类
/**
 * 专门做界面效果的类
 *
 * @author Administrator
 */
public class UiUtil {
 
    private UiUtil() {
    }
 
    //修改窗体的图标
    public static void setFrameImage(JFrame jf) {
        //获取工具类对象
        //public static Toolkit getDefaultToolkit():获取默认工具包。 
        Toolkit tk = Toolkit.getDefaultToolkit();
 
        //根据路径获取图片
        Image i = tk.getImage("src\\cn\\itcast\\resource\\user.jpg");
 
        //给窗体设置图片
        jf.setIconImage(i);
    }
 
        public static void setFrameImage(JFrame jf,String imageName) {
        //获取工具类对象
        //public static Toolkit getDefaultToolkit():获取默认工具包。 
        Toolkit tk = Toolkit.getDefaultToolkit();
 
        //根据路径获取图片
        Image i = tk.getImage("src\\cn\\itcast\\resource\\"+imageName);
 
        //给窗体设置图片
        jf.setIconImage(i);
    }
 
    //设置窗体居中
    public static void setFrameCenter(JFrame jf) {
        /*
         思路:
         A:获取屏幕的宽和高
         B:获取窗体的宽和高
         C:(用屏幕的宽-窗体的宽)/2,(用屏幕的高-窗体的高)/2作为窗体的新坐标。
         */
        //获取工具对象
        Toolkit tk = Toolkit.getDefaultToolkit();
 
        //获取屏幕的宽和高
        Dimension d = tk.getScreenSize();
        double srceenWidth = d.getWidth();
        double srceenHeigth = d.getHeight();
 
        //获取窗体的宽和高
        int frameWidth = jf.getWidth();
        int frameHeight = jf.getHeight();
 
        //获取新的宽和高
        int width = (int) (srceenWidth - frameWidth) / 2;
        int height = (int) (srceenHeigth - frameHeight) / 2;
 
        //设置窗体坐标
        jf.setLocation(width, height);
    }
}
================================================
修改UI----皮肤包(略)
如何修改窗体的皮肤
附上MyLookAndFeel 类
=========================================================
//这里面定义了常见的要使用的皮肤的字符串路径。
public abstract class MyLookAndFeel {
    // 系统自带皮肤,5种都能用
    public static String SYS_METAL = "javax.swing.plaf.metal.MetalLookAndFeel";
    public static String SYS_NIMBUS = "com.sun.java.swing.plaf.nimbus.NimbusLookAndFeel";
    // 有个性
    public static String SYS_CDE_MOTIF = "com.sun.java.swing.plaf.motif.MotifLookAndFeel";
    public static String SYS_WINDOWS = "com.sun.java.swing.plaf.windows.WindowsLookAndFeel";
    public static String SYS_WINDOWS_CLASSIC = "com.sun.java.swing.plaf.windows.WindowsClassicLookAndFeel";
    // JIattoo jar包资源
    public static String JTATTOO_ACRYL = "com.jtattoo.plaf.acryl.AcrylLookAndFeel";
    public static String JTATTOO_AERO = "com.jtattoo.plaf.aero.AeroLookAndFeel";
    // 还可以
    public static String JTATTOO_ALUMINUM = "com.jtattoo.plaf.aluminium.AluminiumLookAndFeel";
    // 很喜欢
    public static String JTATTOO_BERNSTEIN = "com.jtattoo.plaf.bernstein.BernsteinLookAndFeel";
    public static String JTATTOO_FAST = "com.jtattoo.plaf.fast.FastLookAndFeel";
    // 有个性
    public static String JTATTOO_HIFI = "com.jtattoo.plaf.hifi.HiFiLookAndFeel";
    public static String JTATTOO_LUNA = "com.jtattoo.plaf.luna.LunaLookAndFeel";
    // 很喜欢
    public static String JTATTOO_MCWIN = "com.jtattoo.plaf.mcwin.McWinLookAndFeel";
    public static String JTATTOO_MINT = "com.jtattoo.plaf.mint.MintLookAndFeel";
    // 有个性
    public static String JTATTOO_NOIRE = "com.jtattoo.plaf.noire.NoireLookAndFeel";
    public static String JTATTOO_SMART = "com.jtattoo.plaf.smart.SmartLookAndFeel";
    // liquidlnf.jar包资源
    // 很喜欢
    public static String LIQUIDINF = "com.birosoft.liquid.LiquidLookAndFeel";
}
========================================================
测试几个看看效果
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第99张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第100张图片
 
最后,对四则运算案例加入校验和提示
代码(绿字为新增代码)
………………………………………………………………………………………………………………………………
………………………………………………省略前面代码……………………………………………………
//获取第二个操作数
        String secondNumberString = this.secondNumber.getText().trim();
        //数据校验,必须是数字字符串
        String regex = "\\d+";
 
        //校验第一个数
        if (!firstNumberString.matches(regex)) {
//            System.out.println("数据不匹配");
            //public static void showMessageDialog(Component parentComponent,Object message)
            JOptionPane.showMessageDialog(this, "第一个操作数不满足要求必须是数字");
            this.firstNumber.setText("");
            this.firstNumber.requestFocus();
            return;//回去吧
        }
 
        if (!secondNumberString.matches(regex)) {
//            System.out.println("数据不匹配");
            //public static void showMessageDialog(Component parentComponent,Object message)
            JOptionPane.showMessageDialog(this, "第二个操作数不满足要求必须是数字");
             this.secondNumber.setText("");
            this.secondNumber.requestFocus();
            return;//回去吧
        }
 //把字符串数据转换为整数
        int firstNumber = Integer.parseInt(firstNumberString);
        int secondNumber = Integer.parseInt(secondNumberString);
…………………………………………省略后面代码…………………………………………………………
…………………………………………………………………………………………………………………………
附:JOptionPane类方法
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第101张图片
 
运行示例
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第102张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第103张图片
 
18.用户登录注册案例
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第104张图片
包结构
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第105张图片
 
pojo包下
User类
public class User {
    private String username;
    private String password;
 
    public User(){}
 
    /**
     * @return the username
     */
    public String getUsername() {
        return username;
    }
 
    /**
     * @param username the username to set
     */
    public void setUsername(String username) {
        this.username = username;
    }
 
    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }
 
    /**
     * @param password the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }
 
 
}
注意:
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第106张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第107张图片
============================================================
dao包下
UserDao接口
 */
public interface UserDao {
 
    /**
     * 这是用户登录功能
     *
     * @param username 用户名
     * @param password 密码
     * @return 登录是否成功
     */
    public abstract boolean login(String username, String password);
 
    /**
     * 这是用户注册功能
     *
     * @param user 被注册的用户信息
     */
    public abstract void regist(User user);
}
=======================================================
dao.impl包下UserDaoImpl类(与IO流的是一样的)
public class UserDaoImpl implements UserDao {
 
    //定义文件
    private static File file = new File("user.txt");
 
    //类加载的时候就把文件创建
    static {
        try {
            file.createNewFile();
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }
 
    @Override
    public boolean login(String username, String password) {
        boolean flag = false;
 
        BufferedReader br = null;
        try {
            br = new BufferedReader(new FileReader(file));
            String line = null;
            while ((line = br.readLine()) != null) {
                String[] datas = line.split("=");
                if (datas[0].equals(username) && datas[1].equals(password)) {
                    flag = true;
                    break;
                }
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                br.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
 
        return flag;
    }
 
    @Override
    public void regist(User user) {
        BufferedWriter bw = null;
        try {
            bw = new BufferedWriter(new FileWriter(file, true));
            bw.write(user.getUsername() + "=" + user.getPassword());
            bw.newLine();
            bw.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                bw.close();
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }
    }
}
=============================================================
19.用户登录注册的界面实现,界面跳转
借助于NetBeans实现
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第108张图片
再修改一下代码
 public LoginFrame() {
        initComponents();
        init();
    }
 
    private void init() {
        this.setTitle("登录界面");
        UiUtil.setFrameCenter(this);
        UiUtil.setFrameImage(this,"user.jpg");
    }
 
注册界面同理,略
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第109张图片
 
接着是界面跳转
dispose----使当前窗体关闭
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第110张图片
 
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第111张图片
 
this.setResizable(false);
 
还有就是让窗体大小不可改变
传智 刘意 2015年Java基础视频-深入浅出精华版 笔记 day24~day26(2016年4月26日13:11:30)_第112张图片
 
 private void init() {
        this.setTitle("登录界面");
        this.setResizable(false);//窗体大小不可改变
        UiUtil.setFrameCenter(this);
        UiUti

你可能感兴趣的:(Java,java基础,java,传智播客)