本部分介绍Java实战经典的第三部分:Java应用程序设计

  主要包括如下几个重点部分:

  重点一:多线程

  重点二:Java常用类库

  重点三:IO操作

  重点四:Java类集框架

  重点五:Java图形界面

  重点六:数据库编程

  重点七:Java新特性:泛型、枚举、Annotation

  重点八:Java反射机制

  重点九:Java网络程序设计

  重点十:Java新IO

  第一部分和第二部分重点介绍Java的基础,尤其是面向对象对象的理念。介绍基础语句、基本数据类型、如何构建类、实例化对象、对象的多态性、接口及抽象类的使用

  第九章:多线程

  本章要点:

  了解:进程和线程的区别、线程的状态变化、多线程操作方法、同步和死锁、线程的生命周期

  掌握:java多线程的实现方式及区别

  进程是代码加载、执行到执行完毕的一个完整过程,这个过程从生命周期上看也是进程产生、发展和消失的过程。由于现代操作系统实行的是分时机制,就是把一段时间分成极短的时间片,然后把时间片分配给各个进程交替执行,但是由于人对极短时间的感应迟钝,所以感觉不到任务是串行的,而是感觉任务是并行的,中间没有停顿。

  线程是比进程还要小的单位,运行一个进程可以产生很多个子线程。这些子线程可以同时运行、同时存在。例如打开一个word程序,word进程中可以存在很多个很小的线程,比如字体检查,线程关掉,进程还可以继续存在。

  使用多线程能让程序运行效率更高。

  JAVA多线程实现

  实现多线程有两种手段,一种是继承Thread类,一种是继承Runnable类

  方法一:继承Thread类

  Thread类在java.lang中定义

  多线程定义语法:

  class  类名称 extends Thread{

  属性;

  方法;

  public void run(){//覆写Thread类中的run方法,此方法是线程主体

  线程主体

  }

};

  调用时候调用Thread类的start()方法

  通过此方法调用时,调用时只能调用一次start()方法,大于一次会报IllegalThreadStatesException

  一般调用是通过Runnable来实现多线程的多次调用

  Runnable是一个接口,只有一个抽象函数publi void run(),需要实现。

  使用方式:

  Class 类名称 implements Runnable

  {

  属性;

  抽象方法;

  public void run(){

  线程主体//覆写Runnable的方法

  }

}

  启动多线程方式还是依靠Thread类,在Thread类中有两个构造方法

  public Thread(Runnable target)和public Thread(Runnable target,String name)

  通过先实例化Thread类,再将Thread类向上转型就可以Runnable实例调用start()方法

  区别与联系:

  Thread类实际上是Runnable类的实现。

  由定义可以看到

  class Thread extends Object implements Runnable

  继承Thread类不能实现资源共享,使用Runnable类好

  有如下两段代码,都是展示Runnable实现多线程的

class ThreadDemo004 implements Runnable{
    public void run(){
    for( int i = 5 ;i < 100&i > 0;i--){
    System.out.println("余票:" + i); 
      }
    }
  }; public class ThreadDemo003 {
  public static void main(String args[]){
  ThreadDemo004 td1 = new ThreadDemo004();
  new Thread(td1).start();
  new Thread(td1).start();
  }
};

上述程序运行结果是: 

余票:5

余票:4
余票:3
余票:2
余票:1
余票:5
余票:4
余票:3
余票:2
余票:1

  也就是没有实现多线程的资源共享,这个例子中,第一个例子开启了一个进程i是局部变量,属于第一个进程的,不可能共享,需要用下面的程序实现。

  另一个程序是:

class ThreadDemo004 implements Runnable{
  private int ticket = 5;
  public void run(){
  for( int i = 5 ;i < 100;i++){
  if(ticket > 0)
  System.out.println("余票:" + ticket--); 
    }
  }
};public class ThreadDemo003 {
  public static void main(String args[]){
  ThreadDemo004 td1 = new ThreadDemo004();
  new Thread(td1).start();
  new Thread(td1).start();
   }
};

 实现Runnable接口相对于Thread类有如下优势:

 

1、 适合多个相同程序代码的线程处理同一资源的情况

2、 避免java单继承带来的缺陷

3、 增强代码健壮性,代码可以被多个线程共享,使代码与数据独立

总之:建议使用Runnable

线程的状态:

  要想实现多线程,必须在主线程(主方法)中创建多个线程对象,线程一般具有5种状态:

创建、就绪、运行、阻塞、终止

1、 创建状态

在程序中用构造方法创建一个线程对象后,新的线程就处于创建状态,此时有相应的内存空间和其他资源,但处于不可运行状态。新建一个线程可以使用Thread类进行。如Thread a = new Thread

2、 就绪状态

创建完后,使用start()方法启动,启动完线程后,程序就进入就绪状态,线程进入线程队列排队,等待CPU服务

3、 运行状态

当就绪状态的线程获得CPU资源后,进入运行状态,自动调用该线程的run()方法,run()方法定义了改方法的的操作和功能

4、 堵塞状态

正在执行的线程遇到突发情况,被人为挂起,或遇到耗时的输入输出操作,将让出CPU,并暂时中止执行,进入堵塞状态,也可以叫暂停状态。在可执行的状态下,调用sleep(),suspend(),wait()方法,都可以进入堵塞状态。堵塞状态时,线程不能进入线程队列排队,只有解除堵塞状态后,才可以转入就绪状态。

5、 死亡状态

程序执行完毕,或调用stop()方法后,线程将死亡,处于死亡状态的线程,不具有继续执行的能力。线程死亡也意味着其占用的资源被回收

线程的操作方法

线程的主要操作方法在Thread类中,并不在Runnable中

介绍常用的线程方法:

1、 取得和设置线程名称

getName()方法获取名称,setName()设置名称。线程名称一般在启动时候设置,但允许运行时候进行设置。允许两个Thread对象有相同名称,但尽量避免发生。如果没有设置名称,系统会自动为线程分配名称。主方法也是一个线程。

JAVA程序每次运行时候,至少启动两个线程,一个是main线程,一个是垃圾回收线程

2、 判断线程是否启动

使用isAlive方法,通过Thread类的start()方法通知CPU这个线程已经准备好启动,然后等待CPU分配资源。运行此线程,java通过isAlive()方法来测试进程是否已经在启动而且仍然在启动。

由于线程操作的不确定性,主线程可能比其他进程先执行完。。。奇怪。。。

3、线程的强制运行

使用join()方法能够使一个线程强制运行。线程强制运行期间,其他线程禁止运行,直到此线程运行结束。

4、线程的休眠

使用Thread.sleep()进行休眠,sleep()方法中间的参数是时间,单位是毫秒。Ms

5、中断线程

使用方法interrupt()方法中断线程

6、设置后台进程

使用方法setDaemon()方法

7、线程的优先级

线程操作时,所有的线程就已经处于就绪状态,那么哪个线程先运行是个问题。解决方法是使用优先级策略,优先级高的优先可能被处理。

使用方法setPriority()

Max :10

Norm :5

Min:1

实际使用时候,并非设置优先级高就一定先执行,具体由CPU调度执行

主方法的优先级

使用方法getPriority

8、线程的礼让

使用方法yield()

同步与死锁

使用Runnable进行多线程处理的特点是资源被多个线程共享。这样可能导致一个问题是多个线程操作同一个资源的同步问题。比如卖票为负数的问题。

解决方法是使用同步方法:思想是,同一个资源被某个线程占用时候,其他线程禁止访问,直到操作结束。具体操作方法上有两种:1

1、  使用同步代码块。2、使用同步方法

方法一:使用同步代码块

使用关键字synchronized(同步对象){

         需要同步的代码块

}

使用synchronized时候,需要设置同步对象,一般使用this,设置当前操作对象为同步对象,就是this表示后面的大括号部分,作为一个整体,设置为同步对象。

方法二:使用同步方法

同步方法是将代码块包起来变成一个方法而已。语法如下:

Synchronized 方法返回值 方法名称(参数列表){

}

Synchronized是本书的最后一个关于方法的关键字。

访问权限{public,default,protected,private}【final,static,synchronized】

【返回值类型,void】 方法名称(参数类型 参数名称)【throws Exception1,Exception2】{

         Return 返回值|返回调用

}

死锁:

死锁是两个线程都以对方完成为条件才能继续下去,也就是都等待对方完成。

死锁是资源同步过多造成的。

泛型

泛型从字面理解是泛泛的数据类型,就是数据类型是不固定的。什么时候不固定呢?定义变量时候可以定义一个返回类型不固定的类型,具体使用时候,再根据实际情况返回所需要的类型。

泛型可以解决安全性问题。

使用语法:

在类声明时候通过一个泛类型标识表示类的某个属性的类型,或者某个方法的返回值及参数类型。这样在类实例化或声明时候,指定好类型即可。

泛型类的定义:

访问权限 class 类名称 <泛型类型标识1,泛型类型标识2,泛类型标识3>

访问权限 泛类型标识 变量名称;

访问权限 泛类型标识 方法名称(){}

访问权限 泛类型标识 返回值类型 方法名称(泛类型标识 变量名称){
}

例如

         class  JiaWei<泛型类型>{

         修饰符 泛型类型 属性名称

         public 泛型类型 setter(){}

         public void 泛型类型 getter(泛型类型 变量)

}

泛型对象定义

类名称<具体类> 对象名 = new 类名称<具体类>()

class Point < T >{
     private T var;
     public T getVar(){
        return var;
     }
     public void setVar(T var){
        this.var = var;
     }
}

<T>表示泛型,类型T是由外部调用本类时候指定的,可以使用任意字母表示<A>、<B>等等,T是type的首字母大写,这样比较好理解。

加入泛型的最大好处就是避免了类的转换异常

泛型应用中的构造方法

构造方法可以为类中的属性初始化,如果类中的属性类型通过泛型指定,而又需要通过属性设置构造内容时,构造方法和之前并没有异同,不需要像声明类那样指定泛型

访问权限 构造方法(泛型类型 参数名称)

指定类的多个泛型

类中涉及到的属性可能不止一个类型,可以在声明类的时候加上多个泛型。

class TangBao<K,V>

在实例化泛型时候最好同时写出实例化对象的泛型类型,否则会有安全警告

比如有个类class TangBao<K,V>

在主类实例化时候:可以这样写Tangbao jiawei = new Tangbao();

这样的写法是不安全的。要指明类型带上泛型。

TangBao<String,Integer>jiawei = new TanBao<String,Integer>();

也可以不具体指明是哪种,指出是Object统一接收。这样的好处是虽然没有写明是哪个,但是可以消除警告信息。

通配符:

在泛型类型中,可以设置通配符来接收任意类型的对象。通配符是:?

泛型传递后面跟上?表示接收任意类型对象

泛型的范围:

主要从继承 的角度来限定对象传递的范围

使用两个关键字:一个是super,一个是extends

Super是规定对象传递下限的,extends规定上限的

定义上限:

类的定义:访问权限 类名称 <泛型标识 extends 类名称>

对象的定义:类名称<? Extends 类名称> 对象名

设置下限

类定义:访问权限 类名称<泛型标识 extends 类>{}

对象声明:类名称<泛型标识 ? super 类> 对象名

泛型与子类继承的限制

一个子类可以通过对象的多态性为其父类实例化,在泛型中,子类的泛型类型,无法使用父类的泛型来接收。如Info<String>不能用Info<Object>

泛型接口

也可以定义泛型接口

访问权限 interface 接口名称<泛型标识>.

本章是将泛型重新应用于类、对象、方法、接口的定义上,使
相应的处理能够一般化

Annotation注释

本章是讲在程序中嵌入注释的,与之前的//形式注释不同,这种注释可以明确在程序中展现,并且可以在出错时候打印出来,在控制台展现。

@Override用于覆写父类方法

@Deprecated用于声明一个不建议使用的方法

使用后不建议使用的方法名称上会被打上横线

@Deprecated也可以用于类上面

@SuppressWarnings压制警告,例如声明一个类时候,没有声明泛型,就会出现警告,使用该注释可以压制警告 

使用语法:

@SuppressWarnings({“unchecked”,“deprecation”})

被压制的警告有如下:

deprecation  使用了不赞成使用的类或方法时的警告

unchecked       执行了未检查的转换时警告,例如泛型操作中没有指定泛型类型

fallthrough       switch操作时case后未加入break操作,导致程序继续执行其他case语句时出现的警告

path          设置了一个错误的类路径、源文件

serial    当在可序列化的类上缺少serialVersionUID定义时的警告

finally   任何finally子句不能正常完成时的警告

all 以上所有警告

反射机制

反射机制是正常机制的逆行

例如声明了一个类Person后,可以通过对象反向找出实例化对应的类名

比如per是Person类的一个对象,调用方法getClass(),per.getClass()将反向获得类,再使用getName()方法获取类名

per.getClass().getName()

getClass是Object类的方法

正常方式:引入需要的“包.类”名称→通过构造方法实例化→取得实例化对象

反射模式(逆向模式):实例化对象→getClass()方法找到对应的类→取得完整的“包.类”名称

Object类是一切类的父类,所有类的对象是Class类的实例。Class也是一种类,是java.lang.Class

删除指定范围内的字符串

使用方法delete();

indexOf查找指定字符串内容,如果未查到返回-1.

Runtime类 运行时操作类,一个封装JVM进程的类,可以进行JVM级别的底层操作。每一个JVM都对应一个Runtime类的实例。获取JVM实例的方法是:

Runtime run = Runtime.getRuntime();

介绍Runtime类常用的方法:

内存信息类:

maxMemory 最大内存空间

freeMemory 空闲内存空间

没有最小内存量

Runtime类与Process类

可以Runtime类运行本机可执行程序

可以用exec()方法,返回的是Process,可以用Process类来控制进程。

使用destroy()方法

国际化程序

使程序适用于多个国家语言。使用Locale类、属性文件及ResourceBundle支持

 

属性文件是后缀名为.properties的文件,文件内容结构为key = value

 

 

 

如:

 

WizardFrame.install = 安装

 

WizardFrame.uninstall = 卸载

 

WizardFrame.Verify = 校验

 

WizardFrame.next = 下一步

 

WizardFrame.nextCMD = 下一步>

 

WizardFrame.previous = < 上一步

 

WizardFrame.previousCMD = 上一步

 

WizardFrame.cancel = 取消

 

WizardFrame.hint = 提示

 

WizardFrame.confirmation = 确认

 

WizardFrame.InstallAffirmCancel = 确定取消安装吗?

 

WizardFrame.UninstallAffirmCancel = 确定取消卸载吗?

 

WizardFrame.VerifyAffirmCancel = 确定取消校验吗?

 

WizardFrame.UpdateAffirmCancel = 确定取消升级吗?

 

ResourceBundle类

getBundle(资源名),getBundle(资源名,区域码)

 

 

动态文本:

动态文本也可以叫可变文本,就是文本的部分内容不是写死的,需要用户的交互输入。

比如说需要输出:你好,XXX!

XXX就需要用占位符来表述{0},如果需要多个占位符,就用{1},{2}表示。可以使用MessageFormat类来处理占位符内容。起使用的方法是:

format

format(String pattern,Object···arguments),其中Object···arguments表示任意多个参数,没有个数限制

这个是java的新特性

返回值类型     方法名称         (Object ···arguments),表示方法可以接受任意多个参数,然后按照数组方式输出

 

除了使用资源文件保存属性信息外,还可以使用类来保存属性信息。不过这样比较少见

 

 

 

System类

System类是与系统相关的一些属性和方法集合,这些属性和方法都是静态的,都是使用static来定义。

getProperty可以用来获取系统的一系列属性

 

垃圾对象的回收:

Runtime类有个垃圾回收方法是gc(),System类也有一个gc()方法用于回收垃圾,这个是对Runtime垃圾回收的封装事实上。

一个对象如果不被任何一个栈内存所引用,这个就成为垃圾,需要等待被回收,等待时间不确定。可以直接调用System.gc()方法来进行回收

使用gc()方法时,会默认调用一个finalize()方法,进行一些处理,所以System的gc方法是一些方法的封装,

对象的生命周期

类的初始化——对象的实例化——对象的垃圾收集——对象的终结——程序卸载对象

一个类加载后进行初始化,然后可以对对象实例化,对象实例化由构造方法来完成,当一个对象不再使用时等待被垃圾回收,然后对象终结,最终被程序卸载

日期操作类

Date类

使用date()方法获取一个完整的日期

Calendar类

这是一个抽象类,需要利用多态性,转成父类,再调用子类覆写的方法

用子类的构造方法在栈内存中实例化

DateFormat类

DateFormat类和MessageFormat类都属于Format类,用于专门格式化数据。也是一个抽象类,需要子类实例化