内部类与异常

一、内部类(inner class)

1、定义

          在一个类中,定义另一个类的代码结构,通常定义在类内部的类称为 “内部类”  ,外面的类称为“外部类” , 在逻辑关系上 内部类与外部类是从属关系,比如  一个People类 存在收货地址类(收货人,收货联系方式)

2、分类

         2.1、 普通内部类(inner class),一个类A中定义另一个类B,其中类B就是类A的内部类,也是类A的一部分

	

public class People {
    private String pname="张三";

    public void sayHello(){
        System.out.println("Let us say Hello");
        // 知识点1 :外部类的方法中,可以使用内部类的属性、方法
        Address address = new Address();
        address.addressName ="湖北武汉";
        address.contentName="张某某";
        address.showAddressInfo();
    }


    /**
     * 定义普通内部类   收货地址
     */
    class Address{
        private String addressName;// 收货地址
        private String contentName;// 联系人

        public void showAddressInfo(){
            System.out.println("联系人:"+contentName + "--收货地址:"+addressName);
            // 内部类的方法 可以直接访问外部类的属性  (由于通常情况属性的访问必须通过对象才可以使用,而)
            System.out.println("访问外部类的属性:"+pname);
        }


    }



}

     	 注意两点
  •              外部类的方法中,可以直接访问内部类的所有成员(包括私有)
    
  •             内部类的方法中,也可以直接方法外部类的所有成员,当外部和内部的成员名相同时,就近原则访问成员,或者引入外部类的对象访问
    

    2.2、 静态内部类(static inner class): 在普通内部类基础上,增加“static”关键字,与静态方法相似,满足静态的要求

    public class People{
    /**
    * 2、定义静态内部类
    * 卡信息
    */
    static class Card{
    private static String cardNo=“4200018888000022”;
    private String cardName=“身份证”;

          // 定义静态方法
          public static void showCard(){
              System.out.println("身份证号:"+ cardNo);
          }
          // 定义非静态方法
          public void showCard2(){
              System.out.println("cardName:"+cardName + "----"+ cardNo);
          }
     
      }
    
      // 外部类的方法 
      public void method2(){
          Card card = new Card();
          // 对于静态方法可以直接类名.方法名
          // 对于非静态方法,需要创建Card类的对象访问
          card.showCard2();
    
    
      }
    

    }

    使用:
    // 2 创建静态内部类的对象
    People.Card.showCard();
    // 创建静态内部类的对象
    People.Card card = new People.Card();
    card.showCard2();

           2.3、方法内部类: 在一个方法中定义的类,其中这个类只属于该方法,也只能在该方法中使用 
    

    /**
    * 3、方法内部类 (将一个类定义在方法里面)
    */
    public void method3(){
    int score = 98;

           // 在这里定义一个类
          class MyClass{
              String subject="Java";
              public void getSubjectScore(){
                  //方法内部类中 也可以使用方法的属性
                  System.out.println(pname+"的"+subject+":"+score);
              }
          }
    
          //调用方法里面的类
          MyClass  mycls = new MyClass();
          mycls.getSubjectScore();
      }
    
      People  people = new People();
      // 3 调用方法
          people.method3();
    

    注意:内部类剩的class文件 命名 外部类$内部类名.class

    2.4 匿名内部类: 定义一个没有类名,只有对方法的具体实现。通常它依赖于实现关系(接口)或继承关系(父类)

    a、基于实现关系

    public interface MyInterface {
    // 学习
    public void study();
    // 工作
    public void work();
    }

    // 创建一个匿名类(让接口的引用 指向匿名类的对象)
          MyInterface  person = new MyInterface() {
              @Override
              public void study() {
                  System.out.println("这个人也好好学习");
              }
    
              @Override
              public void work() {
                  System.out.println("这个人也好好工作");
              }
          };
    
          person.study();
          person.work();
    

b、基于继承关系

public class MyClass {

   public void service(){
        System.out.println("提供服务的方法。");
    }
}



 // 父类 new 一个 匿名类,这个匿名类是它的子类
        MyClass cls = new MyClass(){
            @Override //匿名类重写父类的方法 service
            public void service() {
                System.out.println("这是子类的方法");
            }
        };
        cls.service();

二、异常

1、异常的概述

       异常定义: 在程序中,发生“不正常”的事件,导致程序无法正常运行,并使JVM中断,称为异常

     生活中的异常: 早上起床上课,平时骑车20分钟可以到达教室,由于天气原因或者闹钟响了自动关闭,不能按时到达教室上课,迟到了,此时就属于异常现象  。

      捕获异常:  当程序在运行时,发生了异常 ,为了让程序正常执行,需要对异常捕获(catch),称之为捕获异常 

      Java是面向对象的语言, 异常本身就是一个类(Exception),当发生异常时会创建异常对象,捕获的就是该对象。



  System.out.println("请输入一个数字");
        Scanner sc = new Scanner(System.in);
        // 对可能发生的异常 进行处理
        int num = sc.nextInt();
        if(num%2==0){
            System.out.println("这个数是偶数");
        }


    异常代码可能发生异常, 当用户输入非数字时, 导致程序抛出一个异常对象 : 

Exception in thread "main" java.util.InputMismatchException
	at java.util.Scanner.throwFor(Scanner.java:864)

2、异常关键字 以及层次关系

     a、try:   试一试 ,将可能发生的代码使用try包裹   ,try不能单独出现 

     b、catch :  捕获异常,  当发生指定的异常对象时,执行catch代码

  System.out.println("请输入一个数字");
        Scanner sc = new Scanner(System.in);
        // 对可能发生的异常 进行处理
        try {
            int num = sc.nextInt();  // 发生异常后,try里面的代码不再执行
            if (num % 2 == 0) {
                System.out.println("这个数是偶数");
            }
            System.out.println("结束");
        }catch(Exception ee){// 对应的异常类 来捕获对应的异常对象  ,不能确定异常类,可以使用父类Exception
            System.out.println("你的输入不正确");
        }

        System.out.println("程序继续运行直到结束。。。。");

       一个try + 多个catch

 	//  抛出的异常 不能被catch捕获,会发生什么?
        try {
            int[] num = {1, 2, 3};
            System.out.println(num[1]); // 没有捕获该异常对象,JVM依然终止运行
            System.out.println(10/0);
        }catch(NullPointerException ee){
            System.out.println("这是空指针异常");
        }catch(ArrayIndexOutOfBoundsException  ee){
            System.out.println("数组下标越界异常");
        }catch(Exception ee){
            // 输出异常 堆栈消息  方便程序员排错(尽可能避免用户看见)
            ee.printStackTrace();
            System.out.println("系统繁忙!"+ee.getMessage());
        }
        System.out.println("程序结束");

     c:  finally :   异常之后的最终处理 (无法是否发生异常,程序都执行 )

          try...  finally 结构 

	 try{
            System.out.println("请输入两个数 ,计算两个数相除");
            Scanner sc = new Scanner(System.in);
            int  num1 =  sc.nextInt();
            int num2 = sc.nextInt();
            double  s = num1/num2; // 可能出错
            System.out.println(" try里面结束,结果:"+s);
        }finally{
            System.out.println("无论是否发生异常,都会执行这个语句块,一般用于资源回收");
        }

try… catch…finally 结构

 try {
            System.out.println("请输入两个数 ,计算两个数相除");
            Scanner sc = new Scanner(System.in);
            int num1 = sc.nextInt();
            int num2 = sc.nextInt();
            double s = num1 / num2; // 可能出错
            System.out.println(" try里面结束,结果:" + s);
        }catch(ArithmeticException ee){
            ee.printStackTrace();
            System.out.println("除数不能为0 !!");
        }catch(Exception ee){
            ee.printStackTrace();
            System.out.println("系统繁忙!!!");
        }finally {
            System.out.println("用于资源回收。");
        }

3、捕获异常

     try...catch...finally 

4、抛出异常

  /**
     * 根据下标访问数组元素
     * @param array
     * @param index
     * @return
     */
    public static int getEleByIndex(int [] array , int index){
         // 抛出异常: 可以在异常发生时 或发生之前 创建一个异常对象并抛出
        //  手动抛出一个异常  throw new 异常类([异常消息]);
        if(index <0 || index > array.length-1){
            //抛出异常
            throw new ArrayIndexOutOfBoundsException("你的下标越界了");
        }
        int n =  array[index];
        return n;
    }

public static void main(String[] args) {
          //数组
        int  [] array = {2,1,4,5};
        int index=4;
        // 定义方法访问下标的元素  此时会产生异常 并抛出给方法的调用者
        try {
            int num = getEleByIndex(array, index);
            System.out.println("访问的元素:" + num);
        }catch(ArrayIndexOutOfBoundsException ee){
            System.out.println(ee.getMessage());
        }
        System.out.println("结束。。。");

    }

5、异常分类

由于有些异常是不能直接抛出的 ,需要先声明才可以抛出,异常可以分为两大类:

1、 编译期异常(check 异常或者检查异常):在编译期间检查异常,如果没有处理异常,则编译出错。

        //创建一个文件类的对象
        File  file = new File("d:/aaa.txt");
         // 在写代码(编译之前)时 一定要处理的异常(try..catch 或者 throws),就是编译时异常 
        try {
            file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
        }

 这里的IOException  就是 编译期异常,需要手动处理的

2、运行期异常(runtime 异常或者运行异常):在运行期间检查异常, 编译期可以不处理异常。

        // 在运行期间抛出异常  不需要事先处理的  NullPointException是运行异常
        String str=null;
        System.out.println(str.length());

Exception中常用的异常类

  •   RuntimeException
    
    • ArrayIndexOutOfBoundsException :数组下标越界异常
    • NullPointerException:空指针异常
    • ArithmeticException: 算术异常
    • NumberFormatException :数字格式化异常
    • ClassNotFoundException: 类没找到异常
    • ClassCaseException: 类转换异常
  • 检查异常(check Exception)
    IOException :IO操作

    	FileNotFoundException: 文件未找到异常
    
    	SQLException:
    
    	EOFException:读写文件尾异常
    
    	 DateFormatException:日期格式化异常
    
    	SocketException:SocketException
    

注意: 对于抛出检查异常,需要使用throws声明,对于抛出运行时异常,必须要使用throws声明

声明抛出异常语法:

 声明抛出异常语法:  
         public ...  方法名([参数]) throws 异常类1,异常类2{
             
              // 通过throw抛出   或 处理 检查异常 
      }

  /**
     *   声明抛出异常语法:
     *       public ...  方法名([参数]) throws 异常类1,异常类2{
     *
     *       }
     */
    //创建文件
    public  static void createFile() throws FileNotFoundException ,IOException {
        File file = new File("d:/hello.txt");
        if(file.exists()){
             // 不能创建  ,需要提示用户  该文件存在
            throw new FileNotFoundException("这个文件已存在,不能创建");
        }else{
            //创建
            file.createNewFile();
        }
    }

面试题: 关于 finally 和 return的执行顺序问题?

回答: 当方法有返回值时,先执行fianlly,再return, 但是 finally的代码不会改变return结果

    /**
     *  方法有返回值 有 finally
     * @param n
     * @return
     */
    public static  int  getNum(int n){
          try{
                if(n%2==0){
                    n++;
                }else{
                    n--;
                }
      
             return n;    
          }catch(Exception ee){
              System.out.println("catch--"+n);
            return 0;
          }finally {
              // return 如果放在 try或catch中,不会受finally的改变
              //  如果放在最下面,会受finally的改变
              n++; // 5
              System.out.println("fially----n:" + n); // 5
          }
    }

结果 返回

fially----n:5
4

6、自定义异常

1、为什么需要使用自定义异常

       在Java中每一个异常类都表示特定的异常类型, 例如 NullPointerException表示空指针    ,ArithmeticException表示算术异常, 但是sun公司提供的API中不可能将实际项目中的业务问题全部定义为已知的异常类 ,这是需要程序员根据业务需求来定制异常类,例如 用户注册,可以定义用户注册异常(RegisterException),分数不能为负数也可以定制异常(ScoreExcecption)。 

2、什么是自定义异常

   在开发中根据自己的业务情况来定义异常类 , 灵活性较高,且方便易用。

3、如何实现自定义异常

    a、定义编译期异常类,创建一个类继承 java.lang.Exception ;

    b、定义运行期异常类,创建一个类继承java.lang.RuntimeException;

4、案例分析:自定义异常应用

       要求: 模拟用户注册操作, 用户输入用户名 ,验证用户名是否存在,如果存在,则抛出一个异常消息 “亲,该用户已存在,不能注册”   ,通过自定义异常提示消息



public class RegisterException  extends  Exception {
    public RegisterException(){

    }

    public RegisterException(String message){
        // 将message 赋值给父类的构造
        super(message); //  将message赋值给父类的 属性,可通过getMessage()方法

    }
}


public class TestRegister {
     // 模拟已存在的用户
    String []  users = {"袁魏巍","王麻子","王小花"};

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        System.out.println("请输入你要注册的用户:");
        String uname = sc.next();
        TestRegister obj = new TestRegister();

        try {
            // 调用方法
            obj.checkUserName(uname);
            System.out.println("注册成功");
        } catch (RegisterException e) {
            System.out.println("注册失败");
            System.out.println(e.getMessage());
        }


    }

    /**
     * 检查用户是否存在
     * @param username
     * @return   true  表示通过
     *    异常表示不通过
     */
    public boolean  checkUserName(String username) throws RegisterException{
         // 使用foreach遍历
        /**
         *   for(数据类型 变量名  : 数组名/集合名 ){
         *        循环中的 变量名代表的就是数组的元素
         *   }
         */
        for(String  u : users){
            // 判断u是否与 username相等 ,相等说明用户存在,需要抛出异常
            if(u.equals(username)){
                throw new RegisterException("亲,"+username+" 已存在,不能注册");
            }
        }
        return true;

    }

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值