现在的位置: 首页 > 综合 > 正文

java程序设计–孙鑫java无难事Lesson4《内部类、异常处理》

2013年08月15日 ⁄ 综合 ⁄ 共 10396字 ⁄ 字号 评论关闭
java程序设计--孙鑫java无难事Lesson4《内部类、异常处理》

1.内部类的特性和使用方法
概念总述:
在一个类中定义另外一个类,这个类就叫做内部类或内置类 (inner class) 。
内部类可以让我们将逻辑上相关的一组类组织起来,并由外部类(outer class)来控制内部类的可见性。
当我们建立一个inner class时,其对象就拥有了与外部类对象之间的一种关系,这是通过一个特殊的this reference形成的,使得内部类对象可以随意的访问外部类中所有的成员。

详细内容:

(1)外部类的main静态方法中无法直接访问内部类,错误信息如下:

//*********************************************************************************

Outer.java:30: 错误: 无法从静态上下文中引用非静态 变量 this
        Inner inner=new Inner();
(2)引用内部类时需要一个外部类的实例来引用

否则错误信息如下:

//*********************************************************************************

Outer.Inner inner=new Outer.Inner();
        inner.print();//error
Outer.java:46: 错误: 需要包含Outer.Inner的封闭实例
                Outer.Inner inner=new Outer.Inner();
(3)内部类访问外部类的成员、中间层类的成员、和本地变量

测试代码及结果如下:

//*********************************************************************************

class  Outer  //外部类
{   
    private int index=100;//外部类成员
    //内部类Inner类不管嵌套层次多深,都可以访问外部类成员
    void fn( final int a)
    {   
        //ok 类的作用域限定在if语句中 仍然可以访问外部类成员
        final int b=0;//需要初始化
        if(true)
        {   
            class Middle    //中间类
            {
                           private int index=70;////中间类成员
                class Inner   //内部类
                {   
                    private int index=50;//内部类成员
                    void print()
                    {   
                       int index=30;
                       System.out.println(index);//30
                       System.out.println(this.index);//50
                       System.out.println(Middle.this.index);//70
                       System.out.println(Outer.this.index);//100
                       System.out.println(a);//ok 声明为final时
                       System.out.println(b);//ok 声明为final时
                    }
                }
            }
        }
}

(4)在方法中定义的内部类,如果要访问方法中定义的本地变量或方法的参数,则变量必须被声明final,否则出错,错误信息如下:

//*********************************************************************************

Outer.java:38: 错误: 从内部类中访问本地变量a; 需要被声明为最终类型a=5;
Outer.java:39: 错误: 从内部类中访问本地变量b; 需要被声明为最终类型b=6;                
(5)private内部类  

内部类声明为private时无法访问,否则错误信息如下:

//*********************************************************************************

Outer.java:133: 错误: Outer.Inner可以在Outer中访问private Outer.Inner inner=outer.new Inner();
内部类还可以声明为protected、abstract或final。
(6)static内部类  

内部类可以声明为static的,但此时就不能再使用外部类的非static的成员变量和非static的成员方法,否则错误信息如下:

//*********************************************************************************

Outer.java:102: 错误: 无法从静态上下文中引用非静态 变量 this
                   System.out.println(Outer.this.index);//error  
(7)非static的内部类中的成员不能声明为static的,只有在顶层类或static的内部类中才可声明static成员,

否则错误信息如下:

//*********************************************************************************

Outer.java:110: 错误: 内部类Outer.Inner中的静态声明非法
                static void print()
修饰符 'static' 仅允许在常量变量声明中使用
(8)内部类继承

内部类无法直接继承,类定义如下:

//*********************************************************************************

class Car
{   
    class Wheel{}
}
class PlaneWheel extends Car.Wheel
{
    public static void main(String[] args) {
            PlaneWheel pw=new PlaneWheel();
        System.out.println("Hello World!");
    }
}
则错误信息如下:
Car.java:9: 错误: 需要包含Car.Wheel的封闭实例
class PlaneWheel extends Car.Wheel
解决方法:
class Car
{   
    class Wheel{}
}
class PlaneWheel extends Car.Wheel
{       
        //产生外部类对象
        PlaneWheel(Car car)
    {
        car.super();
    }
    public static void main(String[] args)
    {   
        Car car=new Car();
        PlaneWheel pw=new PlaneWheel(car);
    }
}
(9)匿名内部类

匿名内部类测试代码1如下:

//*********************************************************************************

interface Animal
{
    void eat();
    void sleep();
}
class  Zoom
{   
    //隐藏实现细节  通过接口访问内部类的方法
    private class Tiger implements  Animal
    {
        public void eat()
        {
            System.out.println("Tiger eat");
        }
        public void sleep()
        {
            System.out.println("Tiger sleep!");
        }
    }
     Animal getanimal()
    {  
      //接口无法直接实例化对象  需要使用匿名内部类 实现接口中的方法
      return new Animal()
      {
          public void eat()
        {
            System.out.println("Animal eat");
        }
        public void sleep()
        {
            System.out.println("Animal sleep!");
        }
      };
    }
}
class Test
{
    public static void main(String[] args)
    {   
        Zoom zoom=new Zoom();
        Animal an=zoom.getanimal();
        an.eat();
        an.sleep();
    }

}

//*********************************************************************************

//输出结果
Animal eat

Animal sleep!

//*********************************************************************************

匿名内部类测试代码2如下:

//*********************************************************************************

class A
{   
    void fn1(){}
}
abstract class B
{
    abstract void fn2();
}
class C extends A
{   
    //使用匿名内置类 返回内置类对象
    B getB()
    {
       return new B()
       {
          public void fn2(){};//实现抽象类B的方法
       };
    }
}
class Test
{
    static void method1(A a)
    {
        a.fn1();
    }
    static void method2(B b)
    {
        b.fn2();
    }
    public static void main(String[] args)
    {   
        C c=new C();
        method1(c);
        method2(c.getB());
    }
}
(10)利用内部类解决方法重名问题

测试代码如下:

//*********************************************************************************

interface Machine
{
    void run();
}
class Person
{
    public void run()
    {
        System.out.println("run");
    }
}
//需要继承 但是继承的同时方法与接口中方法重名 利用内部类解决
class Robot extends Person
{
    private class MachineHeart implements Machine
    {
        public void run()
        {
           System.out.println("heart run");
        }
    }
    Machine getmachine()
    {
       return new MachineHeart();
    }
}
class Test
{
    public static void main(String[] args)
    {   
        Robot robot =new Robot();
        Machine m=robot.getmachine();
        m.run();
        robot.run();
    }

}

//*********************************************************************************

//输出结果
heart run
run
2.异常处理
概念总述:
Java程序在执行过程中如出现异常,会自动生成一个异常类对象,该异常对象将被提交给Java运行时系统,这个过程称为抛出(throw)异常。
当Java运行时系统接收到异常对象时,会寻找能处理这一异常的代码并把当前异常对象交给其处理,这一过程称为捕获(catch)异常。
如果Java运行时系统找不到可以捕获异常的方法,则运行时系统将终止,相应的Java程序也将退出。

详细内容:

(1)构造一个除0异常,捕获异常信息如下:

//*********************************************************************************

Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Excep.division(Excep.java:5)
        at ExcepTest.main(Excep.java:14)
(2)捕获异常的位置--try catch语句块
try语句中发生异常后的语句将不予执行,但是catch语句后的语句予以执行。异常处理代码放置在catch语句中。

(3)抛出异常而没有捕获异常时,错误信息如下:

//*********************************************************************************

Excep.java:53: 错误: 未报告的异常错误Exception; 必须对其进行捕获或声明以便抛出
                System.out.println( excep.division(5,0));
(4)捕获异常顺序--特殊到一般

已经捕获了Exception,再次捕获ArithmeticException时错误信息如下:

//*********************************************************************************

Excep.java:51: 错误: 已捕获到异常错误ArithmeticException
                catch( ArithmeticException e)
(5)RuntimeException运行时异常并不需要显示的捕获
对于RuntimeException,通常不需要我们去捕获,这类异常由Java运行系统自动抛出并自动处理。

(6)捕获异常后可以继续抛出异常

//*********************************************************************************

public int division(int a ,int b) throws ArithmeticException

{   
    //在函数内部捕获异常
    try
    {
        return a/b;
    }
    catch (ArithmeticException e)
    {    
             e.printStackTrace();//输出异常信息
         throw e;//再次抛出异常 程序跳转
    }
}

//捕获异常信息如下:

//*********************************************************************************

java.lang.ArithmeticException: / by zero
        at Excep.division(Excep.java:33)
        at ExcepTest.main(Excep.java:75)
Exception in thread "main" java.lang.ArithmeticException: / by zero
        at Excep.division(Excep.java:33)
        at ExcepTest.main(Excep.java:75)

(7)捕获异常后可以重新抛出新的异常

//*********************************************************************************

public int division(int a ,int b) throws Exception
{   
    //在函数内部捕获异常
    try
    {
        return a/b;
    }
    catch (ArithmeticException e)
    {    
            e.printStackTrace();//输出异常信息后
        throw new Exception("can not div zero!");//再次抛出新异常
    }

}

//*********************************************************************************

捕获异常信息如下:

F:\java\JavaLesson\Lesson4>java ExcepTest
java.lang.ArithmeticException: / by zero
        at Excep.division(Excep.java:33)
        at Excep.fn1(Excep.java:45)
        at ExcepTest.main(Excep.java:58)
java.lang.Exception: can not div zero!
        at Excep.division(Excep.java:38)
        at Excep.fn1(Excep.java:45)
        at ExcepTest.main(Excep.java:58)
(8)自定义异常

从Exception派生子类如下:

//*********************************************************************************

class  DivisorIsMinusException extends Exception
{
    DivisorIsMinusException(String str)
    {
        super(str);
    }
}
自定义异常类的使用如下:
public int division(int a ,int b) throws ArithmeticException ,DivisorIsMinusException
    {   
        if(b<0)
                throw new DivisorIsMinusException("Divisor can't be minus!");
        return a/b;
    }
    int fn1(int a,int b)   throws ArithmeticException ,DivisorIsMinusException
    {
        return division(a,b);

    }

//*********************************************************************************

//异常捕获信息如下:
F:\java\JavaLesson\Lesson4>java ExcepTest
DivisorIsMinusException: Divisor can't be minus!
        at Excep.division(Excep.java:52)
        at Excep.fn1(Excep.java:57)
        at ExcepTest.main(Excep.java:77)
(9)finally执行机会
不管异常发生没有,finally均会执行,适合在此处做一些清理和资源释放工作
finally语句执行不受return语句限制,但是使用exit退出时不会执行.

在Test.java中执行如下测试代码:

//*********************************************************************************

try
    {   
        System.out.println( excep.fn1(5,-2));
        return;//finally语句仍会执行
    }
    catch( ArithmeticException e)
    {
       System.out.println( e.toString() );
    }
    //捕获自定义异常
    catch (DivisorIsMinusException ex)
    {
        ex.printStackTrace();
        System.exit(-1);//finally语句不会执行
    }
    //捕获一般异常
    catch (Exception e)
    {
        e.printStackTrace();//打印异常信息和位置
    }
    finally
    {
       System.out.println( "finally!");

    }

//*********************************************************************************

//运行结果
F:\java\JavaLesson\Lesson4>java ExcepTest
DivisorIsMinusException: Divisor can't be minus!
        at Excep.division(Excep.java:52)
        at Excep.fn1(Excep.java:57)
        at ExcepTest.main(Excep.java:77)
finally!
(10)子类覆盖父类的方法中抛出异常时受限制
如果父类中的方法抛出多个异常,则子类中的覆盖方法要么抛出相同的异常,要么抛出异常的子类,但不能抛出新的异常(注:构造方法除外)。
以下测试代码,子类试图覆盖父类方法的同时抛出新的异常.
//*****************************************************
class Excep
{
    public int division(int a ,int b) throws Exception  
    {   
        try
        {
            return a/b;
        }
        catch (ArithmeticException e)
        {    
                    e.printStackTrace();//输出异常信息后
        }
    }
}
class ChildExcep extends Excep
{   
       //error    子类覆盖父类方法时抛出异常受限制
    public int division(int a ,int b) throws FileNotFoundException
    {   
        return a/b;
    }

}

//*********************************************************************************

以上代码编译会出错,错误信息如下:
Excep.java:63: 错误: ChildExcep中的division(int,int)无法覆盖Excep中的division(in
t,int) public int division(int a ,int b) throws FileNotFoundException
被覆盖的方法未抛出FileNotFoundException
(11)我们可以在方法声明时,声明一个不会抛出的异常,Java编译器就会强迫方法的使用者对异常进行处理。这种方式通常应用于abstract base class和interface中。

抱歉!评论已关闭.