Java第十三课. 异常&集合框架

Java第十三课. 异常&集合框架

回顾

1. Object:toString()/equals()/clone():浅克隆,深克隆:实现克隆接口的对象本身,也会把克隆对象中关联的对象一起克隆
2. Finalize():每个对象都有:是垃圾回收器调用;当垃圾回收器检测到一个对象很久都没有引用的时候,回去调用该对象的Finalize()进行回收;
3. 日期时间对象:Date(掌握获取当前系统时间)  Calendar:api里面获取/设置时间的方法 
4. Date与Calendar互转:getTime()  setTime()->Date转Calendar
5. SimpleDateFormat辅助类:(创建对象时,有参构造放的是格式:yyyy年MM月dd日 HH时mm分ss秒)将日期格式化输出  format()->Date转字符串  parse()->字符串转Date

1.Throwable

在这里插入图片描述
在这里插入图片描述

2. 异常Exception

2.1 Exception与Error的概念、区别
• 异常(Exception):异常指的是程序运行时发生的不正常事件;异常能够被程
序处理,保证程序继续运行下去;例如除数为0、文件没有找到、输入的数字格
式不对……
• 错误(Error):错误程序没法处理,例如内存泄漏。发生错误后,一般虚拟机会
选择终止程序运行,程序员需要修改代码才能解决相关错误;
2.2 常见的异常
1.	java.lang.NullPointerException 空指针异常
2.	ArrayIndexOutOfBoundsException 数组越界异常
3.	java.lang.ArithmeticException: / by zero 算术异常(包含了除数不能为0的异常)
4.	java.lang.ClassCastException 类型转换异常
    
问题引入:
出现了上面的问题带来的结果是什么?
1.	控制台(界面),上会显示异常的信息,给用户带来不来的体验
2.	发生异常的时候,程序立即结束,后续代码也无法执行
基于以上2,我们要做异常的处理,同时还要知道有哪些常见的异常类型,这样才能针对性的处理

在这里插入图片描述

2.3 异常处理
2.31 方式1:try-catch-finally
try{
   //监视作用

}catch (异常){
  //捕获并处理

}finally{
  //不管是否有异常发生,finally语句块中的语句始终保证被执行
  //finally语句块主要用于解决资源泄露问题
}

可能发生异常的代码块,选中,右键 找到surround with ->try catch

2.311 try-catch
try {
			System.out.println(string.length());
			//2.java.lang.ArrayIndexOutOfBoundsException
			//数组下标越界异常
			array[3]=1;
			
			//3. java.lang.ArithmeticException:
			//算术异常(包含了除数不能为0)
			System.out.println(1/0);
			
			
			//4.java.lang.ClassCastException
			//类转换异常
			Object obj=apple;
			Dog dog=(Dog)obj;
			
		}catch (Exception e) {
			System.out.println("异常了");
    
2.312 try-catch-catch…

try里面可以放很多可能发生异常的代码,但是一次只能捕捉一个来处理;
在这里插入图片描述

注意:try的后面可以有多重catch,但是注意层级关系:越高越往下写。

2.313 finally->总会执行
try catchtry 多个catchtry..finallytry catch finally
    try {
        System.out.println(string.length());
        //2.java.lang.ArrayIndexOutOfBoundsException
        //数组下标越界异常
        array[3]=1;

        //3. java.lang.ArithmeticException:
        //算术异常(包含了除数不能为0)
        System.out.println(1/0);


        //4.java.lang.ClassCastException
        //类转换异常
        Object obj=apple;
        Dog dog=(Dog)obj;

    }catch (Exception e) {
        System.out.println("异常了");
    }finally {
        //总会执行->释放资源
        sc.close();
    }

    System.out.println("这是我正常执行的代码");

异常了
这是我正常执行的代码
2.314 finally注意事项

1. finally块前有return语句,finally依然被执行;

public static void main(String[] args) {
		//finally块前有return语句,finally依然被执行;
		try {
			System.out.println(1/0);
		} catch (Exception e) {
			System.out.println("发生算术异常,除数不能为0");
			return;//结束方法
		}finally {
			System.out.println("finally代码块");//于return之前执行
		}

		System.out.println("main方法运行结束");//不执行,11行执行完return表示结束方法运行
	}

发生算术异常,除数不能为0
finally代码块

2. finally块前有System.exit(0)语句,finally不被执行;

public static void main(String[] args) {
    //finally块前有System.exit(0)语句,finally不被执行;
    try {
        System.out.println(1/0);
    } catch (Exception e) {
        System.out.println("发生算术异常,除数不能为0");
        System.exit(0);//结束jvm运行
    }finally {
        System.out.println("finally代码块");//不执行
    }

    System.out.println("main方法运行结束");//不执行
}

发生算术异常,除数不能为0

两个经典题:

1. 没有异常的情况下,测试return语句在try和finally中执行顺序
先执行try中的return,再执行finally中的return,最终以finally中的return 为准。

//先执行try中的return,再执行finally中的return,最终以finally中的return 为准。
	@SuppressWarnings("finally")
	public static int method1() {//结果0
		int i=1;
		try {
			i++;
			return i;//①先执行
		} catch (Exception e) {
			
		}finally {
			return 0;//②也会执行,而且是在try的return执行完再执行,真正返回给调用处的结果
		}
	}
	public static void main(String[] args) {
		System.out.println(method1());//0
	}

2. try里面有return ,finally里面没有return ,那么结果以try里面为准

@SuppressWarnings("finally")
	public static int method2() {//结果2
		int i=1;
		try {
			i++;
			return i;//①这里有个return,会记录i的值=2 ,③返回结果,是之前记录的值
		} catch (Exception e) {
			
		}finally {
			i++;//②执行finally 
		}
		return 0;//在上面的代码没有发生异常的情况下,这里是不执行
	}
	public static void main(String[] args) {
		System.out.println(method2());//2
	}
2.32 方式2:throws(抛出异常)
异常一直向上抛,最顶点就是JVM;
可以称为声明了一个异常;可以理解为抛出异常,抛出给调用者,谁调用他就抛给谁;

在这里插入图片描述

2.33 方式3:throw :手动引发异常(了解)
手动引发异常,发生在方法中(我认为满足特定的条件就是异常发生了)

在这里插入图片描述

2.34 方式4:自定义异常(了解)
1.创建一个自定义异常类:
①继承 Exception(或其子类);
②添加一个带参数构造;  
③重写 getMessage()-可写可不写
public class AgeException extends Exception{

	private static final long serialVersionUID = 5332603740831531025L;
	public AgeException(String message) {
		//调用父类的构造方法
		super(message);
	}

	public AgeException() {
		// TODO Auto-generated constructor stub
	}
	//也可以重写父类的方法
	@Override
	public String getMessage() {
		// TODO Auto-generated method stub
		return super.getMessage();
	}
}
public class Student {
	private String name;
	private int age;
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getAge() {
		return age;
	}
	public void setAge(int age) throws AgeException {
		if (age<=0) {
			//手动
			throw  new AgeException("年龄不合法,至少>0");
		}
		this.age = age;
	}

	
	public static void main(String[] args) throws AgeException {
		Student student = new Student();
		student.setAge(0);
	}
}

在这里插入图片描述

2.4 异常小结:

在这里插入图片描述

异常是程序中的一些错误,但并不是所有的错误都是异常,并且错误有时候是可以避免的。
•  检查性异常:最具代表的检查性异常是用户错误或问题引起的异常,这是程序员无法预见的。例如要打开一个不存在文件时,一个异常就发生了,这些异常在编译时不能被简单地忽略。
public static void main(String[] args)  {
        Class.forName("Apple");
} 
//Exception, SQLException 非运行时异常;
• 运行时异常: 运行时异常是可能被程序员避免的异常。与检查性异常相反,运行时异常可以在编译时被忽略。
//NullPointerException
• 错误: 错误不是异常,而是脱离程序员控制的问题。错误在代码中通常被忽略。例如,当栈溢出时,一个错误就发生了,它们在编译也检查不到的。
//OutOfMemoryError, 内存溢出、StackOverflowError堆栈溢出

在这里插入图片描述
在这里插入图片描述

所有的异常类是从 java.lang.Exception 类继承的子类:

1. 分类:编译时异常、运行时异常
    
2. Exception异常:一般是逻辑或者数据内容的出错
   Error错误:jvm底层的各种异常:内存溢出、堆栈溢出。
    
3.所有的编程语言都需要进行异常处理,针对是“运行期”。
    
4.处理异常作用:预先准备,避免程序因为异常而“终止”。
    
5.所有的异常类的父类的 Java.lang.Exception
    
6.Exception的四个直接子类
  SQLException--数据库异常
  ClassNotFountdException--找不到类
  IOException--流异常
  RuntimeException-运行期异常
    
7.RuntimeException-运行期异常的常见子类
ArithmeticException	       算术异常,如:除数为0
IllegalArgumentException       方法接收到非法参数
ArrayIndexOutOfBoundsException 数组下标越界
NullPointerException	       访问空引用
ClassNotFoundException	       不能加载所需的类
NumberFormatException	       字符串转换数字失败
    
8.异常处理
方式1try{
         //监视作用
     }catch(){
        //捕获作用 做处理
     }finally{
       //无论try中发生什么,finally都会执行,除非特殊情况
     }

注意:1. try的后面可以有多个catch,但是注意层级关系:类层次越低的越上写,越高越往下写。
     2. finally不是永远都会执行。有些特殊情况:finally语句中异常,退出程序...

方式2throws语句用于抛出异常:不在方法中处理异常,向上抛。

方式3throw语句用于手工抛出异常,很少用
2.5 常见面试题
2.51 异常Exception和错误error的区别
都是继承于Throwable ;

Exception异常:可以是可被控制(checked) ,是运行过程中的不正常事件,可以被异常机制处理,程序能够继续运行下去;
    
Error错误:jvm底层的各种问题:内存溢出,堆栈溢出。错误不能够被处理,发生错误后,程序就终止,程序员需要修改源代码才能解决错误;
2.52 try catch fianlly关键字的作用
try: 监视作用
catch: 捕获异常,处理异常
finally: 不管是否出现异常,都会执行 finally 中的代码块, finally 块是可选的,可视具体情况决定是否添加; finally 块必须和 try 块一起使用,不能单独存在。

3. 集合框架

[概念]: 特指java工具包(java.util)提供的对集合的一系列操作类
[作用]:1. 对静态数组的增强(集合长度可变. 支持链表,无序集以及映射集迭代器)
	  2.支持泛型(jdk1.5)
顶层接口:
				  List接口:有序集合
Collection  ->    Set接口:无序集合
Map 接口:映射集合
总体说明:主要的是学习集合框架中常见的接口,接口的实现类,以及对应的方法和应用场景
3.1 List接口有序集合实现类
3.1.1 ArrayList

先从最简单的一个类入手:ArrayList
在这里插入图片描述

构造方法摘要
ArrayList() 构造一个初始容量为 10 的空列表。
ArrayList(Collection<? extends E> c) 构造一个包含指定 collection 的元素的列表,这些元素是按照该 collection 的迭代器返回它们的顺序排列的。
ArrayList(int initialCapacity) 构造一个具有指定初始容量的空列表。

重要的方法:

booleanadd(Ee) 将指定的元素添加到此列表的尾部。
voidadd(int index,Eelement) 将指定的元素插入此列表中的指定位置。
voidclear() 移除此列表中的所有元素。
booleancontains(Objecto) 如果此列表中包含指定的元素,则返回 true。
Eget(int index) 返回此列表中指定位置上的元素。
Eremove(int index) 移除此列表中指定位置上的元素。
intsize() 返回此列表中的元素数。长度
Object[]toArray() 按适当顺序(从第一个到最后一个元素)返回包含此列表中所有元素的数组。

常见的方法:

public class TestArrayList01 {

	public static void main(String[] args) {
		// 创建一个ArrayList对象
		ArrayList list01=new ArrayList();
		//向对象中增加一个元素   参数类型Object
		list01.add(1);
		list01.add("我喜欢学习,不学习就难受");
		list01.add(null);
		list01.add(12.25);
		
		//能否添加重复的元素?   能
		list01.add("我喜欢学习,不学习就难受");
		System.out.println(list01.size());//5 
		
		//将集合中的某个元素删除
		//索引0表示的是集合中的第一个元素 
		list01.remove(0);
		System.out.println(list01.size());//4
		
		//添加一个Emp对象
		list01.add(new Employee());//自定义对象  new
		
		//继续删除
		System.out.println(list01.remove(new Employee()));//false 两次new 不是同一个对象    
		System.out.println(list01.size());//5 
		
		if (list01.contains(12.25)) {
			System.out.println("找到了~");
		}
		
		//遍历集合并输出
		for (int i = 0; i < list01.size(); i++) {
			System.out.println(list01.get(i));
		}

	}

}
我们发现,刚刚的代码有效的补充了我们之前案例中数组的不足:
1.	长度可变;
2.	数组定义,数组类型是固定,Arraylist中类型是Object,随意添加各种类型;
3.	ArrayList中提供了大量已经实现的方法例如添加add,remove等等,让我们更多的时间关注业务,而不是算法;

[一个问题]:
add(任何类型)->当一个对象存放到集合中的时候,这个对象就自动被装箱(Object);
public class EmpManage2 {
	//有几个员工?
	//可以使用数组解决,但是如果数组一旦定义长度固定,以后不好扩展
	//private Employee emps[]=new Employee[20];//默认值是null
	//用集合解决
	private ArrayList emps=new ArrayList();

	
	/**
	 * 增加的操作,通常写成一个方法
	 * @param emp 员工对象
	 */
	public void addEmp(Employee emp) {
		emps.add(emp);
		System.out.println("增加成功");
	}
    
    /**
	 * 员工的显示
	 */
	public void showEmp() {
		System.out.println("*******公司员工列表如下:**********");
		for (Employee employee : emps) {
			if (employee==null) {
				break;
			}
			System.out.println(employee);
		}

	}
3.1.2 泛型
泛型 本质上认为是一种类型检查的机制,存放的元素到集合要进行类型的检查,取出来不需要强制转型了;
public class TestArrayList02 {

	public static void main(String[] args) {
		ArrayList<String> list01=new ArrayList<String>();
		//list01.add(1);无法通过编译
		//list01.add(new Object());
		list01.add("abc");
		
		//遍历
		for (String string : list01) {
			System.out.println(string);
		}
	}

}

刚才的查询员工加上泛型:
在这里插入图片描述
在这里插入图片描述

注意:
泛型里只能放引用类型,不能放基本数据类型;
3.2 LinkedList

在这里插入图片描述
在这里插入图片描述

构造方法摘要
LinkedList() 构造一个空列表。
LinkedList(Collection<? extends E> c) 构造一个包含指定 collection 中的元素的列表,这些元素按其 collection 的迭代器返回的顺序排列。
方法摘要
voidaddFirst(E e) 将指定元素插入此列表的开头。
voidaddLast(E e) 将指定元素添加到此列表的结尾。
EgetFirst() 返回此列表的第一个元素。
EgetLast() 返回此列表的最后一个元素。
EremoveFirst() 移除并返回此列表的第一个元素。
EremoveLast() 移除并返回此列表的最后一个元素。
Epeek() 获取但不移除此列表的头(第一个元素)。
Epoll() 获取并移除此列表的头(第一个元素)
Epop() 从此列表所表示的堆栈处弹出一个元素。
voidpush(E e) 将元素推入此列表所表示的堆栈。
Eset(int index, E element) 将此列表中指定位置的元素替换为指定的元素。
3.21 LinkedList新增的方法
public class TestLinkedList {
	public static void main(String[] args) {
		//构建LinkedList
		LinkedList<String> list=new  LinkedList<String>();
		list.add("abc");
		list.add("abc");
		System.out.println(list.size());//2
		
		//删除
		list.remove(0);
		System.out.println(list.size());//2
		
		//差别来了
		list.addFirst("first");
		list.addLast("last");
		
		//输出list
		System.out.println(list);//LinkedList类重写了toString()
		System.out.println(list.toString());
		
		//删除
		list.removeFirst();
		list.removeLast();
		
		System.out.println(list);
		
		//其他方法和ArrayList几乎类似...
	}

}
3.22 栈操作
public class TestLinkedList2 {
	public static void main(String[] args) {
		//构建LinkedList
		LinkedList<String> list=new  LinkedList<String>();
		System.out.println("------模拟堆栈结构  先进后出--------");
		
		//push(E e)将元素推入此列表所表示的堆栈。换句话说,将该元素插入此列表的开头。 
		list.push("A");
		list.push("B");
		list.push("C");
		//输出
		System.out.println(list);//[C, B, A]
		
		//获取堆栈的第一个
		System.out.println(list.get(0));//C
		//peek()    获取但不移除此列表的头(第一个元素)。
		System.out.println(list.peek());
		
		//poll()    获取并移除此列表的头(第一个元素)
		System.out.println(list.poll());//C
		System.out.println(list);//[B, A]
		
		//pop()   从此列表所表示的堆栈处弹出一个元素。和poll() 类似
		System.out.println(list.pop());
		System.out.println(list);//[A]
	}

}

在这里插入图片描述

3.23 队列
public class TestLinkedList {

	public static void main(String[] args) {
	  //构建一个LinkedList对象
		LinkedList<Object> list=new LinkedList<Object>();

		System.out.println("-----模拟队列   先进先出-------");
		
		list.add("A");
		list.add("B");
		list.add("C");
		
		System.out.println(list.toString());
		//获取  叫号
		//System.out.println("叫号:"+list.get(0));//获取
		System.out.println("叫号:"+list.pop());//获取第一个并且从列表删除该元素
		System.out.println("叫号:"+list.pop());//获取第一个并且从列表删除该元素
		System.out.println(list);
	}

}
3.24 [面试题]LinkedList与ArrayList相比
1. 相似点:都是List接口的实现类;可以在指定位置上插入元素,通过索引访问元素,都允许空元素null,元素可以重复,元素有序(索引),都是非线程同步,线程不安全;
2. 不同点: ①内存数据结构不一致:ArrayList是可变动态数组数据结构, LinkedList基于链表数据结构;
          ②对于查询和修改,ArrayList效率更高;
          ③对于插入和删除, LinkedList效率更高;
          ④ArrayList, LinkedList提供的API方法基本相同,只是LinkedList增加了很多方法: addFirst(),addLast(),removeFirst(),removeLast()

4. 练习

使用ArrayList实现:查询所有员工,增加,查找单个员工,删除,修改和之前的菜单功能

0 退出  1增加员工  2 显示所有员工  3 根据员工编号查询员工  4 删除员工 5 修改员工
public class Employee {
	//员工编号
	private int empNo;
	//姓名
	private String empName;
	//部门
	private String deptName;
	//工资
	private double salary;
	public int getEmpNo() {
		return empNo;
	}
	public void setEmpNo(int empNo) {
		this.empNo = empNo;
	}
	public String getEmpName() {
		return empName;
	}
	public void setEmpName(String empName) {
		this.empName = empName;
	}
	public String getDeptName() {
		return deptName;
	}
	public void setDeptName(String deptName) {
		this.deptName = deptName;
	}
	public double getSalary() {
		return salary;
	}
	public void setSalary(double salary) {
		this.salary = salary;
	}
	public Employee(int empNo, String empName, String deptName, double salary) {
		super();
		this.empNo = empNo;
		this.empName = empName;
		this.deptName = deptName;
		this.salary = salary;
	}
	
	public Employee() {
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {
		return "Employee [empNo=" + empNo + ", empName=" + empName + ", deptName=" + deptName + ", salary=" + salary
				+ "]";
	}

}
public class EmpManage {
	//有几个员工?
	//可以使用数组解决,但是如果数组一旦定义长度固定,以后不好扩展
	//private Employee emps[]=new Employee[20];//默认值是null
	//用集合解决
	private ArrayList<Employee>  emps=new ArrayList<Employee>();
	Scanner scanner=new Scanner(System.in);

	/**
	 * 显示主菜单
	 */
	public void showMenu() {
		while(true) {
			System.out.println("请输入您的选择 0 退出  1增加员工  2 显示所有员工  3 根据员工编号查询员工  4 删除员工 5 修改员工");
			int choice=scanner.nextInt();
			switch (choice) {
			case 0:
				System.out.println("系统退出,再见~");
				System.exit(0);
				break;

			case 1:
				inputEmp();
				break;
			case 2:
				showEmp();
				break;
			case 3:
				//查找的输入方法
				findMenu();
				break;
			case 4:
				//删除的输入方法
				deleMenu();
				break;
			case 5:
				//修改员工的菜单方法
				updateMenu();
				break;
			default:
				break;
			}
		}
	}
	/**
	 * 修改员工的菜单方法
	 */
	private void updateMenu() {
		System.out.println("**********请输入要修改的 员工信息***********");
		int empNo=scanner.nextInt();
		String empName=scanner.next();
		String deptName=scanner.next();
		double salary=scanner.nextDouble();
		Employee emp=new Employee(empNo, empName, deptName, salary);
		//调用修改的方法
		int flag=updateEmp2(emp);
		if (flag==1) {
			System.out.println("修改成功!");
		}else {
			System.out.println("修改失败!");
		}
	}
	/**
	 * 修改员工的方法1
	 * @param emp 传进来新的值
	 */
	private int updateEmp(Employee emp) {
		int flag=0;//修改失败
		//遍历集合
		for (int i = 0; i < emps.size(); i++) {
			//从集合中获取的每一个对象
			Employee emp1=emps.get(i);
			if (emp1.getEmpNo()==emp.getEmpNo()) {
				//修改
				emp1.setEmpName(emp.getEmpName());
				emp1.setDeptName(emp.getDeptName());
				emp1.setSalary(emp.getSalary());
				flag=1;
				break;
			}
		}
		return flag;
	}
	/**
	 * 修改员工的方法2
	 * @param emp 传进来新的值
	 */
	private int updateEmp2(Employee emp) {
		int flag=0;//修改失败
		//遍历集合
		for (int i = 0; i < emps.size(); i++) {
			//从集合中获取的每一个对象
			Employee emp1=emps.get(i);
			if (emp1.getEmpNo()==emp.getEmpNo()) {
				//修改
				emps.set(i, emp);
				flag=1;
				break;
			}
		}
		return flag;
	}
	/**
	 * 删除的输入方法
	 */
	private void deleMenu() {
		System.out.println("**********请输入要删除的 员工编号***********");
		int empNo=scanner.nextInt();
		int flag=deleEmp(empNo);
		if (flag==1) {
			System.out.println("删除成功!");
		}else {
			System.out.println("删除失败!");
		}
		
	}
	/**
	 * 根据员工编号删除员工
	 * @param empNo
	 */
	private int deleEmp(int empNo) {
		int flag=0;//删除失败
		for (int i = 0; i < emps.size(); i++) {
			if (emps.get(i).getEmpNo()==empNo) {
				emps.remove(i);
				//emps.remove(emps.get(i));
				flag=1;
				break;
			}
		}
		return flag;
	}
	/**
	 * 根据员工编号查询员工的菜单方法
	 */
	private void findMenu() {
		System.out.println("**********请输入要查找的 员工编号***********");
		int empNo=scanner.nextInt();
		int flag=findEmp(empNo);
		if (flag==0) {
			System.out.println("查无此人!");
		}
	}

	/**
	 * 根据员工编号查询员工
	 */
	private int findEmp(int empNo) {
		int flag=0;
		for (Employee employee : emps) {
			if (employee.getEmpNo()==empNo) {
				System.out.println(employee);
				flag=1;
				break;
			}
		}
		return flag;
	}

	

	/**
	 * 输入的方法
	 */
	public void inputEmp() {
		
		System.out.println("**********请输入 员工编号,姓名,部门,基本工资*********");
		int empNo=scanner.nextInt();
		String empName=scanner.next();
		String deptName=scanner.next();
		double salary=scanner.nextDouble();
		Employee emp=new Employee(empNo, empName, deptName, salary);
		//调用增加的方法
		addEmp(emp);
	}
	/**
	 * 增加的操作,通常写成一个方法
	 * @param emp 员工对象
	 */
	public void addEmp(Employee emp) {
		emps.add(emp);
		System.out.println("增加成功");
	}
	
	
	/**
	 * 员工的显示
	 */
	public void showEmp() {
		System.out.println("*******公司员工列表如下:**********");
		for (Employee employee : emps) {
			System.out.println(employee);
		}

	}
}

测试类:

public class TestEmp {

	public static void main(String[] args) {
		EmpManage empManage=new EmpManage();
		empManage.showMenu();
	}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值