Java:24-异常机制和File类

异常机制和File类

异常机制------------------------------
异常就是"不正常"的含义,在Java语言中主要指程序执行中发生的不正常情况
java.lang.Throwable类是Java语言中错误(Error)和异常(Exception)的超类
public class Throwable
extends Object
implements Serializable
//Serializable,序列化接口
其中Error类主要用于描述Java虚拟机无法解决的严重错误,通常无法编码解决,如:JVM挂掉了等
其中Exception类主要用于描述因编程错误或偶然外在因素导致的轻微错误,通常可以编码解决,如:0作为除数等
异常的分类------------------------------

在这里插入图片描述

java.lang.Exception类是所有异常的超类
主要分为以下两种:RuntimeException - 运行时异常,也叫作非检测性异常
IOException和其它异常 - 其它异常,也叫作检测性异常,所谓检测性异常就是指在编译阶段都能被编译器检测出来的异常。
其中RuntimeException类的主要子类------------------------------
ArithmeticException类 - 算术异常
ArrayIndexOutOfBoundsException类 - 数组下标越界异常
NullPointerException - 空指针异常
ClassCastException - 类型转换异常
NumberFormatException - 数字格式异常
注意:当程序执行过程中发生异常但又没有手动处理时,则由Java虚拟机采用默认方式处理异常
而默认处理方式就是:打印异常的名称、异常发生的原因、异常发生的位置以及终止程序
package com.lagou.task16;

public class ExceptionTest {

    public static void main(String[] args) {

        // 1.见识一下非检测性异常  运行时异常
        System.out.println(5 / 0); // 编译ok,运行阶段会发生算术异常
        //Exception in thread "main" java.lang.ArithmeticException: / by zero 打印了原因
        //at com.lagou.task16.ExceptionTest.main(ExceptionTest.java:11) 打印了位置
        //当程序执行过程中发生异常但又没有手动处理时,则由Java虚拟机采用默认方式处理异常
        // 而默认处理方式就是:打印异常的名称、异常发生的原因、异常发生的位置以及终止程序
        //发生异常,那么后面代码不运行
        //System.out.println(0 / 0); // 编译ok,运行阶段会发生算术异常
        //System.out.println(0 / 0.0); //NaN 不存在这个数
        //System.out.println(5 / 0.0); //Infinity 正无穷(Infinity)和负无穷(-Infinity)。
        // 2.检测性异常
        //Thread.sleep(1000); // 编译错误  不处理就无法到运行阶段
        //Unhandled exception: java.lang.InterruptedException,没有给出异常来处理
        //即中断异常没有,InterruptedException没有

        System.out.println("程序正常结束了!");
    }
}

异常的避免------------------------------
在以后的开发中尽量使用if条件判断来避免异常的发生
但是过多的if条件判断会导致程序的代码加长、臃肿,可读性差
package com.lagou.task16;

import java.io.IOException;

public class ExceptionPreventTest {

    public static void main(String[] args) {
        String l = "null";
        String k = "1";
        System.out.println(l.equals(k));
        //当l不为直接赋值时最好让他为参数
        //如System.out.println(k.equals(l));
        //防止l为null时报错,提示空指针异常
        //这是好的习惯
        // 会发生算术异常
        int ia = 10;
        int ib = 0;
        if (0 != ib) {
            System.out.println(ia / ib);
        }

        // 数组下标越界异常
        int[] arr = new int[5];
        int pos = 5;
        if (pos >= 0 && pos < 5) {
            System.out.println(arr[pos]);
        }

        // 发生空指针异常
        String str = null;
        if (null != str) {
            //之所以null放前面,防止给str赋值
            //这是好的习惯
            System.out.println(str.length());
        }

        // 类型转换异常
        Exception ex = new Exception();
        if (ex instanceof IOException) {
            IOException ie = (IOException) ex; //有无地方指向,若为null,即可以指
        }

        // 数字格式异常
        String str2 = "123a";
        if (str2.matches("\\d+")) {
            System.out.println(Integer.parseInt(str2)); //变为Integer必须为数字
        }

        System.out.println("程序总算正常结束了!");
    }
}

异常的捕获------------------------------
//语法格式
try { 
    编写可能发生异常的代码;
}catch(异常类型 引用变量名) {
    编写针对该类异常的处理代码;
}
...
finally {
    编写无论是否发生异常都要执行的代码;
}
package com.lagou.task16;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ExceptionCatchTest {

    public static void main(String[] args) {

        // 创建一个FileInputStream类型的对象与d:/a.txt文件关联,打开文件
        FileInputStream fis = null;
        try { //try尝试
            System.out.println("1");
            // 当程序执行过程中发生了异常后直奔catch分支进行处理
            fis = new FileInputStream("d:/a.txt");
            System.out.println("2");
        } catch (FileNotFoundException e) { //尝试的同时,发生异常,catch抓异常,没发生不抓
            System.out.println("3");
            e.printStackTrace(); //打印异常信息
            System.out.println("4");
        }
        // 关闭文件
        try {
            System.out.println("5");
            fis.close(); //当fis为null时,发生空指针异常
            System.out.println("6");
        } /*catch (Exception e) {
            e.printStackTrace();
        }*/ catch (IOException e) { //这个异常抓不了空指针异常
            System.out.println("7");
            e.printStackTrace();
            System.out.println("8");
        } catch (NullPointerException e) { //可以抓空指针异常,即特定的异常可以手动处理
            e.printStackTrace();
        } catch (Exception e) { //但这个大的异常,包括很多的异常,必须放后面,防止细节的错过
            //细节就是知道你是什么异常处理的,如上面的空指针异常,可以打提示,如果被抓了,那么只操作一个
            e.printStackTrace();
        }
        //所谓的异常处理就是打印异常的信息
        //如果是商业的话,可以弹出小窗口,来告诉客户一些提示

        System.out.println("世界上最真情的相依就是你在try我在catch" +
                "无论你发神马脾气我都默默承受并静静的处理,到那时再来期待我们的finally!");
        // 当程序执行过程中没有发生异常时的执行流程:1 2  5 6  世界上...
        // 当程序执行过程中发生异常又没有手动处理空指针异常时的执行流程:1 3 4  5  空指针异常导致程序终止
        // 当程序执行过程中发生异常并且手动处理空指针异常时的执行流程: 1 3 4 5 世界上...

        // 手动处理异常和没有处理的区别:代码是否可以继续向下执行
    }
}

注意事项------------------------------
//当需要编写多个catch分支时,切记小类型应该放在大类型的前面
//懒人的写法: catch(Exception e) {} 
//finally通常用于进行善后处理,如:关闭已经打开的文件等,防止其他程序发生异常
//若其他程序发生异常,就会使得后续代码不运行,而让文件关闭不了
//但是也要知道finally里也会有异常,即也会让文件关闭不了,这种情况也是要避免的
//且try,catch,finally都可以定义相同的变量,即空间不共享
//执行流程
try {
    a;
    b; - 可能发生异常的语句
    c;
}catch(Exception ex) { 
    d;
}finally {
    e;
} 
//当没有发生异常时的执行流程:a b c e; 当发生异常时的执行流程:a b d e;
package com.lagou.task16;

public class ExceptionFinallyTest {

    // 笔试考点
    public static int test() {
        try {
            int[] arr = new int[5];
            System.out.println(arr[5]);
            return 0;
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
            return 1;
        } finally {
            return 2; // 提交结束方法并返回数据
            //try和catch在有代码让他们结束时(如return或者异常等等)或者代码全部运行完
            //都要运行finally里的代码
            //即可以说当try和catch有让finally不能执行的结果时
            //finally都要让他们等一下执行,然后执行finally的代码,若这个代码有return,那么操作他的return,否则操作其他的return,即谁最终操作了return,那么谁返回
        }
    }

    public static void main(String[] args) {

        try {
            int ia = 10;
            int ib = 0;
            //有可能发生异常的最好用异常处理,如try里面
            //"运行时异常"可以不写异常处理,而"检测时异常"必须写异常处理
            //对于"检测时异常"虽然写了异常处理,但还是会报错
            //相当于将他的检测时异常往后面移动,使得运行时发生异常
            //而运行时异常就直接到运行时发生异常
            System.out.println(ia / ib);
        } catch (ArithmeticException e) {
            e.printStackTrace();

            String str1 = null;
            //str1.length(); // 会发生空指针异常
            //其他程序结束,但finally会执行

        } finally {
            System.out.println("无论是否发生异常都记得来执行我哦!");  // 依然是执行
        }

        System.out.println("Over!"); // 不执行了

        System.out.println("----------------------------------------");
        int test = test();
        System.out.println("test = " + test); // 2
    }
}

finally在通过其他如try或者catch里的必须跳出等语句时,他们的必须跳出结果,finally不影响(在上面的笔试考点里面,设置变量就知道了,finally没有改变原来的return变量的值,即不影响,即悄悄存起来了,最后返回)
如:return,可以说是将他们的返回值悄悄存起来,最后返回
例子:
  public static int test() {
        int a = 0;
        try {
            int[] arr = new int[5];
            System.out.println(arr[5]);
            return 0;
        } catch (ArrayIndexOutOfBoundsException e) {
            e.printStackTrace();
            return a; //0进行保存
        } finally {
            a=a+1; 
            
        }
    }
//上面返回的结果是0,即a被保存了

/*
还可以不操作catch,也就是报错后,直接到finally
try{
            int i = 1/0;
        }finally {
            System.out.println(1);
        }
        这样自然会打印异常信息,因为没有处理,所以会打印,而不是交给catch处理(没有了)
*/

异常的抛出------------------------------
在某些特殊情况下有些异常不能处理或者不便于处理时,就可以将该异常转移给该方法的调用者(连起来)
这种方法就叫异常的抛出
当方法执行时出现异常,则底层生成一个异常类对象抛出,此时异常代码后续的代码就不再执行
//语法格式
访问权限 返回值类型 方法名称(形参列表) throws 异常类型1,异常类型2,...{
		方法体; 
}
//如: public void show() throws IOException{} 
方法重写的原则------------------------------
要求方法名相同、参数列表相同以及返回值类型相同,从jdk1.5开始支持返回子类类型
要求方法的访问权限不能变小,可以相同或者变大
要求方法不能抛出更大的异常
注意:子类重写的方法不能抛出更大的异常、不能抛出平级不一样的异常,但可以抛出一样的异常、更小的异常以及不抛出异常
经验分享------------------------------
若父类中被重写的方法没有抛出异常时,则子类中重写的方法只能进行异常的捕获处理
若一个方法内部又以递进方式分别调用了好几个其它方法
则建议这些方法内可以使用抛出的方法处理到最后一层进行捕获方式处理,也可以进行抛,但最好捕获
package com.lagou.task16;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

public class ExceptionThrowsTest {

    public static void show() throws IOException {
        FileInputStream fis = new FileInputStream("d:/aaaaaa.txt");
        System.out.println("我想看看你抛出异常后是否继续向下执行???");
        fis.close();
        //当代码有的异常包含其他代码的异常时,用当前代码异常
        // 如IOException包含FileNotFoundException
        //而异常可以理解为有可能会报错
        // 有可能报错的可以称为编译时异常
        //而看不出的,可以理解为运行时异常
        //当然最主要的是要看你用的方法或者其他的是否用其他异常
        //若有,必须抛出异常他们的异常,如FileInputStream("d:/a.txt")的FileNotFoundException
        //那么这里用了,必须要抛FileNotFoundException异常,注意:只要你继承了RuntimeException就认为你的异常的运行时异常,编译期不会报错,但是如果你继承他的父类Exception就是编译期异常了,对于运行时异常来说,我们并不需要进行抛出(可以选择捕获或者不捕获),这是编译期异常要干的事情,所以对于捕获的理解就是我可以利用jvm来处理,或者利用上层的try来处理,而运行时异常直接处理,即打印错误信息,可不会进行处理的哦(try使得跳过对应的异常而除了catch),所以最终的异常出现就是对应的类似于throw new NullPointerException();的 ,而try和抛出就是将他进行操作的手段,基本上都是这样

 //再简单点,直接手动的throw是当场进行打印异常并结束,也就是认为现在有错误
        //try是检测并进行打印异常并结束
        //抛出是交给其他调用者处理,最终由jvm或者try(也就是说,抛出有时需要try来处理的,只有throw是单独的)进行处理
        //但是可以肯定的是,try和抛出所对应的代码是不一定有错误的,也就是说,只是一个防止作用,更加简单点,就是防止出现错误或者你手动的throw等等,所以才可以说try和抛出就是将认为有错误或者有可能会执行throw进行操作的手段
        //但不可否认的是,抛出只是一个警示作用(所以代码出现的异常(如默认的,或者你throw的,一般来说默认的通常不用考虑),这个抛出异常可以是不一样的,虽然并不建议),基本只由try或者jvm处理,而try不只是操作抛出,也可以操作直接的throw,而jvm有自身的默认异常,如int i = 1/0,出现异常,会到默认的异常(也就是算术异常)

        //但最后都是如下
        /*
        public FileInputStream(String name) throws FileNotFoundException {
        this(name != null ? new File(name) : null);
}
         public File(String pathname) {
        if (pathname == null) {
            throw new NullPointerException(); //抛出异常,throw抛的意思
            //当有这个时,方法的throws会获取,然后去对应的异常里,然后打印异常信息
        }
        this.path = fs.normalize(pathname);
        this.prefixLength = fs.prefixLength(this.path);
    }
      public FileInputStream(File file) throws FileNotFoundException {
        String name = (file != null ? file.getPath() : null);
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            security.checkRead(name);
        }
        if (name == null) {
            throw new NullPointerException();
        }
        if (file.isInvalid()) {
            throw new FileNotFoundException("Invalid file path"); //抛出异常,throw抛的意思
        }
        fd = new FileDescriptor();
        fd.attach(this);
        path = name;
        open(name);
        altFinalizer = getFinalizer(this);
        if (altFinalizer == null) {
            FileCleanable.register(fd);       // open set the fd, register the cleanup
        }
    }

总结:
抛出和try只是警示作用,可以不写
而当他们不写时,可以选择直接的throw
其中抛出后,可以选择try和jvm来进行处理
如果throw后,可以选择try或者自身来进行处理(当然,自身处理,最终都是jvm来处理)

所以异常本身是给jvm来处理的,如果存在try,那么交给try来处理,抛出通常可以选择不需要,只不过是警示或者专门给该操作写一个自定义异常,而进行抛出(即对某些操作进行警示,比如文件,就有文件异常,虽然可以不抛,但是可以警示,认为需要考虑异常的处理)
所以说,为了规范,大多数都会写上抛出,如果不考虑自定义或者怕麻烦,可以考虑直接的throw
         */
    }

    public static void test1() throws IOException {
        show();
    }

    public static void test2() throws IOException {
        test1();
    }

    public static void test3() throws IOException {
        test2();
    }

    // 不建议在main方法中抛出异常   JVM负担很重
    //main方法里抛异常,则到Java虚拟机
    public static void main(String[] args) /*throws IOException*/ {
        try {
            show();
        } catch (IOException e) {
            e.printStackTrace();
        }

        System.out.println("------------------------------------");
        try {
            test3();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

package com.lagou.task16;

import java.io.IOException;

public class ExceptionMethod {

    public void show() throws IOException {}
}

package com.lagou.task16;

import com.sun.jdi.ClassNotLoadedException;

import java.io.FileNotFoundException;
import java.io.IOException;

public class SubExceptionMethod extends ExceptionMethod {

    @Override
    public void show() throws IOException {} // 子类重写的方法可以抛出和父类中方法一样的异常
    //public void show() throws FileNotFoundException {}  // 子类重写的方法可以抛出更小的异常
    //public void show() {} // 子类可以不抛出异常
    //public void show() throws ClassNotLoadedException {} // 不可以抛出平级不一样的异常
    //public void show() throws Exception {} // 不可以抛出更大的异常
}

自定义异常------------------------------
当需要在程序中表达年龄不合理的情况时,而Java官方又没有提供这种针对性的异常,此时就需要程序员自定义异常加以描述
实现流程------------------------------
自定义xxxException异常类继承Exception类或者其子类
提供两个版本的构造方法,一个是无参构造方法,另外一个是字符串作为参数的构造方法
异常的产生------------------------------
throw new 异常类型(实参);
//如: 
throw new AgeException("年龄不合理!!!");
Java采用的异常处理机制是将异常处理的程序代码集中在一起,与正常的程序代码分开,使得程序简洁、优雅,并易于维护
package com.lagou.task16;

public class AgeException extends Exception {

    static final long serialVersionUID = 7818375828146090155L; // 序列化的版本号  与序列化操作有关系

    public AgeException() {
    }

    public AgeException(String message) {
        super(message); //底层处理的,用来提示某些错误打印信息
    }
}

package com.lagou.task16;

public class Person {
    private String name;
    private int age;

    public Person() {
    }

    public Person(String name, int age) /*throws AgeException */{
        setName(name);
        setAge(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 && age < 150) {
            this.age = age;
        } else {
            //System.out.println("年龄不合理哦!!!");
            try {
                throw new AgeException("年龄不合理哦!!!");
            } catch (AgeException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

package com.lagou.task16;

public class PersonTest {

    public static void main(String[] args) {

        /*Person p1 = null;
        try {
            p1 = new Person("zhangfei", -30);
        } catch (AgeException e) {
            e.printStackTrace(); //调用异常Exception的父类Throwable的printStackTrace()方法
        }
        System.out.println("p1 = " + p1); // zhangfei 0*/
        Person p1 = new Person("zhangfei", -30);
        System.out.println("p1 = " + p1); // zhangfei 0  null
    }
}

在这里插入图片描述

File类------------------------------
java.io.File类主要用于描述文件或目录路径的抽象表示信息,可以获取文件或目录的特征信息,如:大小等
而io流用来读写
File(String pathname),根据参数指定的路径名来构造对象
File(String parent, String child),根据参数指定的父路径和子路径信息构造对象
File(File parent, String child),根据参数指定的父抽象路径和子路径信息构造对象
boolean exists(),测试此抽象路径名表示的文件或目录是否存在
String getName(),用于获取文件的名称
long length(),返回由此抽象路径名表示的文件的长度
long lastModified(),用于获取文件的最后一次修改时间
String getAbsolutePath(),用于获取绝对路径信息
boolean delete(),用于删除文件,当删除目录时要求是空目录
boolean createNewFile(),用于创建新的空文件
boolean mkdir(),用于创建目录
boolean mkdirs(),用于创建多级目录
File[] listFiles(),获取该目录下的所有内容
boolean isFile(),判断是否为文件
boolean isDirectory(),判断是否为目录
File[] listFiles(FileFilter filter),获取目录下满足筛选器的所有内容
目录就是目录,文件就是文件,不要以为最后一级就一定是文件了,这里可以看后面的代码就知道了
一般来说,如果创建的目录或者文件存在,可能是到下一级(多级目录)继续判断或者返回是否创建过的意思(true和false),而并不会出现错误,这里可以自行测试
案例题目------------------------------
遍历指定目录以及子目录中的所有内容并打印出来
package com.lagou.task16;

import java.io.File;
import java.io.FileFilter;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;

public class FileTest {

    // 自定义成员方法实现指定目录以及子目录中所有内容的打印
    public static void show(File file) {
        // 获取目录f3下的所有内容并记录到一维数组中
        File[] filesArray = file.listFiles();
        // 遍历数组
        for (File tf: filesArray) {
            String name = tf.getName();
            // 判断是否为文件,若是则直接打印文件名称
            if (tf.isFile()) {
                System.out.println(name);
            }
            // 若是目录,则使用[]将目录名称括起来
            if (tf.isDirectory()) {
                System.out.println("[" + name + "]");
                show(tf);
            }
        }
    }

    public static void main(String[] args) throws IOException {

        // 1.构造File类型的对象与d:/a.txt文件关联
        //File(String pathname),根据参数指定的路径名来构造对象
        File f1 = new File("d:/a.txt"); //可以/开头,也就是/d:
        // 2.若文件存在则获取文件的相关特征信息并打印后删除文件
        //boolean exists(),测试此抽象路径名表示的文件或目录是否存在
        if (f1.exists()) {
            //String getName(),用于获取文件的名称
            System.out.println("文件的名称是:" + f1.getName());
            //long length(),返回由此抽象路径名表示的文件的长度
            System.out.println("文件的大小是:" + f1.length());
            //long lastModified(),用于获取文件的最后一次修改时间
            Date d1 = new Date(f1.lastModified());
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            System.out.println("文件的最后一次修改时间:" + sdf.format(d1));
            // 绝对路径: 主要指以根目录开始的路径信息,如:c:/  d:/   /..
            // 相对路径: 主要指以当前目录所在位置开始的路径信息,如:./  ../   相对路径
            //String getAbsolutePath(),用于获取绝对路径信息
            System.out.println("文件的绝对路径信息是:" + f1.getAbsolutePath());
            //boolean delete(),用于删除文件,当删除目录时要求是空目录
            System.out.println(f1.delete()? "文件删除成功": "文件删除失败");
        } else {
            // 3.若文件不存在则创建新的空文件
            //boolean createNewFile(),用于创建新的空文件
            System.out.println(f1.createNewFile()? "文件创建成功": "文件创建失败!");
        }

        System.out.println("---------------------------------------------------------");
        // 4.实现目录的删除和创建
        File f2 = new File("d:/捣乱/猜猜我是谁/你猜我猜不猜/死鬼");
        if (f2.exists()) {
            System.out.println("目录名称是:" + f2.getName());
            //获取最后一个名称,即为死鬼
            System.out.println(f2.delete()? "目录删除成功": "目录删除失败"); //删除空目录
            //即删除死鬼这个目录
        } else {
            //boolean mkdir(),用于创建目录
            //System.out.println(f2.mkdir()? "目录创建成功": "目录创建失败");   // 创建单层目录
            //boolean mkdirs(),用于创建多级目录
            System.out.println(f2.mkdirs()? "目录创建成功": "目录创建失败");   // 创建多层目录 也可单层
        }

        System.out.println("---------------------------------------------------------");
        // 5.实现将指定目录中的所有内容打印出来
        File f3 = new File("d:/捣乱");
        // 获取目录f3下的所有内容并记录到一维数组中
        //File[] listFiles(),获取该目录下的所有内容
        File[] filesArray = f3.listFiles();
        // 遍历数组
        for (File tf: filesArray) {
            String name = tf.getName();
            // 判断是否为文件,若是则直接打印文件名称
            //boolean isFile(),判断是否为文件
            if (tf.isFile()) {
                System.out.println(name);
            }
            // 若是目录,则使用[]将目录名称括起来
            //boolean isDirectory(),判断是否为目录
            if (tf.isDirectory()) {
                System.out.println("[" + name + "]");
            }
        }

        System.out.println("---------------------------------------------------------");
        // 6.实现目录中所有内容获取的同时进行过滤
        // 匿名内部类的语法格式:接口/父类类型 引用变量名 = new 接口/父类类型() { 方法的重写 };
        /*FileFilter fileFilter = new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                // 若文件名是以.avi为结尾,则返回true表示保留   否则返回false就是表示丢弃
                return pathname.getName().endsWith(".avi");
            }
        };*/
        // Lambda表达式的格式:(参数列表) -> {方法体}
        FileFilter fileFilter = (File pathname) -> {return pathname.getName().endsWith(".avi");};
        //File[] listFiles(FileFilter filter),获取目录下满足筛选器的所有内容
        File[] filesArray2 = f3.listFiles(fileFilter);
        for (File tf : filesArray2) {
            System.out.println(tf);
        }

        System.out.println("---------------------------------------------------------");
        // 7.使用递归的思想获取目录以及子目录中的内容
        show(new File("d:/捣乱"));
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值