内部类,异常

1内部类

在java中,一个文件可以定义多个类,文件名必须和public类型的类的类名保持一致。这两个类 是平行关系。

1.1 内部类概念:

在java中,一个类可以定义在一个类的内部 ,定义在内部的类称为内部类(inner class),定义在类的外部的类叫做外部类(outer class)。

1 public class Outer {
2     
3     [修饰符] class Inner{
4         
5     }
6 }

编译后的结果

内部类根据具体的修饰符和具体位置分为很多情况。

2.1 成员内部类

一个内部类作为外部类的成员而存在,此时该内部类称为外部类的成员内部类。一般而言,内部类都用默认修饰符。

public class Outer {
    class Inner{
    }
}

2.1.1 内部类创建对象

 1 public class Test01 {
 2     public static void main(String[] args) {
 3         
 4         // 【1】创建外部类对象
 5         Outer outer = new Outer();
 6         // 【2】创建内部类对象
 7         Inner inner = outer.new Inner();
 8         inner.showInfo();
 9     }
10 }

2.1.2 内部类可以访问外部类的私有变量

 1 public class Outer {
 2     
 3     private String name = "Outer";
 4     
 5     class Inner{
 6         
 7         public void showInfo() {
 8             System.out.println(name);
 9         }
10     }
11 }

特殊情况:外部类和内部类的变量同名

 1 public class Outer {
 2     
 3     private String name = "Outer";
 4     
 5     class Inner{
 6         
 7         private String name = "Inner";
 8         
 9         public void showInfo() {
10             // String name = "show info";
11             
12             // 访问外部类的私有成员
13             System.out.println(this.name);
14             
15             // 访问外部类的私有成员
16             System.out.println(Outer.this.name);
17             
18         }
19     }
20 }

3 静态内部类

如果一个内部类被static修饰,我们认为这个内部类是静态内部类。形式如下。

1 package cn.sxt01.inner02;
2 
3 public class Outer {
4     
5     static class Inner{    
6     }
7 }

3.1 静态内部类创建对象

1 public class Test01 {
2     public static void main(String[] args) {
3         
4         Inner inner = new Outer.Inner();
5         inner.showInfo();
6     }
7 }

3.2静态内部类可以访问外部类中的(私有)静态成员。

 1 public class Outer {
 2     
 3     private static String name = "Outer";
 4     
 5     static class Inner{
 6         
 7         public void showInfo() {
 8             System.out.println("showInfo");
 9             
10             System.out.println(name);
11         }
12     }
13 }

特殊情况:静态内部类和外部类有同名变量(避免发生)

public class Outer {
    
    private static String name = "Outer";
    
    static class Inner{
        
        private static String name = "Outer";
        
        public void showInfo() {
            System.out.println("showInfo");
            
            System.out.println(name);
            
            System.out.println(Outer.name);
        }
    }
}

4 方法内部类

4.1 如果一个内部类定义在一个方法中,称之为方法内部类。形式如下:

 1 public class Outer {
 2     
 3     
 4     public void print() {
 5         
 6         class Inner{
 7             
 8             public void showInfo() {
 9                 System.out.println("show info");
10             }
11         }
12         
13         Inner inner = new Inner();
14         inner.showInfo();
15     }
16 }

4.2 方法的局部变量进入方法内部类时,会被final修饰,出了方法的内部类则不会被final修饰。

 1 public class Outer {
 2     
 3     public void print(int b) {
 4         
 5         int a = 10;
 6         
 7         class Inner{
 8             
 9             public void showInfo() {
10                 System.out.println("show info");
11                 
12                 System.out.println("print()->a:"+10);
13                 
14                 // 在方法内部类中不能修改方法的局部变量(final)
15                 // a = 20;
16                 // b = 20;
17             }
18         }
19         
20         a = 20;
21         
22         Inner inner = new Inner();
23         inner.showInfo();
24     }
25 }

5 匿名内部类

未来一个类如果只使用一次,我们可以把类声明为匿名类。匿名类一般和内部类一起使用。形成匿名内部类。

匿名内部类可用在:实现接口

 1 package cn.sxt01.inner04;
 2 
 3 public class Outer {
 4     
 5     public void print() {
 6         
 7         // 方法内部类
 8         /*class Inner implements MyInterface{
 9 
10             @Override
11             public void showInfo() {
12                 System.out.println("Inner:showInfo");
13             }
14             
15         }*/
16         
17         /*Inner inner = new Inner();
18         inner.showInfo();*/
19         
20         // new Inner().showInfo();
21         
22         // 匿名内部类
23         new MyInterface(){
24             @Override
25             public void showInfo() {
26                 System.out.println("Inner:showInfo");
27             }
28         }.showInfo();
29         
30     }
31 }

2 异常处理

2.1传统异常处理的方式

 1 public class Test01 {
 2     public static void main(String[] args) {
 3         Scanner sc = new Scanner(System.in);
 4         System.out.println("请输入第一个数:");
 5         
 6         int num1 = 0;
 7         if(sc.hasNextInt()) {            
 8             num1 = sc.nextInt();
 9             
10             System.out.println("请输入第二个数:");
11             int num2 = 0;
12             if(sc.hasNextInt()) {
13                 num2 = sc.nextInt();
14                 
15                 if(0 == num2) {
16                     System.out.println("除数不能为0!");
17                 }else {                    
18                     int r = num1 / num2;
19                     System.out.println("num1/num2 = "+r);
20                 }
21 
22             }else {
23                 System.out.println("第二个数输入不是数字");
24             }
25             
26         }else {
27             System.out.println("第一个数输入不是数字!");
28         }
29     }
30 }

缺点:

[1] 通过判断影响执行效率

[2] 判断逻辑和业务逻辑交织在一起可维护性很差。

2.2 异常

异常是指在程序运行过程中发生的不正常的情况,它会中断正在运行的程序。

异常处理机制

java中通过异常处理机制为程序提供异常处理的能力,保证java在运行过程中,能够保持运行而不因为异常中断程序。

2.3异常处理

 涉及异常处理的关键字有try ...catch/try ...catch ...finally

2.3.1 try/catch

 把可能产生异常的代码放在try代码块中,catch代码块去买个捕获并处理异常。

【1】正常执行,没有异常

【2】出现异常,异常处理,正常结束

 Exception是所有异常类的直接的或间接的父类。

getMessage:返回异常的描述信息

 1 package cn.sxt02.exception02;
 2 import java.util.Scanner;
 3 public class Test01 {
 4     public static void main(String[] args) {
 5         Scanner sc = new Scanner(System.in);
 6         System.out.println("请输入第一个数:");
 7 
 8         int num1 = 0;
 9         int num2 = 0;
10         
11         try {
12             num1 = sc.nextInt();
13 
14             System.out.println("请输入第二个数:");
15             num2 = sc.nextInt();
16 
17             int r = num1 / num2;
18             System.out.println("num1/num2 = " + r);
19         }catch (Exception e) {
20             System.out.println("程序出现异常");
21             // 打印异常的信息
22             // System.out.println(e.toString());
23             
24             
25             // 打印异常堆栈信息
26              e.printStackTrace();
27             
28             // 返回异常的描述信息,如果没有信息,返回null(InputMismatchException 没有描述信息)
29             System.out.println(e.getMessage());
30         }
31         
32         System.out.println("程序正常结束");
33     }
34 }

【3】异常类型不匹配

【4】多重catch

 1 public class Test03 {
 2     public static void main(String[] args) {
 3         Scanner sc = new Scanner(System.in);
 4         System.out.println("请输入第一个数:");
 5 
 6         int num1 = 0;
 7         int num2 = 0;
 8         
 9         try {
10             num1 = sc.nextInt();
11 
12             System.out.println("请输入第二个数:");
13             num2 = sc.nextInt();
14 
15             int r = num1 / num2;
16             System.out.println("num1/num2 = " + r);
17         }catch (ArithmeticException e) {
18             System.out.println("数学计算异常:"+e.getMessage());
19         }catch(InputMismatchException e) {
20             System.out.println("输入不匹配异常:"+e.getMessage());
21         }catch (Exception e) {
22             System.out.println("发送异常:"+e.getMessage());
23         }
24         
25         System.out.println("程序正常结束");
26     }
27 }

2.3.2 try/catch/finally

把有可能产生异常的代码放到try代码块中,catch能够捕获并处理异常,finally用于进行收尾工作(关闭数据库、关闭文件、释放内存等资源).

不管是否发生异常,finally都执行。

 1 public static void main(String[] args) {
 2         Scanner sc = new Scanner(System.in);
 3         System.out.println("请输入第一个数:");
 4 
 5         int num1 = 0;
 6         int num2 = 0;
 7 
 8         try {
 9             num1 = sc.nextInt();
10 
11             System.out.println("请输入第二个数:");
12             num2 = sc.nextInt();
13 
14             int r = num1 / num2;
15             System.out.println("num1/num2 = " + r);
16         } catch (Exception e) {
17             System.out.println("程序出现异常");
18         } finally {
19             System.out.println("不管是否出现异常,finally都执行");
20         }
21 
22         System.out.println("程序正常结束");
23     }

 finally总是执行,常用进行收尾工作。

 特殊情况

 [1] finally执行的情况。

 System.exit(0);正常退出jvm,finally不会执行。

 [2]catch可以省略,变成try...finally块。

2.3.3 return

存在return的try/catch/finally执行顺序。

【1】如果不出现异常,顺序为:try->finally->return

【2】如果出现异常,顺序为:try->catch->finally->return

 1 package cn.sxt02.exception03;
 2 
 3 /**
 4  * 存在return的情况
 5  */
 6 public class Test02 {
 7 
 8     public static int div(int a, int b) {
 9 
10         try {
11             int r = a / b;
12             return r;
13 
14         } catch (Exception e) {
15             System.out.println("出现异常");
16 
17             return 0;
18 
19         } finally {
20             System.out.println("我是finally");
21         }
22 
23     }
24 
25     public static void main(String[] args) {
26 
27         int r = Test02.div(10, 0);
28         System.out.println("r=" + r);
29         System.out.println("程序正常结束");
30     }
31 }

2.4异常的分类

Throwable类是java中所有错误(error)或异常(exception)的父类。

Exception类表示异常类,分为两种:

RuntimeException:运行时异常。不要求程序必须做出处理。是所有运行时异常的父类。

CheckedException:检查时异常。要求程序必须做出处理,不处理无法编译。

 1 public class Test01 {
 2     public static void main(String[] args) {
 3         // 运行时异常
 4         Scanner sc = new Scanner(System.in);
 5         // runtime exception
 6         int r = sc.nextInt();
 7         System.out.println("r = "+ r);
 8         
 9         // 检查时异常
10         SimpleDateFormat df = new SimpleDateFormat();
11         try {
12             Date date = df.parse("2019");
13         } catch (ParseException e) {
14             e.printStackTrace();
15         }
16     }
17 }

常见的运行时异常

ArithmeticException:数学计算异常。比如除数为0

InputMismatchException:输入不匹配异常

ArrayIndexOutofBoundsException:数组下标越界异常。

NullPointException:空指针异常,对象没有初始化就使用时,jvm抛出该异常

IllegalArgumentException:非法参数异常。

ClassCastException:强制类型转换异常。

NumberFormatException:数字格式化异常。比如把“abc”格式化成数字。

常见检查时异常:

 

ClassNotFoundException:类没有被发现异常。

 

SQLException:数据库相关异常

 

IOException:IO操作异常

 

ParseException:解析错误异常

 

FileNotFoundException:文件未发现异常。

 

 

运行时异常和检查时异常的区别

  运行时异常:包括RuntimeException及其所有子类。不要求程序必须对它们作出处理,比如InputMismatchException、ArithmeticException、NullPointerException等。即使没有使用try-catch或throws进行处理,仍旧可以进行编译和运行。如果运行时发生异常,会输出异常的堆栈信息并中止程序执行。

  Checked异常(非运行时异常):除了运行时异常外的其他异常类都是Checked异常。程序必须捕获或者声明抛出这种异常,否则出现编译错误,无法通过编译。处理方式包括两种:通过try-catch捕获异常,通过throws声明抛出异常从而交给上一级调用方法处理.

2.5.1

throws关键字

当一个方法可能存在异常,而此时自身又无法更好的处理时,可以用将异常交给外界处理。此时用throws关键字声明异常并抛出。

 1 public class Test01 {
 2 
 3     public static int div(int a, int b) throws ArithmeticException{
 4         int r = 0;
 5         r = a / b;
 6         return r;
 7     }
 8 
 9     public static void main(String[] args) {
10         try {
11             Test01.div(10, 0);
12         } catch (ArithmeticException e) {
13             System.out.println("除数不能为0");
14         }
15     }
16 }

 

开发者可以根据需要声明检查时异常(Exception或者非运行时异常)和运行时异常(RuntimeException其子类)

如果调用处也不知道如何处理异常,可选择继续声明异常,我们把这个过程称为异常上抛

 

 1 public class Test01 {
 2 
 3     public static int div(int a, int b) throws Exception{
 4         int r = 0;
 5         r = a / b;
 6         return r;
 7     }
 8 
 9     public static void main(String[] args) throws Exception{
10         
11         //【1】 调用处知道如何处理!
12         /*
13         try {
14             Test01.div(10, 0);
15         } catch (Exception e) {
16             e.printStackTrace();
17         }
18         */
19         
20         // 【2】调用处也不知道如何处理
21         Test01.div(10, 0);
22         
23     }
24 }

 

2.5.2 声明异常和重载的关系

 发明异常和重载没有关系。

方法重载

【1】方法名相同

【2】参数列表不同(个数,类型,不同类型的顺序不同)

【3】和返回值,修饰符,声明异常无关

2.5.3 声明异常和重写的关系

声明异常和方法重写有关系。

【1】父类方法声明了异常(检测时或运行时),子类可以不声明任何异常。

【2】父类方法声明没有声明任何异常(检测时或运行时),子类不声明异常或者声明运行时异常。

【3】父类方法声明了异常(检测时或运行时),子类也声明相同的异常

2.6 手动抛出异常

 2.6.1 throw

除了系统自动抛出异常外,有些问题需要开发者自己手动抛出。使用关键字throw

 1 package cn.sxt02.exception06;
 2 
 3 public class Student {
 4     private String name;
 5     private String gender;
 6 
 7     public String getName() {
 8         return name;
 9     }
10 
11     public void setName(String name) {
12         this.name = name;
13     }
14 
15     public String getGender() {
16         return gender;
17     }
18 
19     public void setGender(String gender) throws Exception{
20         if(gender.equals("男") || gender.equals("女")) {            
21             this.gender = gender;
22         }else {
23             throw new Exception("性别不合法!");
24         }
25     }
26 
27     public Student(String name, String gender) {
28         super();
29         this.name = name;
30         this.gender = gender;
31     }
32 
33     public Student() {
34         super();
35     }
36     
37 }
 1 public class Test01 {
 2     public static void main(String[] args){
 3         Student stu = new Student();
 4         stu.setName("二狗");
 5         try {
 6             stu.setGender("xxx");
 7         } catch (Exception e) {
 8             System.out.println(e.getMessage());
 9         }
10     }
11 }

2.7 自定义异常

  如果开发者需要手动抛出的异常在系统不存在,可以自定义异常。

如果要自定义异常,首先要确定异常类型,如果异常运行时异常,必须继承RuntimeException其子类;如果异常是检查时异常,必须继承Exception其子类。

  异常的命名方式,参考系统命名方式,以Exception结尾。

 

 1 public class AgeException extends Exception{
 2 
 3     public AgeException() {
 4         super();
 5     }
 6 
 7     public AgeException(String message) {
 8         super(message);
 9     }
10     
11 }

 

posted @ 2019-04-26 21:21  cowbe  阅读(424)  评论(0编辑  收藏  举报