Java进阶

Java进阶,枚举,注解

参考文献:https://www.cnblogs.com/liangbaolong/p/12884224.html

1、枚举

  • jdk1.5引入了枚举类型

  • 格式
    enum 枚举名{
        枚举体(常量列表)
    }
    

    枚举体就是存放一些常量。

  • 示例

    enum Season{
        SPRING,SUMMER,AUTUMN,WINDER
    }
    
  • 注意事项

    所有的枚举类型隐性的继承java.lang.Enum,枚举实质上还是类!而枚举的每个成员实质就是一个枚举类型的实例,它们默认都是public static final修饰的,可以直接通过枚举名称使用它们;

  • image-20211109175250498

  • 代码示例
    package day07;
    
    public class DemoTest {
        public static void main(String[] args) {
            System.out.println(Season.AUTUMN);
    
            Season a= Season.WINTER;
    		//复习switch语法,每个case之后都需要添加break;
            switch (a){
                case AUTUMN:
                    System.out.println("秋天来了");
                    break;
                case SPRING:
                    System.out.println("春天来了");
                    break;
                case SUMMER:
                    System.out.println("夏天来了");
                    break;
                default:
                    System.out.println("那就是冬天了");
            }
        }
    }
    
    enum Season{
        SPRING,SUMMER,AUTUMN,WINTER
    }
    /*
    AUTUMN
    那就是冬天了
    */
    

2、反射

  • 框架设计的灵魂;

2.1 概念

  • 将类的各个组成部分封装为其他对象,这这就是反射机制

  • image-20211110085739432

  • 好处

    1、可以在程序运行中,可以操作这些对象;

    2、可以解耦,提高程序的可扩展性

2.2 获取Class对象的方式

  • 1、Class.forName("全类名"):将字节码文件加载进内存,返回Class对象

    • 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
  • 2、类名.Class:通过类名的属性class获取

    • 多用于参数传递
  • 3、对象.getClass()方法在Object类中定义这=着

    • 多用于对象获取字节码的方式
  • 结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。

  • image-20211110091143060

  • 代码示例
    package day07;
    
    import day07.reflict.Person;
    
    public class DemoRefct {
        public static void main(String[] args) throws Exception{
            //1.
            Class cls=Class.forName("day07.reflict.Person");//需要将方法的异常抛出
            System.out.println(cls);//class day07.reflict.Person
            //2
            Class cls1=Person.class;
            System.out.println(cls1);//class day07.reflict.Person
            Person per= new Person("张三",20);
            Class cls2=per.getClass();
            System.out.println(cls2);//class day07.reflict.Person
    
            System.out.println(cls1 == cls2);//true
            System.out.println(cls1 == cls);//true
            //同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个。
        }
    }
    
    

2.3 Class对象功能

  • 介绍

    image-20211110093636932

  • 获取成员变量

    image-20211110095302636

    image-20211110095407883

    • 代码示例

      package day07.reflict;
      
      public class Person {
          private String name;
          private int age;
      
          public String a;
          protected String b;
          String c;
          private String d;
      
          public Person() {
          }
      
          public Person(String name, int age) {
              this.name = name;
              this.age = age;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public int getAge() {
              return age;
          }
      
          public void setAge(int age) {
              this.age = age;
          }
          //构造函数可以是私有的通常使用的是单利设计模式和反射的时候使用,一般不建议使用;
      //    private void Person(){
      //
      //    }
      
      
          public String getA() {
              return a;
          }
      
          public void setA(String a) {
              this.a = a;
          }
      
          public String getB() {
              return b;
          }
      
          public void setB(String b) {
              this.b = b;
          }
      
          public String getC() {
              return c;
          }
      
          public void setC(String c) {
              this.c = c;
          }
      
          public String getD() {
              return d;
          }
      
          public void setD(String d) {
              this.d = d;
          }
      
          @Override
          public String toString() {
              return "Person{" +
                      "name='" + name + '\'' +
                      ", age=" + age +
                      ", a='" + a + '\'' +
                      ", b='" + b + '\'' +
                      ", c='" + c + '\'' +
                      ", d='" + d + '\'' +
                      '}';
          }
          public void eat(){
              System.out.println("准备吃饭");
          }
          public void eat(String food){
              System.out.println("准备吃饭吃的是"+food);
          }
      }
      
      
      package day07;
      
      import day07.reflict.Person;
      
      import java.lang.reflect.Field;
      import java.util.Objects;
      
      public class DemoReFileds {
          public static void main(String[] args) throws Exception{
              //Class对象获取
              //1 、获取成员变量们
      
              //获取类对象
              Class cls=Person.class;
              //Field[] getFields();获取所有使用public修饰的成员变量
              Field[] fields =cls.getFields();
              System.out.println(fields);//返回fildes的数组,直接打印显示地址值
              for(Field fied:fields){
                  //循环打印
                  System.out.println(fied);
                  //public java.lang.String day07.reflict.Person.a
              }
              //直接将变量名进行赋值
              Person pp= new Person();
              Field d=cls.getField("a");//需要抛出异常
              System.out.println(d);//public java.lang.String day07.reflict.Person.a
              System.out.println("================================");
              d.set(pp,"张三");//通过反射进行赋值;
              System.out.println(pp);
              //获取所有的变量字段,
              Field[] anyfileds=cls.getDeclaredFields();
              for(Field field:anyfileds){
                  System.out.println(field);
              }
              //访问私有
      
              Field fied2= cls.getDeclaredField("d");
              //忽略安全修饰符的权限
              fied2.setAccessible(true);//暴力反射,变量存在,方法与构造方法也存在
              Person p =new Person();
              Object value=fied2.get(p);
              System.out.println(value);
          }
      
      
      }
      
      /*
      [Ljava.lang.reflect.Field;@14ae5a5
      public java.lang.String day07.reflict.Person.a
      public java.lang.String day07.reflict.Person.a
      ================================
      Person{name='null', age=0, a='张三', b='null', c='null', d='null'}
      private java.lang.String day07.reflict.Person.name
      private int day07.reflict.Person.age
      public java.lang.String day07.reflict.Person.a
      protected java.lang.String day07.reflict.Person.b
      java.lang.String day07.reflict.Person.c
      private java.lang.String day07.reflict.Person.d
      null
      */
      
  • 构造方法
    • image-20211110095945550

    • 代码示例
      package day07;
      
      import day07.reflict.Person;
      
      import java.lang.reflect.Constructor;
      
      public class DemoConStructor {
      
          public static void main(String[] args) throws Exception{
              //获取类对象
              Class cls= Person.class;
              //获得构造器
              Constructor constructor=cls.getConstructor(String.class,int.class);
              System.out.println(constructor);
      
              //创建对象:
              Object person=constructor.newInstance("张三",30);
              System.out.println(person);//有参构造创建对象
              //cls.newInstance("张三",20);
              //constructor.setAccessible(true);也可以使用暴力反射
              System.out.println("=============");
              //无参构造也可以想上述一样,只要不传参数,创建的就是无参构造的对象
              //或者简写,使用Class.newInstance();
              Object o= cls.newInstance();
              System.out.println(o);
      
          }
      }
      /*
      public day07.reflict.Person(java.lang.String,int)
      Person{name='张三', age=30, a='null', b='null', c='null', d='null'}
      =============
      Person{name='null', age=0, a='null', b='null', c='null', d='null'}
      */
      
  • 成员方法与类名称
    • image-20211110100724388

    • 代码示例
      package day07;
      
      import day07.reflict.Person;
      
      import java.lang.reflect.Method;
      
      public class DemoMethod {
          public static void main(String[] args) throws Exception{
      
              Class cls = Person.class;
              //获取指定名称的方法
              Method eat_method= cls.getMethod("eat");
              Person p= new Person();
              //执行方法
              eat_method.invoke(p);
      
              System.out.println("======================");
              //执行待参数的方法
              Method eat_method2=cls.getMethod("eat",String.class);
              eat_method2.invoke(p,"板面");
      
              //获取所有public的修饰方法
              Method[] methods= cls.getMethods();
              for(Method method:methods){
                  System.out.println(method);//打印接过包含默认继承的Object上面;
                  String name =method.getName();//获取方法的名字
                  System.out.println(name);
              }
              String classname= cls.getName();//获取类名
              System.out.println(classname);//全类名:day07.reflict.Person
          }
      }
      /*
      准备吃饭
      ======================
      准备吃饭吃的是板面
      public java.lang.String day07.reflict.Person.toString()
      toString
      public java.lang.String day07.reflict.Person.getName()
      getName
      public void day07.reflict.Person.setName(java.lang.String)
      setName
      public void day07.reflict.Person.eat()
      eat
      public void day07.reflict.Person.eat(java.lang.String)
      eat
      public int day07.reflict.Person.getAge()
      getAge
      public void day07.reflict.Person.setAge(int)
      setAge
      public java.lang.String day07.reflict.Person.getA()
      getA
      public void day07.reflict.Person.setA(java.lang.String)
      setA
      public java.lang.String day07.reflict.Person.getB()
      getB
      public void day07.reflict.Person.setB(java.lang.String)
      setB
      public java.lang.String day07.reflict.Person.getC()
      getC
      public void day07.reflict.Person.setC(java.lang.String)
      setC
      public java.lang.String day07.reflict.Person.getD()
      getD
      public void day07.reflict.Person.setD(java.lang.String)
      setD
      public final void java.lang.Object.wait() throws java.lang.InterruptedException
      wait
      public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
      wait
      public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
      wait
      public boolean java.lang.Object.equals(java.lang.Object)
      equals
      public native int java.lang.Object.hashCode()
      hashCode
      public final native java.lang.Class java.lang.Object.getClass()
      getClass
      public final native void java.lang.Object.notify()
      notify
      public final native void java.lang.Object.notifyAll()
      notifyAll
      day07.reflict.Person
      */
      
  • 案例图片
    • 由于反射主要用来设计框架,一般用不到,知道其原理方便阅读框架的源码,此处不在使用代码实现

    • image-20211110115429991

      image-20211110115359729

      image-20211110115518109

      image-20211110115618869

3、注解

3.1 概念

  • 注释

    • 用文字描述注释,给程序员看的;
  • 注解(Annotation)

    • 也叫元数据。一种代码级别的说明。JDK1.5之后的特性,与类,接口,枚举一个层次;

    • 作用分类

      1、编译检查:通过代码里标识的注解,让编译器能够实现基本的编译检查Override

      2、编写文档:通过代码里标识的注解,生成对应的doc文档

      package day07;
      /**
       * 注解javadoc演示
       *
       * @author ziqingbaojian
       * @version 1.0
       * @since 1.5
      */
      public class AnnoDemo {
      
      
          /**
           * 计算两数的和
           * @param a 整数
           * @param b 整数
           * @return 两数的和
           */
          public int add(int a,int b){
              return a+b;
          }
      }
      
      

      image-20211109211451745

      生成文档的命令javadoc 类

      image-20211109211909887

      生成指定的文件

      image-20211109211940969

      image-20211109212049519

      存在乱码,由于改功能使用较少,因此不做专门的修正,主要是使用下面的代码分析

      3、代码分析:通过代码里标识的注解,对代码进行分析使用反射

    • 使用注解:@注解名称

3.2 JDK中预定义的注解

  • @Override
    • 检测被该注解标注的方法是否继承自父类(接口)的
  • @Deprecated
    • 该注解标注的内容,表示已过时
  • @SuppressWarnings
    • 压制警告
    • 一般需要传递参数all,使用方式@SuppressWarnings("all")
  • 代码示例
    package day07;
    
    import java.util.Date;
    
    public class DemoZJ {
    
        private String name;
    
        @Override
        public String toString() {
            return "DemoZJ{" +
                    "name='" + name + '\'' +
                    '}';
        }//检测toString()方法是否是父类的方法,一般重写的时候都要加上
    
        @Deprecated
        public void show1(){
            //有缺陷
        }//@Deprecated表示函数show1已过时,不推荐使用
    
    
        public void show2(){
            //替代show1
        }
        public void demo(){
            Date date = new Date();
            date.getDate();//代码上有横线表示方法已过时,但是不影响运行,实例化对象的时候如果调用show1方法效果相同;
    
        }
    }
    
    

    不使用注解@SuppressWarnings("all")

    image-20211110170724496

    使用注解@SuppressWarnings("all")时,警告会全部被压制;

    image-20211110170835763

3.3 自定义注解

  • 格式

    public @interface 注解名称{
       	//属性名称
    }
    
  • 代码示例

    package day07.zhujie;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    //自定义注解
    @Target(ElementType.TYPE)//一般自己定义的的时候都会写上@Target描述作用域,TYPE代表类,METHOD代表方法,FIED代表字段
    @Retention(RetentionPolicy.RUNTIME)//参数一般是RetentionPolicy.RUNTIME
    public @interface MyAnnotation {
        String name();
    }
    
    
  • 元注解(用于描述注解的注解)
    • @Target:描述注解能够作用的位置

      参数:ElementType的取值:

      ​ TYPE,类;METHOD代表方法,FIED代表字段

    • @Retention描述注解别保留的阶段

    • @Documnted:描述注解是否被抽取到API文档中

    • @Inherited:描述注解是否别子类继承

  • 注解中的属性

    属性接口中的抽象方法;

    • 要求:
    • 属性的返回值有下列取值
      • 基本数据类型
      • String(其他自定义的引用类型也不可以,仅限于String)
      • 注解
      • 以上类型的数组

    使用属性,使用时赋值

    • 定义属性时使用default关键字给属性默认初始值,则使用注解时可以不进行赋值。
    • 如果只有一个属性需要赋值,并且属性名称是value,则value可以省略,直接定义即可;
    • 数组赋值时,值使用{ }包裹,如果数组只有一个值,则{ }省略;
  • image-20211110172329856

  • image-20211110173654625

  • 代码示例
    //注解使用传参;
    package day07.zhujie;
    
    //注解的使用,strs是数组类型的参数因为只有一个值所以省略{},nums要用{值,值,值}进行传参
    @MyAnnotation(name = "张三",strs = "罗老师",nums = {2,3,4}/*,sex = "女"*/)//作用域是类,注释木部分的参数存在默认值,可以不传参
    public class Student {
        @check("HelloWorld")//注解中的属性是`value`,因此不需要写名称直接传入
        public void func(){
            System.out.println("SSSS");
        }
        public void func2(){
    
        }
    }
    
    
    //自定义注解
    package day07.zhujie;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    //自定义注解
    @Target(ElementType.TYPE)//一般自己定义的的时候都会写上@Target描述作用域,TYPE代表类,METHOD代表方法,FIED代表字段
    @Retention(RetentionPolicy.RUNTIME)//参数一般是RetentionPolicy.RUNTIME
    public @interface MyAnnotation {
        String name();
        String[] strs();
        int[] nums();
        String sex() default "男";//使用default给属性赋值,当参数不传递的时候默认为男;
    }
    
    
    //定义注解
    package day07.zhujie;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface check {
        String value();
    }
    

3.4 在程序中(解析)注解

  • 获取注解定义位置的对象

  • 获取指定注解

    • getAnnotation(Class)
  • 调用注解中的抽象方法获取属性值;

  • 代码示例
    package day07.zhujie;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    //自定义注解
    @Target(ElementType.TYPE)//一般自己定义的的时候都会写上@Target描述作用域,TYPE代表类,METHOD代表方法,FIED代表字段
    @Retention(RetentionPolicy.RUNTIME)//参数一般是RetentionPolicy.RUNTIME
    public @interface MyAnnotation {
        String name();
        String[] strs();
        int[] nums();
        String sex() default "男";//使用default给属性赋值,当参数不传递的时候默认为男;
    }
    
    
    package day07.zhujie;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface check {
        String value();
    }
    
    
    在类中使用注解
    package day07.zhujie;
    
    //注解的使用,strs是数组类型的参数因为只有一个值所以省略{},nums要用{值,值,值}进行传参
    @MyAnnotation(name = "张三",strs = "罗老师",nums = {2,3,4}/*,sex = "女"*/)//作用域是类,注释木部分的参数存在默认值,可以不传参
    public class Student {
    
        @check("HelloWorld")//注解中的属性是`value`,因此不需要写名称直接传入
        public void func(){
            System.out.println("SSSS");
        }
        public void func2(){
            System.out.println("我没带注解,我不会被解析的");
        }
    
    }
    
    
    注解的解析,即一般的框架中注解后台的执行过程
    package day07.zhujie;
    
    import java.lang.reflect.Method;
    import java.security.Signature;
    
    public class DemoMain {
        public static void main(String[] args) throws Exception{
            //使用反射获取字节码对象
            Class<Student> demomain= Student.class;
            //获取注解定义位置对象;其实就是在内存中生成了一个该注解接口的子类实现对象
            MyAnnotation myanno= demomain.getAnnotation(MyAnnotation.class);
            System.out.println(myanno);
            /*
            相当于:
            public calss MyAnnotationimpl implements MyAnnotation{
                重写方法;
            }
            * */
            String name=myanno.name();//获取属性值
            String sex=myanno.sex();
            int[] arr=myanno.nums();
            String[] strarr= myanno.strs();
            System.out.println("名字是"+name);
            System.out.println("性别默认是"+sex);
            for(int item:arr){
                System.out.println(item);//遍历结果数组
            }
            for (String s:strarr){
                System.out.println(s);
            }
    //        获取注解的位置的对象
    //        check cc=demomain.getAnnotation(check.class);//错误写法
    //        String value=cc.value();//获取唯一的属性值value;报错
    //        System.out.println(value);
            //获取注解的位置对象,首先根据反射获取到对应的函数然后在使用对应的解析
            check cc= Student.class.getMethod("func").getAnnotation(check.class);
            String value= cc.value();//获取唯一的属性值value
            System.out.println(value);
    
            //获取注解的位置对象,即获取方法的注解对象
    //        check cc =demomain.getAnnotation(check.class);
    
    
            System.out.println("======================");
            //使用反射执行带有注解的方法
            //1、创建学生对象
            Student stu = new Student();
            //2.获取字节码对象
            Class cls=stu.getClass();
            //3.获取所有的方法
            Method[] methods=cls.getMethods();
            for(Method method:methods){
                //4.判断方法上是否有check注解
                if(method.isAnnotationPresent(check.class)){
                    //5.有,执行
                    method.invoke(stu);//需要抛出异常,直接在主方法头部添加throws
                    System.out.println("执行了带注解的方法");
                }
            }
    
        }
    }
    /*
    @day07.zhujie.MyAnnotation(sex=男, name=张三, strs=[罗老师], nums=[2, 3, 4])
    名字是张三
    性别默认是男
    2
    3
    4
    罗老师
    HelloWorld
    ======================
    SSSS
    执行了带注解的方法
    */
    
  • 注意

    注解不必过于深究,一般在框架内都会使用别人(框架开发者)定义好的注解,无需投入过多;

  • 小结

    • 大多数,使用注解,而非自定义注解
    • 注解给谁用
      • 编译器
      • 给解析程序用
    • 注解不是程序的一部分,可以理解为注解就是一个标签。

4、异常的处理

  • 注:此处就不在记录异常的分类,错误与异常的区别,异常解析等概念型问题;
  • 切记,Error是Throw不是Exception

4.1 try-Catch结构

  • image-20211111094111442

  • Exception
    • Exception是所有异常类的父类;
    • Exception e如果扑捉到子类中的异常属于多态定义的对象;
  • catch中的异常处理

    image-20211111101334887

    注意:一个try可以有多个catch,会跟从上到下依次检查,但是有多个的时候Exception不能是第一个
    try{
        
    }catch(ClassCastException e){
        //Exception 不能写在第一个,因为可以扑捉到所有的异常,后面额catch就不会执行;
        //Exception通常写在最后一个
    }catch(Exception e){
        
    }
    

    输出异常

    • 输出自定义的信息
    • 调用方方法
    • 向上抛:注意这种方法使用后,后面的代码就不执行了;

    Catch后面的语句不执行

    • throw e 后面的不会执行;
    • catch中的异常类型不匹配,JVM会直接向上抛,后面的不执行;
    • 遇到了return语句,也会不在执行;
  • finally语句
    • 即使遇到了catch后面不执行的3种情况;

      如果遇到return会先执行finally语句,再执行return语句;

    • 一般用来关闭I/O流;关闭数据库的连接;

    • 例外:程序中出现了System.exit(0);后面的都不执行;

      • System.exit(0);退出虚拟机;
  • 常见的异常类型

    image-20211111101544301

  • 代码示例
    package day08;
    
    public class TryC {
        public static void main(String[] args) {
            try {
                System.out.println("步骤一");
                System.out.println(1/0);//出异常
                System.out.println("步骤二不执行");
            }catch(Exception e){//异常匹配执行catch中语句,执行完之后执行后面的语句;当try中不出现异常的时候,直接执行catch代码块后的戴安啊
                //Exception e= new ArithmeticException(),因为Exception是ArithmeticException的间接父类,可以捕获到,而且异常对象属于多态定义的写法
                //直接打印
                System.out.println(e.toString());//输出异常
                System.out.println(e);//输出异常
                //1、输出自定义的信息
                System.err.println("除数不能为0");//使用err输出是一般会在控制台的尾部,红色输出
                //2、输出系统信息,比较详细使用较多;
                e.printStackTrace();
                //3、只输出提示信息
                System.out.println(e.getMessage());
    
                System.out.println("步骤三,如果异常匹配正确则执行");
                //4、向上继续抛
    //            throw e;//注意一旦使用throw e后面的代码就不执行了;
            }finally {
                System.out.println("我执行了");
            }
            System.out.println("步骤四:执行");
            System.out.println("=========================");
            try {
                System.out.println("步骤一");
                System.exit(0);//直接退出虚拟机后面的都不执行
                System.out.println("-----------------");
                System.out.println(1/0);//出异常
                System.out.println("步骤二不执行");
            }catch(ArrayIndexOutOfBoundsException e){//异常不匹配,不执行catch中的语句直接报错,抛出异常
                System.out.println(e);//输出异常类型
                System.out.println("步骤三,如果异常匹配正确则执行");
            }finally {
                System.out.println("就算出错了也必须执行");
            }
            System.out.println("步骤四:执行");
        }
    
    }
    /*
    除数不能为0
    java.lang.ArithmeticException: / by zero
    	at day08.TryC.main(TryC.java:7)
    步骤一
    java.lang.ArithmeticException: / by zero
    java.lang.ArithmeticException: / by zero
    / by zero
    步骤三,如果异常匹配正确则执行
    我执行了
    步骤四:执行
    =========================
    步骤一
    */
    

4.2 throw和throws

  • 补充
    检查异常
    1:checked (检查型异常)也就是我们经常遇到的IO异常,以及SQL异常都是这种异常。编译器要检查这类异常,检查的目的一方面是因为该类异常的发生难以避免, 另一方面就是让开发者去解决掉这类异常,所以称为必须处理(try ...catch)的异常。如果不处理这类异常,集成开发环境中的编译器一般会给出错误提示。
    

    注意:如果一个方法没有捕获一个检查性异常,那么该方法必须使用 throws 关键字来声明。throws 关键字放在方法名的后边,eg: 方法名() throws IOExecption。

    运行是异常
    2:runtime exception(运行时异常),编译器不会检查这类异常,不检查的则开发者在代码的编辑编译阶段就不是必须处理,这类异常一般可以避免,因此无需处理(try ...catch)
    

    如果不处理这类异常,集成开发环境中的编译器也不会给出错误提示。 当出现这样的异常时,总是由虚拟机接管。我们从来没有人去处理过NullPointerException异常,它就是运行时异常,并且这种异常还是最常见的异常之一;

    标签: 检查型异常和运行时异常的异同, 检查型异常和非检查型异常的区别, 非检查型异常(UncheckedException), 非运行时异常, 运行时异常(RuntimeException), 检查型异常(CheckedException), java

  • 注意:遇到throw程序也会到此结束,后面的不在运行;
  • image-20211111112158887

  • image-20211111112231026

  • 代码示例
    package day08;
    
    public class Throw {
    
        //运行时异常
        public void show(int age){
            if(age<0){
                //注意:throw抛出运行是异常,不需要处理,编译的时候虚拟机会处理
                throw new RuntimeException("年龄不能是负数");
            }
        }
        /*使用自定义的运行时异常*/
        public void show1(int age){
            if(age<0){
                throw new AgeRunException("年龄不能是负数");
            }
        }
        //检查是异常
        public void func(int age) throws Exception{
            if(age>1000) {
                //检查异常,必须进行处理,可以自身使用try-catch处理,但是一般都会选择在方法头上抛出
                throw new Exception("大于1000,你可能吃了长生不老药了");
            }
        }
    
        public void usefunc1() throws Exception{
            func(10002);//使用了向上抛出异常func函数,必须处理,此处使用的是继续向上抛
        }
        public void usefunc2(){
            try {
                func(10001);//使用了向上抛出异常的函数func必须处理,因此使用try-catch进行处理
            }catch (Exception e){
                e.printStackTrace();
            }
        }
        // 使用自定义的检查异常
        public void func3(int age) throws Exception{
            if(age>2000){
                throw new AgeExpection("大于2000,你可能吃了长生不老药了");
            }
        }
    
    }
    
    
  • package day08;
    
    public class DemoMain {
        public static void main(String[] args) {
            //实例化对象
            Throw t1= new Throw();
            //调用运行时异常的函数,均不需要处理
            t1.show(-2);
            // 调用自定义的运行时异常
            t1.show1(-30);
    
            /******调用检查异常******/
            try{//使用的是向外抛出的异常,因此需要进行处理
                t1.func(200000);
            }catch (Exception e){
                System.out.println("扑捉到了,我接着运行");
            }
            try{//使用的是向外抛出的异常,因此需要进行处理,因为usefunc1也是调用了func1并且继续向上抛出异常,因此也要处理
                t1.usefunc1();
            }catch (Exception e){
                System.out.println("扑捉到了,我接着运行");
            }
            //使用自定义的检查异常
            try{//使用的是向外抛出的异常,因此需要进行处理
                t1.func3(200000);
            }catch (Exception e){
                System.out.println("扑捉到了,我接着运行");
            }
            System.out.println("============");
            t1.usefunc2();//usefunc2中已经处理func抛出的异常,因此不需要进行处理
        }
    }
    
    
  • 代码运行结果

  • image-20211111120515466

  • image-20211111120449575

  • image-20211111121236320

5、I/O

  • 切记:输入与输出都是相对内存而言的;
  • 注意:中文占字节
    • utf8 占3位
    • gbk 占2位
  • 读文件到结尾一般返回-1

5.1概述

image-20211111152414609

  • 一切皆为字节

image-20211112165604772

5.2 字节输出流

  • OutputStream
  • OutputStream该抽象类是所有类的字节输出流的父类。输出流接受输出字节,并将它们发送到一些接收器。

5.3 FileOutputStream类

  • 构造方法
    • FileOutputStream(String name) 创建一个文件输出流,用指定的名称写入文件。

    • FileOutputStream(File file) 创建一个文件输出流写入指定的 File对象表示的文件。

    image-20211112172711690

  • 写入数据(内存------>硬盘)
  • image-20211112173838666

  • 代码示例
    package day09;
    
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.nio.charset.StandardCharsets;
    
    public class DemoMain {
        public static void main(String[] args) throws IOException {
            //1.创建对象,构造方法中写入数据目的地
            FileOutputStream fos= new FileOutputStream("E:\\javacode\\start\\src\\day09\\a.txt");
            //2. 使用write方法吧数据写到a.txt中
            fos.write(97);//显示是a,记事本以字节的方式展示
            
    
            System.out.println("========");
            byte[] bytes={-65,66,67,68};
            fos.write(bytes);//直接写入数组,第一个是负数,会和第二个转换为中文
            byte[] bytes1="你好".getBytes();
            fos.write(bytes1);
            //3.释放资源,流的使用会占用内存中的资源
            fos.close();
        }
    }
    
    
    

    image-20211112175107981

5.4 字节输入流

  • image-20211112180320755

  • image-20211112180600205

5.5 FileInputStream

  • 代码示例
    package day09;
    
    import java.io.FileInputStream;
    import java.io.IOException;
    
    public class DemoInPut {
        public static void main(String[] args) throws IOException {
            FileInputStream fis=new FileInputStream("E:\\javacode\\start\\src\\day09\\a.txt");
            int len=fis.read();//每次读取一个字符读取到最后返回-1
            System.out.println(len);//97
            len=fis.read();
            System.out.println(len);//98
            len=fis.read();
            System.out.println(len);//-1;结束返回-1    
        }
    }
    

image-20211112181820847

  • image-20211112182145346

5.6 字符输入流

  • Reader所有字符的超类

5.7 FileReader

1、创建对象

2、读取文件

3、释放资源

  • image-20211112183445744

  • image-20211112183923264

  • 代码示例
    package day09;
    
    import java.io.FileReader;
    import java.io.IOException;
    
    public class DemoReader {
        public static void main(String[] args) throws IOException {
            //1.创建对象
            FileReader fr=new FileReader("E:\\javacode\\start\\src\\day09\\a.txt");
            //2.读取
            char[] cs=new char[1024];
            int len=0;//记录有效字符个数
            while((len=fr.read(cs))!=-1){//结束标志依旧是-1
                System.out.println(new String(cs,0,len));//使用String 的构造方法使得字符的数组转换成为字符串
                //字符串的构造方法中还有对应的字节数组转换为字符串,将字节数组转换为字符转;
                //注意事项:两个构造方法均含有两种方式
                    //1.将数组的全部转换为元素转换成字符串
                    //2.将数组的一部分(有效部分),转换为字符串;String('数组','有效长度')
                System.out.println(len);
            }
            //3.释放资源
            fr.close();
        }
    }
    
    

5.8 字符输出流

  • image-20211112184428749

  • image-20211112184807023

  • flush与close的区别

    image-20211112185033535

  • image-20211112185312095

  • 换行和续写

    image-20211112185652322

  • 代码示例
    package day09;
    
    import java.io.FileWriter;
    import java.io.IOException;
    
    public class DemoOut {
        public static void main(String[] args) throws IOException {
            FileWriter  fw=new FileWriter("E:\\javacode\\start\\src\\day09\\a.txt");
            fw.write(97);
            fw.flush();//会刷新资源,刷新完成之后可以继续使用
            fw.write(99);
            //换行和续写
            fw.write("\r\n");//换行符号
            fw.write("你好世界");
            fw.close();//释放资源(会先把内存缓冲区的三个月后呀刷新到文件中)
        }
    }
    
    

缺漏之处,欢迎大神前来斧正;

原文地址:https://www.cnblogs.com/Blogwj123/p/15557641.html