Java异常类和常用类、泛型、容器

一.异常类

1. 异常处理的基本概念

Java系统中根据错误严重程度的不同,而将程序运行时出的错分为两类:错误和异常。

错误:是指程序在执行过程中所遇到的硬件或操作系统的错误。如内存溢出、虚拟机错等。错误对于程序而言是致命的,错误将导致程序无法运行,而且程序本身不能处理错误,只能依靠外界干预,否则会一直处于非正常状态。如没有找到.class文件,或.class文件中没有main()方法等,则程序不能运行。

异常,是指在硬件和操作系统正常时,程序遇到的运行错。有些异常是由于算法考虑不周而引起的,也有些是由编程过程中疏忽大意而引发的。如运算时除数为0、操作数超出数据范围、数组下标越界、文件找不到或网络连接中断等。异常对于程序而言是非致命性的,虽然异常会导致程序非正常终止,但Java语言的异常处理机制使程序自身能够捕获和处理异常,由异常处理代码调整程序运行方向,使程序仍可继续运行。由于异常是可以检测和处理的,所以就产生了相应的异常处理机制。

2. Java语言的异常处理机制

异常

Java语言提供的异常处理机制是通过面向对象的方法来处理异常的。所以在Java语言中所有异常都是以类的形式存在的。

抛出异常

生成异常对象并把它提交给运行系统的过程称为抛出异常。该异常对象中包含了异常事件类型以及发生异常时应用程序目前的状态。

捕获异常

异常抛出后,运行系统从生成异常对象的代码开始,沿方法的调用栈逐层回溯查找,直到找到包含相应异常处理的方法,并把异常对象提交给该方法为止,这个过程称为捕获异常。

3. 异常处理类

在这里插入图片描述

4. 异常的处理

在Java语言中,异常处理是通过try、catch、finally、throw、throws 五个关键字来实现的。
下面给出实际使用的具体例子。

异常的产生

//输出一个数组的所有元素,捕获数组下标越界异常和除数为0异常。
public class Product {
    public static void main(String[] args) {
        int i;
        int[] a = {1,2,3,4};
        for(i = 0;i < 5;i++) {
            System.out.println("a[" + i + "]=" + a[i]);//第9行
        }
        System.out.println("5/0"+(5/0));
    }
}

运行结果如下:

a[0]=1
a[1]=2
a[2]=3
a[3]=4
Exception in thread “main” java.lang.ArrayIndexOutOfBoundsException: 4
at Product.main(Product.java:6)

程序运行时,正常执行了前4循环,但在执行第5次循环并试图输出a[4]时,Java抛出了一个异常对象,系统报告了异对象的类型(java.lang.ArrayIndexOutOfBoundsException:数组下标越界异常类)及异发生所在的方法(Product.java:6),所以程序卡在第9行同时终止程序的运行。因除数为0将会产生一个术异常(ArithmeticException),系统并未报告是因为该程序终止在第9行,所以该行语句并没有执行到。

使用try-catch-finally语句捕获和处理异常

一般来说,系统捕获抛出的异常对象并输出相应的信息,同时终止程序的运行,导致其后的程序无法运行。这其实并不是用户所期望的,因此就需要能让程序来接收和处理异常对象,从而不至影响其他语句的执行,这就是捕获异常的意义所在。当一个异常被抛出时,应该有专门的语句来接收这个被抛出的异常对象,这个过程就是捕获异常。当一个异常类的对象被捕获或接收后,用户程序就会发生流程跳转,系统终止当前的流程而跳转到专门的异常处理语句块,或直接跳出当前程序和Java虚拟机回到操作系统。

在Java语言的异常处理机制中,提供了try-catch-finally语句来捕获和处理一个或多个异常,其语法格式如下:
在这里插入图片描述
说明

  1. finally块是可以省略的,若省略finally块,则在catch块结束后,程序跳转到 try-catch块之后的语句继续运行。

  2. 当catch块中含有System.exit(0)语句时,则不执行finally块中的语句,程序直接终止;当catch块中含有return语句时则执行完finally块中的语句后再终止程序。

下面给出多异常处理实例:

//异常的捕获与处理
public class TryCatchFinally {
    public static void main(String[] args) {
        int i;
        int[] a = {1,2,3,4};
        for(i = 0;i < 5;i++) {
            try {
                System.out.println("a[" + i + "]/" + i + "=" + (a[i]/i));
            }
            catch(ArrayIndexOutOfBoundsException e) {
                System.out.print("捕获到数组下标越界异常");
            }
            catch (ArithmeticException e) {
                System.out.print("异常类名称是:"+e);
                //显示异常信息
            }
            catch (Exception e) {
                System.out.println("捕获"+e.getMessage() + "异常!");
                //显示异常信息
            }
            finally {
                System.out.println("finally i =" + i);
            }
            System.out.println(("继续!!"));
        }
    }
}

运行结果如下:

异常类名称是:java.lang.ArithmeticException: / by zero
finally i =0
a[1]/1=2
异常类名称是:java.lang.ArithmeticException
finally i =1
a[2]/2=1
异常类名称是:java.lang.ArithmeticException
finally i =2
a[3]/3=1
异常类名称是:java.lang.ArithmeticException
finally i =3
捕获到数组下标越界异常finally i =4
继续!!

抛出异常

如果在一个方法内部的语句执行时可能引发某种异常,但是并不能确定如何处理,则此方法应声明抛出异常,表明该方法将不对这些异常进行处理,而由该方法的调用者负责处理,也就是说,方法中的异常没有用try-catch语句捕获异常和处理异常的代码。

说明:通过这两种方式抛出异常,在方法中就不必编写try-catch-finally程序段,而交由调用此方法的程序来处理。当然在这两种情况下,也可以在本方法内用 try-catch-finally语句来处理异常。

抛出异常的方法

一个方法声明抛出异常有两种方式:
方式一,在方法体内使用throw语句抛出异常对象,其语法格式为:

//throw   由异常类所产生的对象;例如 :
throw new IllegalArgumentException("求负数阶乘异常"); 
//其中“由异常类所产生的对象”是一个从Throwable派生的异常类对象。

方式二,在方法头部添加 throws子句表示方法将抛出异常。带有throws子句的方法的声明格式如下:

//[修饰符]返回值类型 方法名([参数列表])throws 异常类列表,例如
static void check(String str1) throws NullPointerException  //方法头抛出空指针异常
  {
    if(str1.length()>2)     //如果字符串参数str的字符长度大于2
    {
      str1=null;            //则字符串参数赋值为空
      System.out.println(str1.length());     //试图输出空串的长度会抛出空指针异常
    }
    char ch;
    for (int i=0;i<str1.length();i++)
    {
      ch=str1.charAt(i);
      if(!Character.isDigit(ch))                 //判断参数中字符是否为数字
        throw new NumberFormatException();       //方法中抛出数值格式异常
    }
  }
  //throws是关键字,“异常类列表”是方法中要抛出的异常类,当异常类多于一个的时候,要用逗号“,”隔开。
调用方法处理异常

4. 自定义异常类

除了内置的异常类之外,Java语言也允许用户自行定义异常类。

二. 常用类

String类

构造String对象

String s1 = new String("Java");
char a [] = {'J','a','v','a'};
String s2 = new String(a);
//s1,s2输出均为  Java

char a [] = {'J','a','v','a'};
String s1 = new String(a,0,2);
String s2 = new String(a,2,2);
String s;
s=s1+s2;
//s1输出为 Ja   s2输出为  va   s输出为Java

String的常用方法

public int length()
/*获取一个String 对象的字符序列的长度*/

public boolean equals(String s)
/*比较当前对象是否与参数 s 指定的对象的字符序列是否相同,
是返回true,否返回false*/

public boolean startsWith(String s)
/*判断当前String对象的字符序列前缀是否是参数 s 指定对象的字符序列*/
public boolean endsWith(String s)
/*判断当前String对象的字符序列后缀是否是参数 s 指定对象的字符序列*/


public int compareTo(String s)
/*将当前String对象按字典序与参数 s 指定对象的字符序列比较大小,
相同返回 0 ,大于 s 返回正值,小于 s 返回负值*/

public boolean contains(String s)
/*判断当前String对象字符序列是否包含参数 s 的字符序列*/
 
public int indexOf(String s)/*当前对象字符序列 0 索引位置开始检索
首次出现 s 字符序列的位置,并返回该位置,没有检索则返回 -1*/ 
public int indexOf(String s,int startpoint)/*当前对象字符序列 startpoint 索引
位置开始检索首次出现 s 字符序列的位置,并返回该位置,没有检索则返回 -1 */

public int lastIndexOf(String s)/*当前对象字符序列 0 索引位置
开始检索最后一次出现 s 字符序列的位置,并返回该位置,没有检索到返回 -1 */

public String substring(int startpoint)/*获得一个新的 String 对象,
新对象是复制当前对象 startpoint 位置至最后位置的字符*/
Public String substring(int start,int end)/*获得一个新的 String 对象,
新对象是复制当前对象 start 位置至 end-1 的字符*/

public String trim()/*得到当前对象去掉前后空格后的新字符序列*/

StringBuffer

StringBuffer对象

String对象的的字符数列的字符是不能被修改、删除,即String对象的实体是不可以再发生变化的。而StringBuffer类的对象的实体的内存空间是可以自动地改变大小,便于存放可变的字符数列。

常用方法

append方法

StringBuffer append(String s)/*将 String 对象s的字符序列追加到当前StringBuffer
对象的字符序列中,并返回当前 StringBuffer 对象的引用。*/
StringBuffer append(int n)/*将int型数据n转化为String对象,再把该String对象的
字符序列追加到当前 StringBuffer对象的字符序列中,并返回当前StringBuffer对象的引用。*/

public char charAt(int n)和public void setCharAt(int n, char ch) 方法

char charAt(int n)//得到 StringBuffer对象的字符序列位置n上的字符
setCharAt(int n,char ch)/*当前 StringBuffer 对象/*的字符序列位置n处的字符
用参数ch指定的字符替换*/

StringBuffer insert(int index, String str)

StringBuffer insert(int index, String str)/*将参数str指定的字符序列插入到
参数index指定的位置并返回对象的引用。*/

public StringBuffer reverse()

 public StringBuffer reverse()//将该对象实体中的字符序列翻转,并返回当前对象的引用。

StringBuffer delete(int startIndex, int endIndex)

StringBuffer delete(int startIndex, int endIndex)
/*从当前 StringBuffer 对象的字符序列中删除一个子字符序列,并返回当前对象的引用。
从startIndex位置到endIndex-1位置处的字符序列被删除*/
deleteCharAt(int index)/*删除当前StringBuffer 对象实体的字符序列中index位置处的一个字符。*/

StringBuffer replace( int startIndex, int endIndex, String str)

StringBuffer replace( int startIndex, int endIndex, String str)
/*将当前StringBuffer对象的字符序列的一个子字符序列用参数str指定的字符序列替换。
被替换的子字符序列由下标 startIndex 和 endIndex 指定,即从 startIndex到
endIndex-1的字符序列被替换。该方法返回当前StringBuffer 对象的引用。*/

Date类

使用Date类的无参数构造方法创建的对象可以获取本机的当前日期和时间,例如:

Date nowTime= new Date();//当前nowTime对象的实体中含有的日期和时间就是创建nowTime对象时本地计算机的日期和时间。
System.out.println(nowTime);//输出结果为  Sun Mar 31 20:09:68 CST 2023

Math类和Eandom类

Math类常用方法

public static long abs(double a)//返回a的绝对值。
public static double max(double a,double b)//返回a、b的最大值。
public static double min(double a,doubleb)//返回a、b的最小值。
public static double random()://产生一个0~1之间的随机数(不包括0和1)。
public static double pow(double a,double b)//返回a的b次幂。
public static double sqrt(double-a)//返回a的平方根。
public static double log(double a)//返回a的对数。
public static double sin(double a)//返回a的正弦值。
public static double asin(double a)//返回a的反正弦值。
public static double ceil(double a)//返回大于a的最小整数,并将该整数转化为double型数据。
public static double floor(double a)//返回小于a的最大整数,并将该整数转化为double型数据
public static long round(double a)//返回值是(long)Math.floor(a+0.5)),即所谓a的“四舍五入”后的值。

Eandom类常用方法

Java提供了更为灵活的用于获得随机数的Random类(该类在java.util包中)。人们习惯地将Random对象称为随机数生成器。

Random random=new Random();//使用当前机器时间作为种子创建一个Random对象
random.nextInt();//返回一个随机整数。
random.nextInt (n);//让随机数生成器random返回一个0~n之间(包括0,但不包括n)的随机数
random.nextBoolean();//返回一个随机 boolean 值

三. 泛型

泛型的基本概念

泛型其实质就是将数据的类型参数化,通过为类、接口及方法设置类型参数来定义泛型。泛型使一个类或一个方法可在多种不同类型的对象上进行操作,运用泛型意味着编写的代码可以被很多类型不同的对象所重用,从而减少数据类型转换的潜在错误。。泛型实际上是在定义类、接口或方法时通过为其增加“类型参数”来实现的。即泛型所操作的数据类型被指定为一个参数,这个参数称为类型参数(Type Parameters),泛型的实质是将数据的类型参数化。当这种类型参数用在类、接口以及方法的声明中时,则分别称为泛型类、泛型接口和泛型方法。

泛型类及其应用

在使用泛型定义的类创建对象时,即在泛型实例化时,可以根据不同的需求给出类型参数T的具体类型。而在调用泛型类的方法传递或返回数据类型时可以不用进行类型转换,而是直接用T作为类型来代替参数类型或返回值的类型。
说明:在实例化泛型类的过程中,实际类型必须是引用类型,即必须是类类型,不能用如int、double或char等这样的基本类型来替换类型参数T。

public class Demo3_1<T>         //定义泛型类,T是类型参数
{
    private T obj;            //定义泛型类的成员变量
    public T getObj()         //定义泛型类的方法getObj()
    {
        return obj;
    }
    public void setObj(T obj)   //定义泛型类的方法setObj()
    {
        this.obj=obj;
    }
    public static void main(String[] args)
    {
        Demo3_1<String> name=new Demo3_1<String>();  //创建App12_1<String>型对象
        Demo3_1<Integer> age=new Demo3_1<Integer>();  //创建App12_1<Integer>型对象
        name.setObj("张小华");
        String newName=name.getObj();
        System.out.println("姓名:"+newName);
        age.setObj(25);                //Java自动将25包装为new Integer(25)
        int newAge=age.getObj();       //Java将Integer类型自动解包成int类型
        System.out.println("年龄:"+newAge);
    }
}

运行结果为

姓名:张小华
年龄:25

泛型接口

泛型方法

一个方法是否是泛型方法与其所在的类是否是泛型类没有关系。要定义泛型方法,只需将泛型的类型参数置于返回值类型前面即可。在Java中任何方法包括静态方法和构造方法都可声明为泛型方法。泛型方法除了定义不同,调用时与普通方法一样。

//filename App12_2.java
public class Demo3_2             //定义一般类,即非泛型类
{
    public static void main(String[] args)
    {
        Integer[] num={1,2,3,4,5};                     //定义数组
        String[] str={"红","橙","黄","绿","青","蓝","紫"};
        Demo3_2.display(num);//用类名调用静态泛型方法
        Demo3_2.display(str);
    }
    public static <E> void display(E[] list)  //定义泛型方法,E为类型参数
    {
        for(int i=0;i<list.length;i++)
            System.out.print(list[i]+ "  ");
        System.out.println();
    }
}

运行结果如下:

1 2 3 4 5
红 橙 黄 绿 青 蓝 紫

四. 容器

容器的基本概念

容器类是Java以类库的形式供用户开发程序时可直接使用的各种数据结构。所谓数据结构,就是以某种方式将数据组织在一起,并存储在计算机中。数据结构不仅可以存储数据,还支持访问和处理数据的操作。在面向对象的思想中,一种数据结构被认为是一个容器。数组是一种简单的数据结构,除数组外Java还以类库的形式提供了许多其他数据结构。这些数据结构通常称为容器类或称集合类。

Java容器框架

Java容器框架中有两个名称分别为Collection和Set的接口。Java容器框架提供了一些现成的数据结构可供使用,这些数据结构是可以存储对象的集合,在这里对象也称为元素。从JDK5开始,容器框架全部采用泛型实现,且都存放在java.util包中。
在这里插入图片描述

列表接口List

List介绍

列表接口 List是Collection 子接口,是一种包含有序元素的线性表,其中的元素必须按顺序存放,且可重复,也可以是空值null。元素之间的顺序关系可以由添加到列表的先后来决定,也可由元素值的大小来决定。List接口使用下标来访问元素。下标范围为0~size()-1,List接口新增了许多方法,使之能够在列表中根据具体位置添加和删除元素。

链表类LinkedList

LinkedList链表类采用链表结构保存对象,使用循环双链表实现List。这种结构向链表中任意位置插入、删除元素时不需要移动其他元素,链表的大小是可以动态增大或减小的,但不具有随机存取特性。

LinkedList<E>类的构造方法
public LinkedList()//创建空的链表
public LinkedList(Collection<?extends E> c)//创建包含容器c中所有元素的链表
LinkedList<E>类的常用方法
public void addFirst(E e)
//将元素e插入到列表的开头
public void addLast(E e)
//将元素e添加到列表的尾
public E getFirst()
//返回列表中的第一个元素
public E getLast()
//返回列表中的最后一个元素
public E removeFirst()
//删除并返回列表中的第一个元素
public E removeLast()
//删除并返回列表中的最后一个元素

数组列表类ArrayList

ArrayList数组列表类使用一维数组实现List,该类实现的是可变数组,允许所有元素,包括null。具有随机存取特性,插入、删除元素时需要移动其他元素,当元素很多时,插入、删除操作的速度较慢。在向ArrayList中添加元素时,其容量会自动增大,但不能自动缩小,但可以使用trimToSize()方法将数组的容量减小到数组列表的大小。

ArrayList<E>类的构造方法
public ArrayList() //创建初始容量为10的空数组列表
public ArrayList(int initialCapacity)//创建初始容量为initialCapacity的空数组列表
public ArrayList(Collection<?extends E> c)//创建包含容器c所有元素的数组列表,元素次序与c同
ArrayList<E>类的常用方法
public void trimToSize()
//将 ArrayList对象的容量缩小到该列表的当前大小

选用原则

选用这两种线性表,通常的原则是:若要通过下标随机访问元素,但除了在末尾处之外,不在其他位置插入或删除元素,则应该选择ArrayList类;但若需要在线性表的任意位置上进行插入或删除操作,则应选择LinkedList类。

集合接口Set

Set是一个不含重复元素的集合接口,它继承自Collection接口,并没有声明其他方法,它的方法都是从Collection接口继承来的。Set集合中的对象不按特定的方式排序,只是简单地把对象加入集合中即可,但加入的对象一定不能重复。集合中元素的顺序与元素加入集合的顺序无关。实现Set接口的两个主要类是哈希集合HashSet及树集合TreeSet。

哈希集合HashSet

哈希集合对所包含元素的访问并不是像线性表一样使用下标,而是根据哈希码来存取集合中的元素。

哈希码的概念:哈希集合是在元素的存储位置和元素的值k之间建立一个特定的对应关系f,使每个元素与一个唯一的存储位置相对应。因而在查找时,只要根据元素的值k,计算f(k)的值即可,如果此元素在集合中,则必定在存储位置f(k)上,因此不需要与集合中的其他元素进行比较便可直接取得所查的元素。称这个对应关系f为哈希(Hash)函数,按这种关系建立的表称为哈希表也称散列表。

HashSet类是基于哈希表的Set接口实现。HashSet根据哈希码来确定元素在集合中的存储位置(即内存地址),因此可以根据哈希码来快速地找到集合中的元素。HashSet类不保证迭代顺序,且允许元素值为null。

HashSet<E>类构造方法
public HashSet()
//创建默认初始容量是16,默认上座率为0.75的空哈希集合
public HashSet(int initialCapacity)
//创建初始容量是initialCapacity,默认上座率为0.75的空哈希集合
public HashSet(int initialCapacity,float loadFactor)
//创建初始容量是initialCapacity,上座率为 loadFactor的空哈希集合
public HashSet(Collection<?extends E> c)
//创建包含容器c中所有元素,默认上座率为0.75的哈希集合
HashSet<E>类常用方法
public boolean add(E e)
/*如果集合中尚未包含指定元素,则添加元素e,并返回true;如果集合中已包含该元素,
则该调用不更改集合并返回false*/
public void clear()
//删除集合中的所有元素,集合为空
public boolean contains(Object o)
//如果集合中包含元素o,则返回true
public int size()
//返回集合中所包含元素的个数,即返回集合的容量

树集合TreeSet

树集合TreeSet类不仅实现了Set接口,还实现了java.util.SortedSet 接口。TreeSet的工作原理与HashSet相似,但TreeSet增加了一个额外步骤,以保证集合中的元素总是处于有序状态。因此,当排序很重要时,就选择TreeSet,否则应选用HashSet。

TreeSet<E>类常用的构造方法
public TreeSet()
//创建新的空树集合,其元素按自然顺序进行排序
public TreeSet(Collection<?extends E>c)
//创建包含容器c元素的新TreeSet,按其元素的自然顺序进行排序
TreeSet<E>类常用的方法
public E first()
//返回集合中的第一个(最低)元素
public E last()
//返回集合中的最后一个(最高)元素
public SortedSet<E> headSet(E toElement)
//返回一个新集合,新集合元素是toElement(不包含toElement)之前的所有元素
public SortedSet<E> tailSet(E fromElement)
//返回一个新集合,新集合元素包含 fromElement 及fromElement之后的所有元素
public SortedSet<E> subSet(E fromElement,E toElement)/*返回一个新集合,新集合
包含从 fromElement 到toElement(不包含toElement)之间的所有元素*/
public E lower(E e)
//返回严格小于给定元素e的最大元素,如果不存在这样的元素,则返回null
public E higher(E e)
//返回严格大于给定元素e的最小元素,如果不存在这样的元素,则返回null
public E floor(E e)
//返回小于或等于给定元素e的最大元素,如果不存在这样的元素,则返回null
public E ceiling(E e)
//返回大于或等于给定元素e的最小元素,如果不存在这样的元素,则返回null

映射接口Map

Map中的元素都是成对出现的,它提供了键(Key)到值(Value)的映射。值是指要存入Map中的元素(对象),键决定了值在Map中的存储位置。Map中的每个键都是唯一的,且每个键最多只能映射到一个值。

键很像下标,但在List中下标是整数,而在Map中键可以是任意类型的对象。如果要在Map中检索一个元素,必须提供相应的键,这样就可以通过键访问到其对应元素的值。

HashMap

HashMap类是基于哈希表的Map接口的实现,所以HashMap通过哈希码对其内部的映射关系进行快速查找,因此对于添加和删除映射关系效率较高,并且允许使用null值和null键,但必须保证键的唯一性。

HashMap<K,V>类常用的构造方法
public HashMap()
//构造一个具有默认初始容量(16)和默认上座率(0.75)的空HashMap对象
public HashMap(int initialCapacity)
//创建初始容量为 initialCapacity,默认上座率(0.75)的空HashMap对象
public HashMap(Map <?extends K,?extends V> m)
/*创建一个映射关系与指定Map相同的新 HashMap对象,
具有默认上座率(0.75)和足以容纳指定Map中映射关系的初始容量*/
HashMap类的方法大多是继承自Map接口

TreeMap

TreeMap中的映射关系存在一定的顺序,如果希望Map映射中的元素也存在一定的顺序,应该使用TreeMap类实现的Map映射,由于TreeMap类实现的Map映射中的映射关系是根据键对象按照一定的顺序排列的,因此不允许键对象是null。

TreeMap<K,V>类构造方法
public TreeMap()
//使用键的自然顺序创建一个新的空树映射
public TreeMap(Map<? extends K,?extends V> m)
//创建一个与给定映射具有相同映射关系的新树映射,该映射根据其键的自然顺序进行排序
TreeMap<K,V>类常用的方法
public K firstKey()
//返回映射中的第一个(最低)键
public K lastKey()
//返回映射中的最后一个(最高)键
public SortedMap<K,V> headMap(K toKey)
//返回键值小于toKey的那部分映射
public SortedMap<o<K,V>tailMap(K fromKey)
//返回键值大于或等于fromKey的那部分映射
public K lowerKey(K key)
//返回严格小于给定键key的最大键,如果不存在这样的键,则返回 null
public K floorKey(K key)
//返回小于或等于给定键key的最大键,如果不存在这样的键,则返回 null
public K higherKey(K key)
//返回严格大于给定键key的最小键,如果不存在这样的键,则返回null
public K ceilingKey(K key)
//返回大于或等于给定键key的最小键,如果不存在这样的键,则返回null
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值