Day_11 内部类、接口回调、异常

1、内部类

1.1 内部类的分类
  • 成员内部类(实例内部类)
  • 静态内部类
  • 局部内部类
  • 匿名内部类
1.2 什么是内部类

概念:在一个类的内部再定义一个完整的类。

特点:

  • 编译之后可生成独立的字节码文件。
  • 内部类可直接访问外部类的私有成员,而不破坏封装。
  • 可为外部类提供必要的内部功能组件。
1.3 成员内部类(实例内部类)
  • 在类的内部定义,与实例变量、实例方法同级别的类。
  • 外部类的一个实例部分,创建内部类对象时,必须依赖外部类对象。
    Outer out = new Outer();
    Outer.Inner in = out.new Inner();
  • 当外部类、内部类存在重名属性时,会优先访问内部类属性。
  • 成员内部类不能定义静态成员。

案例演示:实例内部类使用。

package com.qf.pan.inner1;
//主方法
public class Demo01 {
    public static void main(String[] args) {
        //方法一:实例化外部类
        Outter outter = new Outter();
        Outter.Inner inner = outter.new Inner();

        inner.i_id = 11;
        System.out.println(inner.i_id);
        inner.test();
        Outter.Inner inner2 = new Outter().new Inner();

        //方法二:实例化外部类
        Outter.Inner inner1 = new Outter().new Inner();
        inner1.test();
    }
}

外部类

package com.qf.pan.inner1;
//外部类
public class Outter {
    //实例属性
    public int id;

    //实例化内部类
    public class Inner{
        public int i_id;
        public void test(){
            System.out.println("实例化内部类的方法");
        }
    }
}
1.4 静态内部类
  • 不依赖外部类对象,可直接创建或通过类名访问,可声明静态成员。
  • 只能直接访问外部类的静态成员(实例成员需实例化外部类对象)。
    Outer.Inner inner = new Outer.Inner();
    Outer.Inner.show();

案例演示:静态内部类使用。

package com.qf.pan.inner2;
//静态内部类
public class Demo01 {
    public static void main(String[] args) {
        //调用静态属性
        System.out.println(Outter.id);

        //调用静态内部类的方法
        Outter.Inner inner = new Outter.Inner();
        inner.test();
    }
}
class Outter{
    public static int id;
    //静态内部类
    static class Inner{
        public void test(){
            System.out.println("静态内部类");
        }
    }
}
1.5 局部内部类
  • 定义在外部类方法中,作用范围和创建对象范围仅限于当前方法。
  • 局部内部类访问外部类当前方法中的局部变量时,因无法保障变量的生命周期与自身相同,变量必须修饰为final。
  • 限制类的使用范围。

案例演示:局部内部类使用。

package com.qf.pan.inner3;
//局部内部类
public class Demo01 {
    public static void main(String[] args) {
        Outter outter = new Outter();
        //局部属性外界无法调用
        //outter.test1().id;
        outter.test2();
    }
}
class Outter{
    public void test1(){
        //局部属性  --  不存在访问修饰符
        int id = 1;
        System.out.println(id);
    }
    public void test2(){
        //局部内部类  -- 作用域只在当前方法中
        class Inner{
            public void test(){
                System.out.println("局部内部类");
            }
        }
        Inner inner = new Inner();
        inner.test();
    }
}
1.6 匿名内部类
  • 没有类名的局部内部类(一切特征都与局部内部类相同)。
  • 必须继承一个父类或者实现一个接口。
  • 定义类、实现类、创建对象的语法合并,只能创建一个该类的对象。
  • 优点:减少代码量。
  • 缺点:可读性较差。

案例演示:匿名内部类使用。

package com.qf.pan.inner4;
//匿名内部类
//主方法
public class Demo01 {
    public static void main(String[] args) {
        //使用多态的方式
        IInner inner = new Test();
        inner.inner();

        //使用匿名内部类的方式    --  减少类的数量,当方法只使用一次的时候则可以使用匿名内部类
        IInner2 inner2 = new IInner2() {
            @Override
            public void inner() {
                System.out.println("匿名内部类");
            }
        };
        inner2.inner();
    }
}

接口IInner

package com.qf.pan.inner4;
public interface IInner {
    void inner();
}

接口

package com.qf.pan.inner4;
public interface IInner2 {
    void inner();
}

类Test

package com.qf.pan.inner4;
public class Test implements IInner{

    @Override
    public void inner() {
        System.out.println("使用多态的方式");
    }
}

2、接口回调

package com.qf.pan.inner5;/*
 * @author  pyh
 * @date  2020/11/30 0030 上午 10:46
 * @version 1.0
 * @since JDK1.8_241
        接口回调
 */
import com.qf.pan.utils.TimeUtils;

public class Demo1 {
    public static void main(String[] args) {
        //返回当前时间    --  以毫秒为单位
        /*long time1 = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            for (int j = 0; j < 100000; j++) {
                for (int k = 0; k < 10000; k++) {

                }
            }
        }
        long time2 = System.currentTimeMillis();
        System.out.println(time2-time1);*/

        //直接传递对象的方式
        //Test test = new Test();
        //TimeUtils.testTime(test);

        //使用匿名内部类的方式
        /*ITest test = new ITest(){
            @Override
            public void test() {
                for (int i = 0; i < 100000; i++) {
                    for (int j = 0; j < 100000; j++) {
                        for (int k = 0; k < 10000; k++) {

                        }
                    }
                }
            }
        };
        TimeUtils.testTime(test);*/

        //接口回调
        TimeUtils.testTime(new ITest() {//new ITest()相当于直接在这里重写Test的类
            @Override
            public void test() {
                for (int i = 0; i < 10000; i++) {
                    for (int j = 0; j < 10000; j++) {
                        for (int k = 0; k < 10000; k++) {

                        }
                    }
                }
            }
        });
    }
}

接口ITest

package com.qf.pan.inner5;

public interface ITest {
    void test();
}

类Test

package com.qf.pan.inner5;/*
 * @author  pyh
 * @date  2020/11/30 0030 上午 10:49
 * @version 1.0
 * @since JDK1.8_241
 */

public class Test {
    public void test(){
        for (int i = 0; i < 10000; i++) {
            for (int j = 0; j < 10000; j++) {
                for (int k = 0; k < 10000; k++) {

                }
            }
        }
    }
}

工具类TimeUtils,在另一个包utils下写

package com.qf.pan.utils;/*
 * @author  pyh
 * @date  2020/11/30 0030 上午 10:48
 * @version 1.0
 * @since JDK1.8_241
 */

import com.qf.pan.inner5.ITest;
//工具类TimeUtils
public class TimeUtils {
    public static void testTime(ITest test){//ITest test 调用接口ITest的方法
        long time1 = System.currentTimeMillis();
        //调用需要测试的方法
        test.test();
        long time2 = System.currentTimeMillis();
        System.out.println("程序运行所用的时间:"+(time2-time1));
    }
    public static void testTime2(ITest test){
        long time3 = System.currentTimeMillis();
        test.test();
        long time4 = System.currentTimeMillis();
        System.out.println("程序运行所用的时间:"+(time4-time3));
    }
}

3、异常

3.1 概念

异常:程序在运行过程中出现的特殊情况。

3.2 异常的必要性

任何程序都可能存在大量的未知问题、错误。

如果不对这些问题进行正确处理,则可能导致程序的中断,造成不必要的损失。

3.3异常分类

Throwable:可抛出的,一切错误或异常的父类,位于java.lang包中。

3.3.1 错误
  • Error: JVM、硬件、执行逻辑错误,不能手动处理。
  • 常见错误: StackOverflowError、 OutOfMemoryError等。
3.3.2 异常
  • Exception:程序在运行和配置中产生的问题,可处理。
    • RuntimeException:运行时异常,可处理,可不处理。
    • CheckedException:检查时异常,必须处理。

常见运行时异常:

异常描述
NullPointerException空指针异常
ArrayIndexOutOfBoundsException数组越界异常
ClassCastException类型转换异常
NumberFormatException数字格式化异常
ArithmeticException算术异常
public class Demo1 {
	public static void main(String[] args) {
		//常见运行时异常
		//1NullPointerException
		String name=null;
		System.out.println(name.equals("zhangsan"));
		//2ArrayIndexOutOfBoundsException
		int[] arr= {10,30,50};
		System.out.println(arr[3]);
		//3ClassCastException
	    Object str="hello";
		Integer i=(Integer)str;
		//4NumberFormatException
		int n=Integer.parseInt("100a");
		System.out.println(n);
		//5ArithmeticExceptioin
		int n=10/0;
		System.out.println(n);
		
		try {
			FileInputStream fis=new FileInputStream("d:\\hell.txt");
		} catch (FileNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
}
3.4异常产生和传递
3.4.1 异常产生
  • 自动抛出异常:当程序在运行时遇到不符合规范的代码或结果时,会产生异常。
  • 手动抛出异常:语法:throw new 异常类型(“实际参数”)。
  • 产生异常结果:相当于遇到 return语句,导致程序因异常而终止。
3.4.2 异常传递
  • 异常的传递:
    • 按照方法的调用链反向传递,如始终没有处理异常,最终会由JVM进行默认异常处理(打印堆栈跟踪信息)。
  • 受查异常:throws 声明异常,修饰在方法参数列表后端。
  • 运行时异常:因可处理可不处理,无需声明异常。

案例演示:异常的产生、传递。

/**
 * 演示异常的产生和传递
 * 要求:输入两个数字实现两个数字相除
 */
public class TestException1 {
	public static void main(String[] args) {
		operation();
	}
	public static void operation() {
		System.out.println("---opration-----");
		divide();
	}
	public static void divide() {
		Scanner input=new Scanner(System.in);
		System.out.println("请输入第一个数字");
		int num1=input.nextInt();//出现异常,没有处理,程序中断
		System.out.println("请输入第二个数字");
		int num2=input.nextInt();
		int result=num1/num2;//出现异常没有处理,所以程序中断
		System.out.println("结果:"+result);
		System.out.println("程序执行完毕了...");
	}
}
3.5异常处理

Java的异常处理是通过5个关键字来实现的:

  • try:执行可能产生异常的代码 。
  • catch:捕获异常 ,并处理。
  • finally:无论是否发生异常,代码总能执行。
  • throw: 手动抛出异常 。
  • throws:声明方法可能要抛出的各种异常。
3.5.1 try…catch…

语法:

try {

​ //可能出现异常的代码

} catch(Exception e) {

​ //异常处理的相关代码,如:getMessage()、printStackTrace()

}

public class TestException2 {
	public static void main(String[] args) {
		Scanner input=new Scanner(System.in);
		int result=0;
		try {
			System.out.println("请输入第一个数字");
			int num1=input.nextInt();//InputMismatchException
			System.out.println("请输入第二个数字");
			int num2=input.nextInt();
			result=num1/num2;//发生异常// ArethmicException
		}catch (Exception e) {//捕获 Exception:是所有异常的父类
			//处理
			//e.printStackTrace();
			System.out.println(e.getMessage());
		}
		System.out.println("结果是:"+result);
		System.out.println("程序结束了...");
				
	}
}

注:1、正常请求 2、出现异常并处理 3、异常类型不匹配。

3.5.2 try…catch…finally…

语法:

try {
//可能出现异常的代码
} catch(Exception e) {

​ //异常处理的相关代码,如:getMessage()、printStackTrace()

} finally{
//是否发生异常都会执行,可以释放资源等。
}

public class TestException3 {
	public static void main(String[] args) {
		Scanner input=new Scanner(System.in);
		int result=0;
		try {
			System.out.println("请输入第一个数字");
			int num1=input.nextInt();//InputMismatchException
			System.out.println("请输入第二个数字");
			int num2=input.nextInt();
			result=num1/num2;//发生异常// ArethmicException
			//手动退出JVM
			//System.exit(0);
		}catch (Exception e) {//捕获 Exception:是所有异常的父类
			//处理
			//e.printStackTrace();
			System.out.println(e.getMessage());
		}finally {
			System.out.println("释放资源...");
		}
		System.out.println("结果是:"+result);
		System.out.println("程序结束了...");
	}
}

注:1、finally块是否发生异常都执行,释放资源等 2、finally块不执行的唯一情况,退出java虚拟机。

3.5.3 多重catch

语法:

try{

​ //可能出现异常的代码。

}catch(异常类型1){

​ //满足异常类型1执行的相关代码。

}catch(异常类型2){

​ //满足异常类型2执行的相关代码。

}catch(异常类型3){

​ //满足异常类型3执行的相关代码

}

public class TestException4 {
	public static void main(String[] args) {
		Scanner input=new Scanner(System.in);
		int result=0;
		try {
//			String string=null;
//			System.out.println(string.equals("hello"));
			System.out.println("请输入第一个数字");
			int num1=input.nextInt();//InputMismatchException
			System.out.println("请输入第二个数字");
			int num2=input.nextInt();
			result=num1/num2;//发生异常// ArethmicException
		}catch (ArithmeticException e) {//捕获 Exception:是所有异常的父类	
			System.out.println("算术异常");
		}catch (InputMismatchException e) {
			System.out.println("输入不匹配异常");
		}catch (Exception e) {
			System.out.println("未知异常");
		}
		System.out.println("结果是:"+result);
		System.out.println("程序结束了...");
	}
}

注意:

3.5.4 try…finally…
  • try…finally…不能捕获异常 ,仅仅用来当发生异常时,用来释放资源。
  • 一般用在底层代码,只释放资源不做异常处理,把异常向上抛出。

语法:

try{
//可能出现异常的代码
}finally{
//是否发生异常都会执行,可以释放资源等
}

public class TestException5 {
	public static void main(String[] args) {//JVM
		try {
			divide();
		}catch (Exception e) {
			System.out.println("出现异常:"+e.getMessage());
		}
	}
	public static void divide() {
		Scanner input=new Scanner(System.in);
		int result=0;
		try {
			System.out.println("请输入第一个数字");
			int num1=input.nextInt();//InputMismatchException
			System.out.println("请输入第二个数字");
			int num2=input.nextInt();
			result=num1/num2;//发生异常// ArethmicException
		}finally {
			System.out.println("释放资源");
		}
		System.out.println("结果是:"+result);
		System.out.println("程序结束了...");
	}
}
3.5.5 小结
  • try{ } catch{ }
  • try{ } catch{ } catch{ }
  • try{ } catch{ } finally{ }
  • try{ } catch{ } catch{ } finally{ }
  • try{ } finally{ }

注:多重catch,遵循从子( 小 )到父( 大 )的顺序,父类异常在最后。

3.6 声明异常
  • throws关键字:声明异常
public class TestException6 {
	public static void main(String[] args){//JVM
		try {
			divide();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			//e.printStackTrace();
			System.out.println(e.getMessage());
		}
		
	}
	public static void divide() throws Exception {
		Scanner input=new Scanner(System.in);
		System.out.println("请输入第一个数字");
		int num1=input.nextInt();
		System.out.println("请输入第二个数字");
		int num2=input.nextInt();
		int result=num1/num2;
		System.out.println("结果:"+result);
	}
}
3.7 抛出异常

除了系统自动抛出异常外,有些问题需要程序员自行抛出异常。

  • throw关键字:抛出异常
public class Person {
	private String name;
	private String sex;
	private int age;
	public Person() {
		// TODO Auto-generated constructor stub
	}
	public Person(String name, String sex, int age) {
		super();
		this.name = name;
		this.sex = sex;
		this.age = age;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getSex() {
		return sex;
	}
	public void setSex(String sex) {
		if(sex.equals("男")||sex.equals("女")) {
			this.sex = sex;
		}else {
			throw new RuntimeException("性别不符合要求");
		}
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) {
		if(age>0&&age<=120) {
			this.age = age;
		}else {
			//抛出异常
			throw new RuntimeException("年龄不符合要求");
		}
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", sex=" + sex + ", age=" + age + "]";
	}
	
}
3.8 自定义异常
  • 需继承Exception或Exception的子类,代表特定问题。
  • 异常类型名称望文生义,可在发生特定问题时抛出对应的异常。

常用构造方法:

  • 无参数构造方法。
  • String message参数的构造方法。
public class AgeException extends RuntimeException{

	public AgeException() {
		super();
		// TODO Auto-generated constructor stub
	}

	public AgeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
		super(message, cause, enableSuppression, writableStackTrace);
		// TODO Auto-generated constructor stub
	}

	public AgeException(String message, Throwable cause) {
		super(message, cause);
		// TODO Auto-generated constructor stub
	}

	public AgeException(String message) {
		super(message);
		// TODO Auto-generated constructor stub
	}

	public AgeException(Throwable cause) {
		super(cause);
		// TODO Auto-generated constructor stub
	}
	
}
3.9 异常中方法覆盖

带有异常声明的方法重写:

  • 方法名、参数列表、返回值类型必须和父类相同。
  • 子类的访问修饰符合父类相同或是比父类更宽。
  • 子类中的方法,不能抛出比父类更多、更宽的检查时异常。
public class Animal {
	public void eat(){
		System.out.println("父类吃方法..........");
	}
}

子类Dog

public class Dog extends Animal{
	@Override
	public void eat() throw Exception{ 
        //出现错误,父类没有声明异常,子类不能声明异常
		System.out.println("子类的吃的方法..........");
	}
}
3.10 自我总结
package com.qf.pan.exception1;/*
 * @author  pyh
 * @date  2020/11/30 0030 上午 11:43
 * @version 1.0
 * @since JDK1.8_241
        Error:错误
        Exception:异常
            1、一般异常(受检性异常),即在编写代码会有异常需要去处理
            2、运行事异常(非受检性异常),即运行的时候会出现的异常

        处理异常的方式:
            1、抛出异常:throws
                当出现异常,方法会终止运行
                当不知道该怎么处理异常时,向上抛出给调用方,由调用方处理
            2、捕获异常:try/catch
                try {
                    可能会出现异常的代码
                }catch (异常类型 异常对象) {
                    处理异常的方式
                }
              怎么用:当知道如何处理异常的时候使用try/catch,方法的运行不会被中断,继续执行
                      try块中出现异常,则不再执行try块中剩余的代码,直接结束try块的代码,执
                      行catch块中的代码
            3、抛出(声明)异常对象:throw
                更改异常说明信息,让异常定位更加准确

            解决异常:了解异常的类型,明白异常出现的原因,寻找异常出现的位置
 */

import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class Demo1 {                //throws FileNotFoundException 表示抛出异常
    public static void main(String[] args) throws FileNotFoundException {
        // ----------------一般异常(受检性异常)------------------
        test();

/*        try {
            FileInputStream file = new  FileInputStream("io.text");
        }catch (FileNotFoundException e) {
            e.printStackTrace();
        }*/

        // ----------------运行时异常(非受检性异常)------------------
        //数组下标越界异常      --      ArrayIndexOutOfBoundsException
        //int nums[] = {11,22,23};
        //print(nums);

        //空指针异常             --      NullPointerException
        //String str = null;
        //不会报空指针异常
        //System.out.println("".equals(str));
        //报空指针异常
        //System.out.println(str.equals(""));

        //类型转换异常        -- ClassCastException
//        Animal animal = new Animal();
//        Dog dog = (Dog)animal;

        //数字转换异常        -- NumberFormatException
//        String str = "abc";
//        int num = Integer.parseInt(str);
//        System.out.println(num);

        //算术异常          -- ArithmeticException
//        int num1 = 1;
//        int num2 = 0;
//        int num3 = num1/num2;
    }
    public static void print(int[] nums){
        System.out.println(nums[3]);
    }
    public static void test() throws FileNotFoundException {
        System.out.println("异常开始");
        FileInputStream file = new  FileInputStream("io.text");
        System.out.println("异常结束");
    }
}

class Animal{

}
class Dog extends Animal{

}

捕获异常

package com.qf.pan.exception2;/*
 * @author  pyh
 * @date  2020/11/30 0030 下午 4:43
 * @version 1.0
 * @since JDK1.8_241
        捕获异常
 */

import java.io.FileInputStream;
import java.io.FileNotFoundException;
public class Test01 {
    public static void main(String[] args) {
        int num = test();
        System.out.println("num:"+num);
    }
    public static int test(){
        try {
            return 1;
        }finally {
            return 11;
        }
    }

    //try/catch后面接finally,finally则一定会执行
/*    public static void main(String[] args) {
        System.out.println("异常开始");
        int num = 0;
        try {
            int[] nums = {1,2,3};
            //会报ArrayIndexOutOfBoundsException
            System.out.println(nums[3]);
            System.out.println("a");
            //会报FileNotFoundException
            FileInputStream fis = new FileInputStream("io.txt");
            System.out.println("b");
        } catch (Exception e) {
            //e.printStackTrace();
            //手动提示语句
            System.out.println("小老弟,出异常啦,赶紧找你老大");
        //一定执行的代码
        }finally {
            num = 11;
        }
        System.out.println("异常结束");
        System.out.println("num:"+num);
    }*/

    //一个try块多个异常,一个catch处理所有的异常
   /* public static void main(String[] args) {
        System.out.println("异常开始");
        try {
            int[] nums = {1,2,3};
            //会报ArrayIndexOutOfBoundsException
            System.out.println(nums[3]);
            System.out.println("a");
            //会报FileNotFoundException
            FileInputStream fis = new FileInputStream("io.txt");
            System.out.println("b");
        } catch (Exception e) {
            //e.printStackTrace();
            //手动提示语句
            System.out.println("小老弟,出异常啦,赶紧找你老大");
        }
        System.out.println("异常结束");
    }*/

   //一个try块中有多个异常,一个catch块可以处理多个异常,用|分隔开
/*     public static void main(String[] args) {
        System.out.println("异常开始");
        try{
            int[] num = {11,23,30};
            System.out.println(num[3]);//数组下标越界异常
            System.out.println("a");
            FileInputStream fis = new FileInputStream("io.txt");
        }catch (FileNotFoundException | ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
            //自己手动写提示语句
            System.out.println("文件不存在,请先创建文件");
        }
        System.out.println("异常结束");
    }*/

    //一个try可以捕获多个异常,多个catch分别进行处理
 /*   public static void main(String[] args) {
        System.out.println("异常开始");
        try{
            int[] num = {11,23,30};
            System.out.println(num[3]);//数组下标越界异常
            System.out.println("a");
            FileInputStream fis = new FileInputStream("io.txt");
        }catch (FileNotFoundException e) {
            e.printStackTrace();
            //自己手动写提示语句
            System.out.println("文件不存在,请先创建文件");
        }catch (ArrayIndexOutOfBoundsException e){
            e.printStackTrace();
        }
        System.out.println("异常结束");
    }*/
}

自定义异常类

package com.qf.pan.exception2;
//自定义异常类
import java.io.FileNotFoundException;

public class FileException extends FileNotFoundException {
    public FileException(String str){
        //调用父类的构造方法
        super(str);
    }
}

抛出异常对象

package com.qf.pan.exception2;
//抛出异常对象
import java.io.FileInputStream;
import java.io.FileNotFoundException;

public class Test02 {
    public static void main(String[] args) {
        try {
            FileInputStream fis = new FileInputStream("io.txt");
        } catch (FileNotFoundException e) {
            try {
                throw new FileNotFoundException("com.qf.ran.exception2的Demo02的第15代码出错了");
            } catch (FileNotFoundException ex) {
                ex.printStackTrace();
            }
            /*
            自定义异常
            try {
                throw new FileException("io.txt文件还没创建");
            } catch (FileException e1) {
                e1.printStackTrace();
            }*/
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值