Java学习笔记二

来源:互联网 发布:cs1.6 for mac 编辑:程序博客网 时间:2024/06/06 01:23

后面书中的内容,把图形编程,还有数据库这些都是略过去了,毕竟目前还要以C++为主,去做Qt,后面的线程文件这些东西,并没有写太多东西,因为之前在学的还不错,那些东西都明白知道,而且那些东西记忆性太强,必须通过长时间的实践才会掌握,以后用的时候再去熟练使用吧。网络编程这个就先放下了,等之后去实践做东西的时候,再去系统学学;

小亚~~~~~ 么么哒哒哒哒哒

Java的异常机制主要依赖于try、catch、finally、throw和throws五个关键字;其中try块里面放置可能引发异常的代码块。catch紧跟一个异常的类型和一个代码块,用于表明该catch块用于处理这种异常类型的。多个catch块后还可以跟一个finally块,finally块用于回收try块里打开的物理资源。异常机制保证finally块总会被执行。 throws关键字主要在方法签名中使用,用于声明该方法可能抛出的异常,而throw用于抛出一个实际的异常。

当Java运行时环境受到异常对象时,会寻找能处理该异常对象的catch块,如果找到合适的catch快,就把异常对象交给catch块处理,这个过程叫 捕获异常; 如果找不到捕获异常的catch块,那么程序也将退出。

不管程序代码块是否处于try块中,只要执行这段代码的时候出现了异常,系统都会自动生成一个异常对象。如果没有定义处理这个异常对象的catch块,程序肯定在此处退出。

try块与if语句不一样,try块后面的花括号({…})不能省略,catch的也是一样的。

Java提供了丰富的异常类,并且这些异常之间有严格的继承关系。继承关系如下:

从上面可以看出,异常分为两种:异常(Exception)和错误(Error),都是继承Throwable父类。
Error错误,一般是指虚拟机相关的问题,如系统崩溃、虚拟机处错误、动态连接失败等,这种错误没法回复或不可能捕获,将导致程序中断。应用程序无法处理这些错误,因此应用程序不应该试图使用catch块来捕获Error对象。所以无须在其throws子句中声明该方法可能抛出Error及其任何子类。

public class TestNull{    public static void main(String[] args)    {        Date d = null;        try        {            System.out.println(d.after(new Date));        }        catch(NullPointerException ne)        {            System.out.println("空指针异常");        }        //注意一定要把Exception放到最后面        catch(Exception e)        {            System.out.println("位置异常");        }    }}

注意上面的程序中,我们把Exception类的catch总是放在最后,为什么呢?我想应该明白吧,因为如果把Exception放在前面的话,那么他后面的catch块就没有作用了。实际上,我们不仅应该吧Exception的catch块放在最后,所有父类的异常的catch块都应该排在子类异常的后面。

try{    statements...}catch(RuntimeException e){    System.out.println("运行时异常");}//注意一定要把Exception放到最后面catch(NullPointerException ne){    System.out.println("空指针异常");}

如果按上面的程序进行编译,但是由于第一个RuntimeException是后面的异常的父类,所以第二个异常永远都没有用了,所以编译会出错。
所以一定要记住先捕获小的异常,再捕获大的异常。
如果程序需要在某个catch块中访问异常对象的相关信息,对于所有的异常对象都包含了如下几个常用方法:
getMessage();//返回该异常的详细描述字符串
printStackTrave();//该异常的跟踪栈信息输出到标准错误输出
printStackTrace(PrintStream s);//将该异常的跟踪栈信息输出到指定输出流
getStackTrace();//返回该异常的跟踪栈信息
如下面的程序实例:

public class TestNull{    public static void main(String[] args)    {        try        {            FileInputStream fis = new FileInputStream("a.txt");        }        catch(IOException ioe)        {            System.out.println(ioe.getMessage());            ioe.printStackTrace();        }    }}

有些时候,程序在try块中打开了一些物力资源,这些物理资源必须显示回收。所以出现了finally块。

try{    //业务代码}catch(SubExveption e){    //异常处理块}finally{    //资源回收快}

异常处理的语法中,只有try块必须的,后面的catch块和finally块都是可选的;finally块必须位于catch块之后。

try{    fis = new FileInputStream("a.txt");}catch(SubExveption e){    //异常处理块}finally{    if( fis != null )    {        try        {            fis.close();        }        catch(IOException ioe)        {            ioe.printStackTrace();            return;        }    }    System.out.println("程序执行了finally里的资源");}

虽然catch块中有return语句,但是不会强制这个方法结束,一定会先执行finllay块里的代码,再结束程序。
正常的情况下,不要再finally块中使用return或者throw等导致方法终止的语句,一旦在finally块中使用return 或 throw语句,将会导致try块、catch块中的return、throw语句失败。

(到现在我还没太弄明白这两类有什么区别)Java异常被分为两大类:Checked异常和Runtime异常。Check异常如果在程序中没有完善处理根本不会执行。处理方式有两种:
1:如果知道如何处理异常,程序应该使用try,catch来捕获异常。
2:当前不知道如何处理的话,应该在定义该方法时声明抛出该异常。
Runtime异常无须显示声明抛出,如果要捕捉也可以使用try..catch来捕捉异常。

关于Checked异常和Runtime异常的区别:
Checked异常必须被显式地捕获或者传递,如Basic try-catch-finally Exception Handling一文中所说。而unchecked异常则可以不必捕获或抛出。
Checked异常继承java.lang.Exception类。Unchecked异常继承自java.lang.RuntimeException类。
Checked和unchecked异常从功能的角度来讲是等价的。可以用checked异常实现的功能必然也可以用unchecked异常实现,反之亦然。
使用throws声明抛出异常的思路是:当前方法不知道应该如何处理这种类型异常,该异常应该由上一级调用者处理,如果main方法也不知道应该如何处理这种类型的异常,也可以使用throws声明抛出的异常,该异常将交给JVM.JVM对异常处理的方法是:打印异常跟踪栈信息,并终止程序运行。

throws声明只能在方法签名中使用,throws可以声明抛出多个异常类,多个异常类之间以都好隔开。

如果某段代码调用了一个带throws声明的方法,该方法声明跑出了Checked异常,这表明该方法希望它的调用者来处理异常,也就是说,这段代码要么放在try块中显示捕获异常,要么这段代码处于另一个带throws声明抛出的方法中。

public class Test{    //注意两个调用关系以及抛出的异常对象的关系    //最终抛出的异常的对象必须是上一级抛出异常的    //父类,要么是同一级    public static void main(String[] args)throws Exception    {        Func();    }    public static void Func() throws IOException    {        //因为下面的可能会抛出异常        //所以下面的代码要么在try..catch块中        //要么处于另一个带throws声明的方法中        FileInputStream fis = new FileInputStream("a.txt");    }}

throws可以单独使用,但是throw不能,throw要么和try-catch-finally语句配套使用,要么与throws配套使用;throws出现在方法函数头;而throw出现在函数体;

throw语句抛出的不是异常类,而是一个异常实例,并且每次只能抛出一个异常实例。
throw语句的语法格式如下:
throw ExceptionInstance
用户可以自定义异常都应该继承Exception基类,例如希望自定义Runtime异常,则应该继承RuntimeException基类。定义异常类时通常需要提供两种构造器:一个是无参数的构造器;另一个是带一个字符串的构造器,这个字符串将作为该异常对象的详细说明。
下面是自定义的异常类:

//如果自定义Runtime异常,只需要将继承的Exception类改成//RuntimeException基类public class AuctionException extends Exception{    public AuctionException() {}    public AuctionException(String msg)    {        //通过super调用父类的构造器        super(msg);    }}

第十一章
所有和AWT编程相关的类都放在java.awt包和它的子包里,AWT编程中有两个基类:Component和MenuComponent。如下图所提供的图形组件之间的继承关系:

其中Component代表一个能以图形化方式显示出来,并可与用户交互的对象,例如Button按钮,TextField等,而MenuComponent则代表图形界面的菜单组件,包括MenuBar(菜单条)、MenuItem(菜单项)等子类。

Component类有如下几个常用方法设置组件的大小、位置和可见性等。
setLocation(int x,int y);设置组件位置
setSize(int width, int height);设置组件的大小
setBounds(int x, int y, int width, int height);同时设置组件的位置、大小。
setVisible(Boolean b);设置该组件的可见性。‘

布局管理器:
1:FlowLayout布局管理器:
组件像流水一样向某方法六栋(排列),遇到障碍(边界)就折回,重头开始排列。默认情况下,FlowLayout布局管理器从左向右排列所有组件,遇到边间就会折回下一行重新开始。
FlowLayout();使用默认对其方式、默认垂直方式、水平间距创建FlowLayout布局管理器。
FlowLayout(int align);使用指定对齐方式、默认垂直、水平间距创建FlowLayout布局管理器。
lowLayout(int align, int hgap, int vgap);使用指定对齐方式、指定垂直、水平间距创建;

BorderLayout布局管理器:
将容器分为EAST、SOUTH、 WEST、NORTH、CENTER五个区域,普通组件可以放在这五个区域的任意一个。当使用这种布局管理器的时候,需要制定要添加到哪个区域里,如果没有制定添加到哪个区域里,则默认添加到中间区域里。
如果向同一个区域中添加多个组件时,后放入的组件会覆盖前面的组件。

GridLayout布局管理器:
GirdLayout布局管理器将容器分割成纵横线分割的网络,每个网络所占的区域大小相同。当想使用GiridLayout添加组件时,默认从左向右,从上向下。与FlowLayout不同的是,放在GridLayout布局管理器中的各组件的大小由组件所出的区域来决定。

GridBagLayout布局管理器:
这种布局管理器是功能最强大的,但也是最复杂的布局管理器,与GridLayout布局管理器不同的是:GridBagLayout布局管理器中,一个组件可以跨越一个或多个网格,并可以设置各网格的大小互不相同。

CardLayout布局管理器
这种布局管理器是以时间而非空间来管理它里面的组件。它将加入容器的所有组件看成一叠卡片,每次只有最上面的那个Componet才可见。

15章 文件
流的分类:
字节流和字符流:字节流操作的最小数据单元是8位的字节,而字符流操作的最小数据单元是16位的字符。
节点流和处理流:
节点流:可以从/向一个特定的IO设备读/写数据的流,成为节点流,节点流常常被称为低级流。
处理流:用于对一个已存在的流进行连接或封装,通过封装后流来实现数据读/写功能。处理流也被称为高级流;

Java的IO流涉及40多个类,这些类都是从4个抽象基类派生出来的;
InputSteam/Reader:所有输入流的基类,前者是字节输入流,后者是字符输入流。
OutputStream/Writer:所有输出的基类,前者是字节输出流,后者是字符输出流。

16章 多线程
Java中有两种方法创建线程:
1:继承Thread类创建线程类
2:实现Runnable接口创建线程类

第一种方法实现步骤如下:
1、定义Thread类的子类,并重写该类的run方法。
2、创建Thread子类的实例
3、线程对象的start方法来启动该线程

class Test extends Thread{    private int i;    public void run()    {        for(; i<100; i++)            //注意下面的getName方法是直接调用的            System.out.println(getName()+" "+i);    }    public static void main(String[] args)    {        for(int i=0; i<100; ++i)        {            System.out.println(Thread.currentThread().getName()+""+i);            if(20 == i)            {                new Test().start();                new Test().start();            }        }    }}

第二种方法的实现:
1、定义Runable接口的实现类,并重写接口的run方法。
2、创建Runnable实现类的实例,并以此实例作为Thread的target来创建线程对象。
3、调用线程对象的start方法启动线程

class Test implements Runnable{    private int i;    public void run()    {        for(; i<100; i++)            //注意下面的getName方法是直接调用的            System.out.println(Thread.currentThread().getName()+" "+i);    }    public static void main(String[] args)    {        for(int i=0; i<100; ++i)        {            System.out.println(Thread.currentThread().getName()+""+i);            if(20 == i)            {                Test st = new Test();                new Thread(st,"新县城1").start();                new Thread(st,"新县城2").start();            }        }    }}

第二种方法执行的结果两条子线程的i变量是连续的,也就是说这两个子线程是共享i这个变量的!!!

虽然两种方法都可以实现,但是这两种方法还是有区别的:
采用实现Runnable接口方式的多线程:
线程类只是实现了Runnable接口,还可以继承其他类。
在这种方式下,可以多个线程共享同一个target对象,所以非常适合多个线程来处理同一份资源的情况。
劣势:编程复杂些,如果需要访问当前进程,必须使用Thread.currentThread()方法。
采用继承Thread类方式的多线程:
劣势:因为线程类已经继承了Thread类,所以不能再继续继承其他父类。
优势:编写简单,如果需要访问当前线程,无需使用Thead.currentThread()方法。

当发生如下情况下,线程会进入阻塞状态:
1、线程调用sleep方法主动放弃所占用的处理器资源
2、线程调用了一个同步监视器,但该同步监视器正被其他线程所持有。
3、线程调用了一堵塞式IO方法,该方法返回之前,线程被堵塞
4、线程在等待某个通知
5、程序调用了线程的suspend方法将该线程挂起,不过这种方法容易导致死锁。

线程会以以下三种方法之一结束,结束后就处于死亡状态:
1、run()方法执行完成,线程正常结束。
2、线程泡醋一个未捕获的Exception或Error
3、直接调用该线程的stop()方法来结束该线程

为了测试某条线程是否已经死亡,可以调用线程对象的isAlive()方法,当线程处于就绪、运行、阻塞三种状态时,该方法将返回true;当线程处于新建、死亡两种状态时,该方法将返回false。
(绝对不能对一个已经死亡的线程调用start()方法使它重新启动)如果再次调用start()方法来启动线程,将引发ILLegalThreadStateException异常,表明死亡状态的线程无法再次运行。

线程睡眠sleep和线程让步yield的区别在于:线程睡眠是使线程处于堵塞状态,而线程让步是使线程回归到就绪状态

任何线程进入同步代码块、同步方法之前,必须现货的同步监视器的锁定,那么何时会释放对同步监视器的锁定呢?程序无法显示释放对同步监视器的锁定,线程会在如下几种情况下释放对同步监视器的锁定:
1、当前线程的同步方法、同步代码块之行结束,当前线程即释放同步监视器。
2、当线程在同步代码块、同步方法中遇到break、return终止了该代码块、该方法的继续执行,当前线程将会释放同步监视器。
3、当线程在同步代码块、同步方法中出现了未处理的Error或Exception,导致了该代码块、该方法一场结束时会释放同步监视器。
4、当线程执行同步代码块或同步方法时,程序执行了同步监视器对象的wait()方法,则当前线程暂停,并释放同步监视器。
下面情况下,线程不会释放同步监视器:
1、县城执行同步代码块或同步方法时,程序调用Thread.sleep()、Thread.yleld()方法来暂停当前线程的执行,当前线程不会释放同步监视器。
2、线程执行同步代码块时,其他线程调用了该线程的suspend方法将该线程挂起,该线程不会释放同步监视器。

一旦某个线程加入了指定线程组之后,该线程将一直属于该线程组,知道该线程死亡,线程运行中途不能改变它所属的线程组。

0 0
原创粉丝点击