欢迎来到三一办公! | 帮助中心 三一办公31ppt.com(应用文档模板下载平台)
三一办公
全部分类
  • 办公文档>
  • PPT模板>
  • 建筑/施工/环境>
  • 毕业设计>
  • 工程图纸>
  • 教育教学>
  • 素材源码>
  • 生活休闲>
  • 临时分类>
  • ImageVerifierCode 换一换
    首页 三一办公 > 资源分类 > PPT文档下载  

    《Java程序设计基础》第7章:例外处理.ppt

    • 资源ID:6525840       资源大小:730.50KB        全文页数:65页
    • 资源格式: PPT        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    三方登录下载: 微信开放平台登录 QQ登录  
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)
    支付方式: 支付宝    微信支付   
    验证码:   换一换

    加入VIP免费专享
     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    《Java程序设计基础》第7章:例外处理.ppt

    第7章 例外处理,学习重点:例外机制Java定义的例外类如何定义自己的例外类,第7章 例外处理,7.1 例外的概念 程序中的错误 例外的概念 例外控制机制 7.2 Java定义的例外类 Java中的例外类 例外类使用中的两个问题 例外在继承关系中的特殊性 例外的重新抛出 7.3 关于finally finally的使用方法 finally用在哪里 finally的缺陷 7.4 定义自己的例外 7.5 练习题,7.1 例外的概念,例外是一种对象,它是在某种运行错误时被创建的,例外控制机制是Java用来进行例外控制的一种有效手段。,7.1.1 程序中的错误,编译错误 程序的编制存在语法错误,编译器能检查出这种错误,此时程序不能继续运行。我们在以前的程序编制和运行中可能已经遇到过编译错误的情况,可以根据系统的提示加以修改运行错误 程序在执行过程中产生的错误,它很有可能产生不可意料的结果,有时可能对系统有严重的危害,如计算机的瘫痪。,常见的运行错误表现为两个方面:一是对操作系统产生影响,出现死机、死循环等现象 二是程序的运行结果和编程者的意图不符 排除运行错误的手段:使用开发环境提供的单步运行机制和设置断点来暂停程序运行,一步步发现错误,或打印一部分的中间结果用于分析,找到错误。,7.1.2 例外的概念,例外(Exception),在其他材料上可能被译为“异常”,指程序在执行过程中出现程序本身没有预料到的情况,从而导致程序错误结束。例外机制就是用来在发生运行异常时,告诉程序如何控制自身的运行,以防止错误的进一步恶化。,例外是一个对象,它在程序运行异常的时候被创建出来,并被在发生错误的位置抛出(throw),由一定的接收机制来接收并处理,这就是例外处理的一个简单过程例外的产生一定有条件的,例外条件与普通问题的区别:在普通问题的情况下,在当地可能有足够的信息,可在某种程度上解决碰到的问题。在例外条件的情况下,却无法继续下去,因为当地没有提供解决问题所需的足够多的信息。此时,我们能做的惟一事情就是跳出当地环境,将那个问题委托给一个更高级的负责人。这便是出现例外时的情况。,产生一个例外时,会发生几件事情,首先,按照与创建Java对象一样的方法创建例外对象:使用new来创 建。随后,停止当前执行路径(记住不可沿这条路径继续下去),然后从 当前的环境中释放出例外对象的地址。此时,例外控制机制 会接管一切,并把程序运行转移到另一个地方,这个地方可 称为例外控制器,它的职责是解决这个运行问题,要么使程 序简单地继续,要么结束程序并报错。,产生例外的一个简单示例,假设有一个名为t的对象,它只是被定义,而还没有在内存中创建,这个对象名并未指向任何实际的内存地址 if(t=null)throw new NullPointerException();/“抛”出了一NullPointerException类的例外抛出这个例外后,“例外控制器”就会处理这个问题。,7.1.3 例外控制机制,1.例外处理的语法结构 对于Java的例外控制机制,Java把可能产生例外的代码段形成一个区域,可称为“警戒区”,然后紧接例外控制器。警戒区由try引导,例外控制器由catch引导,一个警戒区可以接多个catch从句,以对应多种例外。结构如下:try可能产生例外的代码段;catch(例外类名1 对象名1)处理语句组1;catch(例外类名2 对象名2)处理语句组2;try块一般位于一个方法的内部,它用来包含有可能抛出例外的程序段,try块的格式如下:,try 可能产生例外的代码段try块中的代码段可以是几个简单语句,也可以是方法的调用,也可以是很复杂的结构,如以下的一种情况都可以:trythrow new ExceptionName();tryfunctionA();/这个方法的调用可能产生例外tryint i=0;for(i=0;i100;i+)catch块是专门用来捕获例外的地方,在try块内部,不同的方法调用可能生成相同的例外,但只需要一个控制器。另外,在通常情况下,遇到例外时,程序会自行中断,而转到catch程序去继续执行,出现例外的语句后面的逻辑都将不再被执行,例7.1 例外处理 这个程序的处理逻辑是,在初始化时,创建一个类似数组的对象vector(关于vector的使用在后面章节介绍),像其中存储09十个数字,然后将这些数字取出来写入一个文件OutFile.txt中,如果这个文件不存在于当前目录中,就创建一个新文件。在程序中粗体字的部分都可能出现错误,因此,需要进行例外处理程序逻辑已经预计到的例外有两方面,一是数组下标出界,即ArrayIndexOutOfBoundsException二是IO错误,即IOException,并在两处catch语句中都做了相应处理,ListOfNumbers.java的源程序如下:import java.io.*;import;public class ListOfNumbers public static void main(String args)ListOfNumbers list=new ListOfNumbers();list.writeList();private Vector victor;private static final int size=10;public ListOfNumbers()victor=new Vector(size);for(int i=0;i size;i+)victor.addElement(new Integer(i);public void writeList()PrintStream out=null;try System.out.println(Entering try statement);/打开向文件写入的输出流,在这句话执行过程中可能会出现错误 out=new PrintStream(new FileOutputStream(OutFile.txt);/向输出流中写内容,也可能出现错误 for(int i=0;i size;i+)out.println(Value at:+i+=+victor.elementAt(i);catch(ArrayIndexOutOfBoundsException e)System.err.println(Caught ArrayIndexOutOfBoundsException:+e.getMessage();catch(IOException e)System.err.println(Caught IOException:+e.getMessage();,假如对程序做一点修改,将“for(int i=0;i size;i+)”改为“for(int i=0;i=size;i+)”,就会得到如图所示的结果,另外一种修改,将上次执行时已经产生的OutFile.txt文件的属性修改为只读,然后再执行程序,就会得到的结果如图所示,2.Java中对例外的规定,在Java中,每个方法必须对它可能抛出的例外进行预先声明,这就是方法头中throws后面的内容,也就是说在定义方法时,必须声明这个方法可能会抛出哪一种或几种例外。两个方法头的定义:/它可能抛出tooBig,tooSmall,divZero3个例外类的例外void f()throws tooBig,tooSmall,divZero/它不会抛出任何例外void f()/.,Java在编译期间就进行例外控制情况的检查,如果某个方法可能抛出例外,而程序没有使用throws指明这个例外,或者没有使用try/catch语句对例外进行处理,编译器都会给出提示,并告诉我们必须对这个例外进行控制,例如,我们在上面讲到的ListOfNumber.java中如果不进行例外处理,即去掉try/catch语句,编译时会得到如下结果:ListOfNumbers.java:24:unreported exception;mustbe caught or declared to be thrown out=new PrintStream(new FileOutputStream(OutFile.txt);1 error,Java允许声明抛出一个并没有发生的例外,编译器能理解我们的要求,并强迫使用这个方法的用户当做真的产生了那个例外处理,好处:在应用中,可将其作为一个“占位符”使用,这样一来,以后如果修改这个方法,让它产生实际的例外,而不需修改调用这个方法的现有代码。定义空例外的例子如下:public void f()throws Exception/Exception是一个已经定义好的例外类这个方法f()是一个空方法,无论如何抛不出任何例外,但编译器允许我们定义它可能会抛出例外类Exception的例外。当其他方法调用f()时必须把它置入try块中。,7.2 Java定义的例外类,我们已经讲过,一个例外类在使用它时必须先定义,可以想象,如果这些例外类都由我们自己定义是很麻烦的事,幸好Java已经定义好了许多常用的类,我们就来介绍一下Java中已经定义的例外类。,7.2.1 Java中的例外类,Throwable及其子类类定义 Throwable是Object类的子类,并且实现了接口 Serializable 构造函数Throwable类有public Throwable()和public Throwable(Stringmessage)两个构造 函数。方法 getMessage()toString()printStackTrace()fillInStackTrace(),下面我们通过一个例子来看Throwable的这些方法如何使用。例7.2 例外方法的使用 ThrowableMethods.java的源程序如下:,public class ThrowableMethods public static void main(String args)try/try块中只有一抛出例外的语句 throw new Throwable(Heres my Throwable);catch(Throwable e)System.out.println(Caught Throwable);System.out.println(e.getMessage():+e.getMessage();System.out.println(e.toString():+e.toString();System.out.println(e.printStackTrace():);e.printStackTrace();,该程序输出结果,该程序输出如下:,Caught Throwablee.getMessage():Heres my Throwable:Heres my Throwablee.printStackTrace():Heres my Throwable at ExceptionMethods.main(ExceptionMethods.java:4)如果我们将“throw new Throwable(Heres my Throwable)”;修改为“/throw new Throwable();”,那么得到的结果就是这样的:Caught Throwablee.getMessage():nulle.toString():java.lang.Throwablee.printStackTrace():java.lang.Throwable at ExceptionMethods.main(ExceptionMethods.java:4),2.例外类之间的继承关系,Throwable对象有两个子类:Error和Exception。Java定义的例外类都是Exception的子类,这些子类被放置于不同的包中,Throwable类大致的继承结构如图所示,Exception这个类是我们用到的例外类的祖先类,它在java.lang包中,所有的能捕获的类都是从它衍生出来的,我们可创建一个控制器,令其捕获所有类型的例外。具体的做法是捕获基础例外类Exception(Exception是适用于几乎所有编程活动的基础)。例如:catch(Exception e)System.out.println(caught an exception);这段代码能捕获任何例外,所以在实际使用时最好将其置于控制器列表的末尾,防止跟随在后面的任何特殊例外控制器失效。,7.2.2 例外类使用中的两个问题,例外是一种比较特殊的类,在其使用过程中有很多特殊问题,需要大家注意,这一节我们就几个常见问题和大家做一个讨论。,1例外匹配 例外匹配是指try块中抛出的对象如何找到对应的例外控 制器,例7.3 子类不能和父类例外匹配 MissCatch.java的源程序如下:public class MissCatch public static void main(String args)throws Throwable try throw new Throwable();catch(Exception e)/这个语句不能捕获Throwable类例外 System.out.println(Caught in main()!);这个程序的try块中抛出的是Throwable类例外,而catch括号内定义的例外名e是Exception类的,所以不能形成匹配,从而使Throwable类的例外未被捕获,这种错误在编译过程中是不能被发现的,直到运行时才会被发现,因此运行结果如下,运行结果,Exception in thread main at MissCatch.main(MissCatch.java:4)如果上例中的Throwable与Exception进行对换,即改为:try throw new Exception();catch(Throwable e)/这个语句不能捕获Throwable类例外 System.out.println(Caught in main()!);结果,或者把Throwable改成Exception,再或者把Exception改成Throwable,输出结果都是:Caught in main()!说明例外控制捕获了例外。,由于抛出一个例外后,例外控制系统会按顺序搜索“最接近”的控制器。一旦找到相符的控制器,就认为例外已得到控制,不再进行更多的搜索工作 例7.4 控制器的排列问题,Human.java的源文件如下:class Annoyance extends Exception class Sneeze extends Annoyance public class Human public static void main(String args)try throw new Sneeze();catch(Exception c)System.out.println(Caught Exception);catch(Sneeze a)System.out.println(Caught Sneeze);catch(Annoyance b)System.out.println(Caught Annoyance);,输出结果,输出结果如下,Human.java:9:exception Sneeze has already been caught catch(Sneeze a)Human.java:11:exception Annoyance has already been caught catch(Annoyance b)2 errors 在这个程序中,我们先定义了Annoyance和Sneeze两个例外类,其中,Annoyance是从Exception继承而来,而Sneeze是从Annoyance继承而来。然后主程序中捕获这些例外,但是由于程序先捕获了Exception类,那么后面两个例外都不可能被捕获,因此,程序在编译时就会出错,2.RuntimeException的特殊情况,if(t=null)throw new NullPointerException();这个例子看起来上面的语句很正常,如果传递的对象名t未指向任何实际地址,就抛出NullPointerException类的例外。但事实上Java中不需要这样做,Java中存在一个特殊的例外类:RuntimeException,这个类里含有一系列子类。这些类的例外是由系统自动抛出、自动捕获,并由系统自行处理。,如果我们的程序中不捕获RuntimeException类例外,系统又会如何处理呢?请试试下面这个例子:,例7.5 RuntimeException类的例外CaughtBySystem.java的源文件如下:public class CaughtBySystem static void f()throw new RuntimeException(From f();static void g()f();public static void main(String args)g();,输出结果,输出结果如下:,Exception in thread main:From f()at CaughtBySystem.f(CaughtBySystem.java:3)at CaughtBySystem.g(CaughtBySystem.java:6)at CaughtBySystem.main(CaughtBySystem.java:9),7.2.3 例外在继承关系中的特殊性,在子类的方法覆盖父类的方法,且父类的方法声明抛出某些例外时,子类方法只能抛出被覆盖的方法所能抛出的例外所属的例外类或它的衍生类。如果父类中方法未定义成抛出例外,那么子类覆盖的方法也不能抛出例外,如果父类方法声明抛出例外,子类方法可以不声明抛出例外。不过,对于构造函数,父类的构造函数声明抛出的例外必须在子类的构造函数中也声明抛出,子类也可以抛出父类中根本不存在的例外,例7.6 覆盖的方法只能抛出父类方法的例外或它的衍生类,StormyInning.java的源文件 这个例子中定义了两个例外族,然后定义一个抽象类作为主类 的父类,主类还实现了一个接口,由主类的构造函数可以看出,它抛出的例外中必须包含父类构造函数的例外。这个程序由两个特别的地方:第一个是方法event(),它即是主类的父类中含有的方法,也是主类 所实现的接口中含有的方法。第二个特别的地方就是第二个黑体字代码行,它用一个父类(还是抽 象类)的对象名指向一个子类的对象,那它的方法atBat()将 按照父类的方法头定义,抛出两种例外:Strike类的和Foul 类的,7.2.4 例外的重新抛出,在某些情况下,我们需要重新抛出刚才产生过的例外,特别是在用Exception捕获所有可能的例外时,由于已拥有当前例外的对象名,所以只需简单地重新抛出那个对象名即可。下面是一个例子:atch(Exception e)System.out.println(An exception has been generated.);throw e;重新抛出一个例外将进入上一级结构的例外控制器中。但在这一层次的例外控制机制中,后面的catch仍然被忽略。这个被再次抛出的例外保留原例外的有关信息,所以用于捕获这个再抛出例外的上一层的控制器可以从那个对象里提取出所有信息。,例7.7 重新抛出例外Rethrowing.java的源程序如下:public class Rethrowing/定义一个方法f(),它能抛出Exception类的例外public static void f()throws Exception System.out.println(originating the exception in f();throw new Exception(thrown from f();/定义一个方法g(),它将调用方法f(),并用控制器捕获f()抛出的例外,/控制器中重新将例外抛出public static void g()throws Throwable try f();catch(Exception e)System.out.println(Inside g(),e.printStackTrace():);e.printStackTrace();/打印堆栈使用情况 throw e;/简单地重新抛出例外/读者应用下一句来替代上一句,再次运行程序,以进行比较/throw e.fillInStackTrace();/抛出新对象并用它来填充原对象的堆栈/定义main()方法,在main()方法中调用g(),它将产生被重新抛出的对象,/再用printStackTrace()方法打印出堆栈使用情况以和第一次抛出时比较public static void main(String args)throws Throwable try g();catch(Exception e)System.out.println(Caught in main,e.printStackTrace():);e.printStackTrace();/再次打印堆栈信息,程序的运行结果,程序的运行结果如下:,originating the exception in f()Inside g(),e.printStackTrace():thrown from f()at Rethrowing.f(Rethrowing.java:5)at Rethrowing.g(Rethrowing.java:12)at Rethrowing.main(Rethrowing.java:26)Caught in main,e.printStackTrace():thrown from f()at Rethrowing.f(Rethrowing.java:5)at Rethrowing.g(Rethrowing.java:12)at Rethrowing.main(Rethrowing.java:26)这样我们可以看出,例外的多次简单抛出时,它含有的堆栈信息是相同的,如果像程序中注释要求的那样,用throw e.fillInStackTrace();来代替throw e;结果就不一样了,throw e.fillInStackTrace();的意思是“抛出例外,把它当新对象,它的信息填充原对象的信息”,所以这个新对象只记住了目前的境况,而忘记了过去,这时的结果如下,originating the exception in f()Inside g(),e.printStackTrace():thrown from f()at Rethrowing.f(Rethrowing.java:5)at Rethrowing.g(Rethrowing.java:12)at Rethrowing.main(Rethrowing.java:26)Caught in main,e.printStackTrace():thrown from f()at Rethrowing.g(Rethrowing.java:18)at Rethrowing.main(Rethrowing.java:26),下面的例子就是程序重新抛出了一个与原来不同类型的例外。例7.8 重新抛出一个不同的例外,RethrowNew.java的源程序如下:public class RethrowNew public static void f()throws Exception System.out.println(originating the exception in f();throw new Exception(thrown from f();public static void g()throws NullPointerException try f();catch(Exception e)System.out.println(Caught in g(),e.printStackTrace():);e.printStackTrace();/重新抛出的是另一例外类NullPointerException throw new NullPointerException(from main);public static void main(String args)try g();catch(NullPointerException e)System.out.println(Caught in main,e.printStackTrace():);e.printStackTrace();,输出如下:,originating the exception in f()Caught in g(),e.printStackTrace():thrown from f()at RethrowNew.f(RethrowNew.java:4)at RethrowNew.g(RethrowNew.java:9)at RethrowNew.main(RethrowNew.java:19)Caught in main,e.printStackTrace():from main at RethrowNew.g(RethrowNew.java:13)at RethrowNew.main(RethrowNew.java:19),7.3 关于finally,我们常常会遇到这样的情况,如果发生了错误,程序抛出了例外,不管是哪个例外我们都想执行一段固定的代码,例如程序错误时将窗口关闭,或者一些其他代码,当然可以把这些代码在每个例外控制器的最后复制一份,这样,不管程序在哪个控制器中捕获了例外,这段代码都能被执行,但如果控制器太多,或者这段代码较长,这样做程序就显得很啰嗦。事实上,Java中存在的finally关键词就可以解决这个问题。本节向大家介绍关于finally的一些内容。,7.3.1 finally的使用方法,finally引导的从句放在例外控制器的末尾,只要不管try块中是否抛出了例外,不管例外是否被捕获,由哪个控制器捕获,再结束当前的例外控制结构之前,系统会去执行finally从句,这样每次都需要执行的代码可以放入finally从句,可以让程序较为简洁。所以完整的例外控制小节应该像下面这个样子:try/可能“抛”出A,B,或C的例外的代码段 catch(A a)/控制器 A catch(B b)/控制器 B catch(C c)/控制器 C finally/每次都需要执行的代码,例7.9 演示finally从句的作用FinallyWorks.java的源文件如下:,public class FinallyWorks static int count=0;/设置一个静态计数器 public static void main(String args)while(true)/无限循环 try System.out.print(count=+count+:);if(count+%2=0)throw new Exception();/如果有例外抛出这句就不会执行到 System.out.println(No exception);catch(Exception e)System.out.println(Exception thrown);finally/每个循环这个从句都会被执行 System.out.println(finally clause executed);if(count=5)break;/用它来跳出无限循环,输出如下:,count=0:Exception thrownfinally clause executedcount=1:No exceptionfinally clause executedcount=2:Exception thrownfinally clause executedcount=3:No exceptionfinally clause executedcount=4:Exception thrownfinally clause executed,例7.10 两个并列的例外控制结构ParataxisStructure.java的源文件如下:,public class ParataxisStructure public static void main(String args)/第一个例外控制结构 try throw new Exception();catch(Exception e)System.out.println(first Exception!);finally System.out.println(finally clause);/第二个例外控制结构 try throw new Exception();catch(Exception e)System.out.println(second Exception!);,输出结果,这个程序的输出结果如下:,first Exception!finally clausesecond Exception!,例外抛出后,如果不在当前的例外控制结构中被捕获,finally仍会在跳到上一层次的例外控制结构之前被执行。如下所示:public class NestedStructure public static void main(String args)System.out.println(Entering first try block);try System.out.println(Entering second try block);try throw new Exception();finally System.out.println(finally in 2nd try block);/*try throw new Exception();catch(Exception a)System.out.println(2nd try block inside);*/catch(Exception e)System.out.println(Caught Exception in first try block);finally System.out.println(finally in 1st try block);,该程序的输出结果,该程序的输出如下:,Entering first try blockEntering second try blockfinally in 2nd try blockCaught Exception in first try blockfinally in 1st try block,例7.11 在例外控制结构中使用break语句NestedStructure2.java的源文件如下:public class NestedStructure2 public static void main(String args)System.out.println(Entering outside block);/外层结构 try System.out.println(Entering inside block1);lebalname:/第一个内层结构 try throw new Exception();catch(Exception e)System.out.println(Caught an Exception in inside block1);break lebalname;finally/这个finally从句仍被执行 System.out.println(finally in inside block1);/第二个内层结构 try System.out.println(Entering inside block2);throw new Exception();finally/加一个空的finally从句以完成一个例外控制结构 catch(Exception c)System.out.println(Caught another Exception in outside block);finally System.out.println(finally in outside block);,该程序的结果反映了程序经过的几个结构:,Entering outside blockEntering inside block1Caught an Exception in inside block1finally in inside block1Entering inside block2Caught another Exception in outside blockfinally in outside block,7.3.2 finally用在哪里,以上的内容使我们对finally从句及例外控制有了更深入的了解,这一小节让我们看看finally真正应该用在哪里。通常若要设置另一些东西时,我们就可以用finally,例如,有时需要打开一个文件或者建立一个网络连接,或者在屏幕上画一些东西,甚至设置外部世界的一个开关,等等,如果这些动作完成之后发生了错误,产生了例外,我们用一般手段不能完成如关闭文件、断开网络连接等事情,就把它交给finally从句去做。,例7.12 没有finally从句的不完善程序WithoutFinally.java的源文件如下:,class Switch boolean state=false;boolean read()return state;void on()state=true;void off()state=false;public class WithoutFinally static Switch sw=new Switch();public static void main(String args)try sw.on();/这个操作可能抛出例外 sw.off();catch(NullPointerException e)System.out.println(NullPointerException);sw.off();catch(IllegalArgumentException e)System.out.println(IOException);sw.off();,例7.13 用finally从句改善的程序WithFinally.java的源文件如下:,class Switch2 boolean state=false;boolean read()return state;void on()state=true;void off()state=false;public class WithFinally static Switch2 sw=new Switch2();public static void main(String args)try sw.on();catch(NullPointerException e)System.out.println(NullPointerException);catch(IllegalArgumentException e)System.out.println(IOException);finally sw.off();,7.3.3 finally的缺陷,一般情况下使用finally不会出现问题,但在一种特殊的程序结构中,会发生例外信息的丢失现象,结果如同使用了fillInStack()一样。,例7.13 例外的丢失LostMessage.java的源文件如下:class ImportantException extends Exception public String toString()return An important exception!;class NormalException extends Exception pub

    注意事项

    本文(《Java程序设计基础》第7章:例外处理.ppt)为本站会员(牧羊曲112)主动上传,三一办公仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知三一办公(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    备案号:宁ICP备20000045号-2

    经营许可证:宁B2-20210002

    宁公网安备 64010402000987号

    三一办公
    收起
    展开