Java 异常处理

Java 的异常处理

在程序设计和运行的过程中,发生错误是不可避免的。为此,Java 提供了异常处理机制来帮助程序员检查可能出现的错误,保证程序的可读性和可维护性。Java 中将异常封装到一个类中,出现错误就会抛出异常。

Java 语言是一门面向对象的编程语言,因此,异常在 Java 语言中也是作为类的实例的形式出现的。当某一方法中发生错误时,这个方法会创建一个对象,并且把它传递给正在运行的系统。这个对象就是异常对象。

通过异常处理机制,可以将非正常情况下的处理代码与程序的主逻辑分离,即在编写代码主流程的同时在其它地方处理异常。

生活和程序中的异常

生活中常见的异常

有些人平时会开车上班,从家到公司这段路程需要30分钟,于是就提前40分钟出门了。可是上班的途中遇到了堵车,原本30分钟的路程我们用了两个小时。最后,结局很美好,我们迟到了。我们原本的计划是30分钟到达公司,结果在路上突发了一些情况导致我们没有能够完成我们的任务,这就是生活中的一个异常场景。

程序中常见的异常

在程序中,错误可能产生于程序员各种没有预料到的情况,或者是超出了程序员的可控范围的环境因素。例如用户的坏数据、用户试图打开一个根本不存在的文件等等。异常是一个在程序执行期间发生的事件,它中断了正在执行的程序的正常指令流。而在 Java 中这种在程序运行时可能出现的一些错误,我们都管它叫做异常。

异常的分类

在 Java 类库中每个包中都定义了异常类,而这些所有的类都是 Throwable 类的子类

Throwable 类是所有异常类的超类

Throwable 类派生出了两个子类,分别是 Exception 和 Error,其中 Error 类及其子类它是用来描述 Java运行系统中的内部错误以及资源耗尽的错误,这一类错误的比较严重的,而且我们是无法解决的。而 Exception 类被称为非致命性错误,是可以通过捕捉处理使程序继续执行的一种错误。

Exception 类又可以根据错误发生的原因分为运行时异常和非运行时异常,所谓的运行时异常它的名字叫做 RuntimeException。

Exception 异常

Exception 异常是可以通过处理去解决的异常:

比如汽车没有油了,我们可以到加油站去加油;轮胎爆胎了,我们可以把备胎换上;像这样一些问题我们是可以自己解决的

所谓的 Exception 异常就是会影响程序正常运行,但可以被解决的问题

RuntimeException

1、RuntimeException是那些可能在 Java 虚拟机正常运行期间抛出的异常的超类,即程序运行过程中产生的异常

可能在执行方法期间抛出但未被捕获的 RuntimeException 的任何子类都无需在 throws 的字句中进行声明

2、比如空指针异常、数组下标越界、强制转换类异常、算术异常等等,这些异常一般是由程序逻辑错误引起的

//空指针异常
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        Object obj = null;
        System.out.println(obj.hashCode());
    }
}
/*
Exception in thread "main" java.lang.NullPointerException
	at com.zyt.lesson01.Demo.main(Demo.java:6)
*/
//数组下标越界异常
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        int arr[] = new int[6];
        System.out.println(arr[10]);
    }
}
/*
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 10
	at com.zyt.lesson01.Demo.main(Demo.java:6)
*/
//算术异常
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        int a = 1/0;		//除数不能为0
    }
}
/*
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at com.zyt.lesson01.Demo.main(Demo.java:5)
*/

Error 错误

Error 是指系统发生了重大的错误,是不应该试图捕获的严重问题:

例如:字节码文件无法解析、Java 虚拟机的资源耗尽、配置文件格式不规范

我们在代码中是无法通过修改代码去解决 Error 级别的错误的,可以通过重新编写程序、重新分配系统资源去解决

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        int a = 1/1
        System.out.println(a);
    }
}
//Error:(5, 20) java: 需要';'

如何捕捉处理异常

在 Java 中,如果某个方法抛出异常,既可以在当前方法中进行捕捉,然后处理该异常,也可以使用 throws 关键字将异常向上抛出,由方法调用者来处理。

main 方法向上抛出的异常是由 java 虚拟机去处理的,我们干涉不了,所以在 main 方法中我们尽量用 try catch 去捕获异常,而不要用 throws 去向上抛出异常。

1、自动捕捉异常

Java 虚拟机运行期间,如果程序发生了异常,Java 虚拟机会自动地捕捉异常

但 Java 虚拟机只能捕获这个异常,却无法去处理这个异常

2、try catch 语句捕捉并处理异常

我们可以通过 try catch 语句对发生的异常进行处理

语法格式:
try{
  被捕获的代码
}catch(){
  对异常的处理
}
Execption 是 try 代码块传递给 catch 代码块的变量类型,e 是变量名。catch 代码块中的语句"e.getMessage();"用于输出错误性质。通常,异常处理常用以下3个函数来获取异常的有关信息:
1、getMessage()函数:输出错误性质——用于 Error
2、toString()函数:给出异常的类型与性质
3、printStackTrace()函数:指出异常的类型、性质、栈层次以及出现在程序中的位置
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        try {
            int a = 1/0;
        } catch (ArithmeticException e) {
            System.out.println("发生了算术异常,请管理员及时处理!");
        }
    }
}
3、多重 try catch 代码块

由上至下逐级捕获异常,当正好是 Exceotion2 的异常我们就执行 catch(some Exceotion2 e) 后大括号内的处理代码,处理完之后,我们就直接结束 try catch 语句,不再向下执行

try{
  语句1;
  语句2;
}catch(some Exceotion1 e){
  ......
}catch(some Exceotion2 e){
  ......   
}catch(some Exceotion3 e){
  ......  
}
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        try {
            Object obj = null;
            obj.hashCode();
        }catch(NullPointerException e){
            System.out.println("发生了空指针异常!");
        }catch (ArithmeticException e) {
            System.out.println("发生了算术异常,请管理员及时处理!");
        }catch(ClassCastException e){
            System.out.println("发生了类转换异常!");
        }
    }
}
//输出结果: 发生了空指针异常!
4、异常的中断机制

当出现异常之后,异常之后的代码就会被屏蔽掉,不会再执行了,这就是异常的中断机制

异常产生后,如果不做任何处理,程序就会被终止。例如,将一个字符串转换为整型,可以通过 Integer 类的 parseInt( ) 方法来实现。但如果该字符串不是数字形式,parseInt( ) 方法就会抛出异常,程序将会在出现异常的位置终止,不再执行之后的语句。

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        try{
            System.out.println("第1行");
            System.out.println("第2行");
            System.out.println("第3行");
        }catch(Exception e){
            e.printStackTrace();
        }
    }
}

/*
输出结果:
第1行
第2行
第3行
Very Good
*/

当 try 语句块中的语句发生异常时,程序就会调转到 catch 代码块中执行,执行完 catch 代码块中的程序代码后,将继续执行 catch 代码块后的其它代码,而不会执行 try 语句块中发生异常语句后面的代码。

由此可知,Java 的异常处理是结构化的,不会因为一个异常影响到整个程序的执行。

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        try{
            System.out.println("第1行");
            int num = 1/0;
            System.out.println("第2行");
            System.out.println("第3行");
        }catch(Exception e){
            e.printStackTrace();
        }
        System.out.println("Very Good");
    }
}
/*
输出结果:
第1行
Very Good
java.lang.ArithmeticException: / by zero
	at com.zyt.lesson01.Demo.main(Demo.java:7)
*/

思考:如果在循环中出现了异常,会不会把循环中断?

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        try {
            for(int i=0;i<5;i++){
                System.out.println("输出"+i+"行");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/*
输出结果:
输出0行
输出1行
输出2行
输出3行
输出4行
*/
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        try {
            for(int i=0;i<5;i++){
                System.out.println("输出"+i+"行");
                int a = 1/i;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
/*
输出结果:
输出0行
java.lang.ArithmeticException: / by zero
	at com.zyt.lesson01.Demo.main(Demo.java:8)
*/

结论:在循环中出现了异常,会把循环中断

有什么方法能让循环中即使发生了异常,循环仍不终止?

如下:

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        for (int i = 0; i < 5; i++) {
            try {
                System.out.println("输出" + i + "行");
                int a = 1 / i;
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}
/*
输出结果:
输出0行
java.lang.ArithmeticException: / by zero
输出1行
输出2行
输出3行
输出4行
	at com.zyt.lesson01.Demo.main(Demo.java:8)
*/

恢复机制—finally

finally 语句块就是为了防止像现实生活中的电脑突然断电关机,快结束的工作因为未保存而功亏一篑的情况而设计的

finally 代码块

Java 语言的异常捕获结构由 try、catch、finally 三部分组成。其中,try 语句块存放的是可能发生异常的 Java 语句;catch 程序块在 try 语句块之后,用来激发被捕获的异常,对异常进行处理;finally 语句块是异常处理结构的最后执行部分,无论 try 语句块中的代码如何退出,都将执行 finally 语句块中的语句。

finally 具有一个收尾的功能

异常处理器的语法格式:
try{
   被捕获的代码 
}catch(异常类型 e){
   对异常e的处理
}finally{
   最后一定会执行的代码 
}

通过异常处理器的语法可知,异常处理器大致分为 try catch 语句块和 finally 语句块

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        try {
            System.out.println("打开连接池");
            System.out.println("通过连接池读取数据");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("关闭连接池");
        }
    }
}
/*
输出结果:
打开连接池
通过连接池读取数据
关闭连接池
*/


package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        try {
            System.out.println("打开连接池");
            int a = 1/0;
            System.out.println("通过连接池读取数据");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("关闭连接池");
        }
    }
}
/*
输出结果:
打开连接池
java.lang.ArithmeticException: / by zero
	at com.zyt.lesson01.Demo.main(Demo.java:7)
关闭连接池
*/

finally 的四种特殊情况

finally 代码块一般情况下都会得到执行,它相当于一个万能的保险,但有四种特殊情况 finally 将不会执行

1、在 finally 代码块中发生了异常

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        try {
            System.out.println("打开连接池");
            int a = 1/0;
            System.out.println("通过连接池读取数据");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            int b = 1/0;
            System.out.println("关闭连接池");
        }
    }
}
/*
输出结果:
打开连接池
java.lang.ArithmeticException: / by zero
	at com.zyt.lesson01.Demo.main(Demo.java:7)
Exception in thread "main" java.lang.ArithmeticException: / by zero
	at com.zyt.lesson01.Demo.main(Demo.java:12)
*/

2、在前面的代码块中用了 System.exit( ) ,System.exit( ) 的作用是强制中断当前的程序

红点没有了相当于程序停止了

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        try {
            System.out.println("打开连接池");
            System.exit(0);		//强制停止当前的程序
            System.out.println("通过连接池读取数据");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("关闭连接池");
        }
    }
}
/*
输出结果:
打开连接池
*/

3、程序所在的线程死亡了

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        try {
            System.out.println("打开连接池");
            sc.nextLine();		//一直不输入值,手动让线程死亡
            System.out.println("通过连接池读取数据");
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            System.out.println("关闭连接池");
        }
    }
}
/*
输出结果:
打开连接池
此时红灯一直亮着,代表程序一直没有结束
*/

4、关闭 CPU

程序运行时突然停电,电脑关机

Java 中的常见异常

种类说明
ClassCastException类型转换异常
ClassNotFoundException未找到相应类异常(经常出现在反射中)
AirthmeticException算术异常
ArrayIndexOutOfBoundsException数组下标越界异常
SQLException操作数据库异常
IOException输入输出异常
FileNotFoundException文件未找到异常
IllegalAccessException不允许访问某类异常
NullPointerException空指针异常
拓展:
1、变量一般定义之后是一定要赋值的,但静态变量可以不赋值,如果不赋值默认为 null
2、静态变量不能在静态方法中定义
//算术异常
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        int a = 10/0;
    }
}

————————————————————————————————————————————————————————————————————————————————————————————————————————————

//未找到相应类异常
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c = Class.forName("java.lang.String");
        System.out.println(c);
    }
}
//输出:Class.java.lang.String
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException {
        Class c = Class.forName("java.lang.zyt");
        System.out.println(c);
    }
}
//抛出 ClassNotFoundException 异常

————————————————————————————————————————————————————————————————————————————————————————————————————————————

//下标越界异常
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException {
        int a[] = new int[5];
        a[10] = -1;
    }
}

————————————————————————————————————————————————————————————————————————————————————————————————————————————

//空指针异常
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) throws ClassNotFoundException {
        Object obj = null;
        obj.getClass();
    }
}


package com.zyt.lesson01;

public class Demo {
    //变量一般定义之后是一定要赋值的,但静态变量可以不赋值,如果不赋值默认为 null
    static Object obj;		
    public static void main(String[] args) throws ClassNotFoundException {
        //静态变量不能在静态方法中定义
        obj.getClass();
    }
}

自定义异常

使用 Java 内置的异常类可以描述在编程时出现的大部分异常情况,除此之外,用户只需继承 Exception 类即可自定义异常类

创建自定义异常的定义:自己创建一个 API 中不存在的异常

//语法格式:
class 自定义异常类 extends 已有的异常类{

}

在程序中使用自定义异常类,大体可以分为以下几个步骤:

1、创建自定义异常类

2、在方法中通过 throw 关键字抛出异常对象

3、如果在当前抛出异常的方法中处理异常,可以使用 try catch 语句块捕获并处理,否则在方法的声明处通过 throws 关键字指明要抛出给方法调用者的异常,继续进行下一步操作

4、在出现异常方法的调用者中捕获并处理异常

有四名运动员参加长跑比赛,一号选手为飞人博尔特、二号选手为中国飞人刘翔、三号选手为美国超级英雄闪电侠、四号选手为一个大猩猩,此时我们自定义一个异常为 NonHumansException,当选手不是一个人的时候就会抛出这个异常。

//自定义异常 NonHumansException
package com.zyt.lesson01;

public class NonHumansException extends Exception{
    public NonHumansException(String message){
        super(message);
    }
}



//测试异常
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        String playerType = "monkey";
        try {
            if(!playerType.equals("human")){
                throw new NonHumansException("有非人类的选手:"+playerType);
            }
            System.out.println("开始比赛");
        } catch (NonHumansException e) {
            e.printStackTrace();
        }
    }
}
/*
输出:
com.zyt.lesson01.NonHumansException: 有非人类的选手:monkey
	at com.zyt.lesson01.Demo.main(Demo.java:8)
*/

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args) {
        String playerType = "human";
        try {
            if(!playerType.equals("human")){
                throw new NonHumansException("有非人类的选手:"+playerType);
            }
            System.out.println("开始比赛");
        } catch (NonHumansException e) {
            e.printStackTrace();
        }
    }
}
//输出:开始比赛
//优化
public class Demo {
    public static void main(String[] args) {
        String playerType = "monkey";
        try {
            if(!playerType.equals("human")){
                throw new NonHumansException("有非人类的选手:"+playerType);
            }
            System.out.println("开始比赛");
        } catch (NonHumansException e) {
            e.printStackTrace();
        }
    }
}


package com.zyt.lesson01;

import javax.swing.*;

public class NonHumansException extends Exception{
    String message;
    public NonHumansException(String message){
        super(message);
        this.message = message;
    }

    @Override
    public void printStackTrace() {
        super.printStackTrace();
        JOptionPane.showMessageDialog(null,message,"发生异常",JOptionPane.ERROR_MESSAGE);
    }
}
//此时会弹出一个对话框,上面写着,有非人类的选手:monkey

在方法中抛出异常

有时候我们碰到的问题是我们自己解决不了的,比如我们开车的时候没有油了,这个问题我们自己是解决不了的,我们唯一能做的就是把车开去加油站加油。

同样,Java 中我们遇到的一些问题,我们自己是处理不了的,我们需要把这个问题交给我们的上一级来处理。

若某个方法可能会发生异常,但不想在当前方法中处理这个异常,则可以使用 throw、throws 关键字在方法中抛出异常。

Java 中抛出异常的方法有两种,分别是 throw 和 throws,二者的区别在于:
1、
throw 关键字抛出异常对象
throws 关键字指明要抛出给方法调用者的异常
2、
throw 关键字通常用于方法体中,并且抛出一个异常对象
throws 关键字通常被应用在声明方法时,用来指定方法可能抛出的异常,多个异常可使用逗号分隔开
使用 throws 关键字抛出异常

throws 关键字通常被应用在声明方法时,用来指定方法可能抛出的异常。多个异常可使用逗号分隔开

使用 throws 关键字将异常抛给上一级后,如果不想处理该异常,可以继续向上抛出,但最终要有能够处理该异常的代码

注意:如果是 Error、RuntimeException 或它们的子类,可以不使用 throws 关键字来声明要抛出的异常,编译依旧能顺利通过,但在运行时会被系统自动抛出

语法格式:
public void method() throws 异常类型1,异常类型2,....,异常类型n{
    
}
知识点:
1、抛出异常要慎重,从现在开始养成良好的习惯,能自己处理的异常千万别抛出,自己处理不了的问题一定要抛出去
2、main 方法抛出的异常是由 java 虚拟机去处理的,我们干涉不了,所以在 main 方法中我们尽量用 try catch 去捕获异常,而不要用 throws 去抛出异常
3、如果是 Error、RuntimeException 或它们的子类,可以不使用 throws 关键字来声明要抛出的异常,编译依旧能顺利通过,但在运行时会被系统抛出
4、休眠一秒,一秒之后再继续运行程序
Thread.sleep(1000);     

throws 将代码中可能产生的异常交给别人来处理,用于方法之后

如果我们将可能发生的异常加在 throws 的后面,那我们就可以不用再去 try catch 捕获这些异常了

但是如果此方法在外部的代码被调用的时候,则必须对此方法进行异常捕获

try{
    method();
}catch(异常类型 e){
    e.printStackTrace();
}
package com.zyt.lesson01;

public class Demo {
    public static void show() throws InterruptedException,NullPointerException,Exception{
        for(int i=0;i<10;i++){
            System.out.println(i);
            Thread.sleep(1000);     //休眠一秒,一秒之后再继续运行程序
        }
    }
    public static void main(String[] args) {
        try {
            show();
        } catch (NullPointerException e){
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

java 虚拟机会自动处理 main 方法所抛出的异常

//在 main 方法中将异常抛出
package com.zyt.lesson01;

public class Demo {
    public static void show() throws InterruptedException,NullPointerException,Exception{
        for(int i=0;i<10;i++){
            System.out.println(i);
            Thread.sleep(1000);     //休眠一秒,一秒之后再继续运行程序
        }
    }
    public static void main(String[] args) throws InterruptedException,NullPointerException,Exception{
        show();
    }
}
使用 throw 关键字抛出异常

throw 关键字通常用于方法体中,并且抛出一个异常对象。程序在执行到 throw 语句时立即终止,它后面的语句都不执行。通过 throw 抛出异常后,如果想在上一级代码中来捕获并处理异常,则需要在抛出异常的方法中使用 throws 关键字在方法的声明中指明要抛出的异常;如果要捕捉 throw 抛出的异常,则必须使用 try catch 语句块。

我们来考虑这样一个场景,此时有一个群体的聚会,我们要统计这次聚会的人数,结果由于统计者的疏忽,将总人数写为了-1000
在计算机中用一个整型变量来保存人数时,-1000是合法的,它并不是一个错误
但在实际生活中,人数是不可能等于负数的
也就是说,此时计算机并不能发现这是一个错误
那么我们改如何解决这个问题呢?我们可以将人数为负的这种情况当成一个异常

throw 用于手动制造一个异常对象

语法格式:
throw new 异常类型();
package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args){
       int count = -100;
        try {
            if(count < 0){
                throw new ArithmeticException("人员数量是负数:"+count);
            }
            System.out.println("当前统计人数为:"+count);
        } catch (ArithmeticException e) {
            e.printStackTrace();
            System.out.println("捕捉到了异常");
        }
    }
}

throw 关键字可以更改异常

throw 能在异常发生之前拦截异常,然后将问题交给另外一个异常,如下,将算术异常变为了空指针异常

package com.zyt.lesson01;

public class Demo {
    public static void main(String[] args){
        try {
            int a = 1,b = 0;
            if (b==0){
                throw new NullPointerException("b等于0,发生异常");
            }
            int c = a/b;
        } catch (NullPointerException e) {
            e.printStackTrace();
        }
    }
}

//此时抛出的是空指针异常而不是算术异常

运行时异常

RuntimeException 是 Exception 的一个子类,经常与其它异常区分开

运行时异常就像它的名字描述的一样,它只有在程序运行的时候,才会发现这种异常

常见的运行时异常

种类说明
NullPointerException空指针异常
ArrayIndexOfBoundException数组下标越界异常
ArithmeticException算术异常
ArrayStoreException数组中包含不兼容的值抛出的异常
IllegalArgumentException非法参数异常
SecurityException安全性异常
NegativeArraySizeException数组长度为负异常

异常的使用原则

1、编写异常的时候不要乱抛异常,如果自己能处理的异常,应该主动的处理掉。

2、当你不能解决一个异常时,才把这个异常交给其他人处理

3、如果你将所有的异常全都抛出,你编写的代码将会非常难维护,不仅会埋下巨大的安全隐患,同时也会被 Boss 指责

4、不要忽略捕捉到的异常,既然已经捕捉到这个异常了,就应该及时的、积极的处理掉,而不是当作没看见

5、不要过度的使用异常,虽然通过异常可以增强程序的健壮性,但是如果使用过多不必要的异常处理,可能会影响到程序的执行效率

6、不要使用过于庞大的 try catch 代码块,即在一个 try catch 代码块中放一段几千行的代码去捕捉其中的异常

7、子类抛出的异常不能比父类更高级,如果父类方法中抛出了多个异常,子类覆盖父类方法的同时,也要抛出相同的异常或者是其异常的子类

特例:RuntimeException 异常及其子类不受此原则约束

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值