Java异常与String基础知识

一、异常

Throwable

Error:错误    

代码出现重大错误,相当于人得了绝症,需要写代码,需要重写代码,需要大的改动

Exception:异常

代码出现了小的问题,相当于人的了感冒

(1)编译时期异常

代码一写编译,爆红(语法错误除外)

Exception以及子类除了RuntimeException之外其他子类都属于编译异常

(2)运行时期异常

写代码不报错,一运行就报错

RuntimeException以及子类

异常

概述:代码出现了不正常的现象,在java中,异常都是一个一个的类

1.创建异常对象

创建对象时,只是为了后面学习如何处理异常,其他的暂时没有啥意义

关键字:throw

格式:throw new  异常

public class Demo03Exception {
    public static void main(String[] args) {
        String s="a.txt";
        method(s);

    }

    private static void method(String s) {
        if (!s.endsWith(".txt")){
            //故意创建异常对象,用throw说明此处异常
            throw new NullPointerException();
        }
        System.out.println("我要执行了!");
    }
}

2.异常对象的处理方式

(1)异常处理方式一_throws

格式:在方法参数和方法体之间位置上写

Throws  异常

意义:处理异常

  将异常往上抛

import java.io.FileNotFoundException;

public class Demo04Exception {
    public static void main(String[] args) throws FileNotFoundException {
        String s="a.txt1";
        add(s);//添加功能
        delete();
        update();
        find();
    }

    private static void find() {
        System.out.println("查询功能");
    }

    private static void update() {
        System.out.println("修改功能");
    }

    private static void delete() {
        System.out.println("删除功能");
    }


    private static void add(String s) throws FileNotFoundException {
        if (!s.endsWith(".txt")){
            //故意创造异常
            throw  new FileNotFoundException("文件找不到");
        }
        System.out.println("我要执行了");
    }
}

异常处理方式一_throws多个异常

格式:Throws  异常1,异常2

注意:如果throws的多个异常之间有子父类继承关系,我们可以直接throws父类异常

    如果不知道多个异常之间是否存在有子父类继承关系,我们可以直接throws Exception(所有子类的父类)

(2)异常处理方式二_try....catch

格式:

  Try{

     可能出现异常的代码

}catch(异常 对象名){

    处理异常的代码->将来开发会将异常信息保存在日志文件中

}

public class Demo06Exception {
    public static void main(String[] args)  {
        String s="a.txt1";
        try {
            int[] arr=null;
            System.out.println(arr.length);
            add(s);//添加功能
        }catch (FileNotFoundException e){
            System.out.println(e);
        }

        delete();
        update();
        find();
    }

    private static void find() {
        System.out.println("查询功能");
    }

    private static void update() {
        System.out.println("修改功能");
    }

    private static void delete() {
        System.out.println("删除功能");
    }


    private static void add(String s) throws FileNotFoundException {
        if (!s.endsWith(".txt")){
            //故意创造异常
            throw  new FileNotFoundException("文件找不到");
        }
        System.out.println("我要执行了");
    }
}

(3)异常处理方式二_多个catch

格式:

  Try{

     可能出现异常的代码

}catch(异常 对象名){

    处理异常的代码->将来开发会将异常信息保存在日志文件中

}catch(异常 对象名){

    处理异常的代码->将来开发会将异常信息保存在日志文件中

}

catch(异常 对象名){

    处理异常的代码->将来开发会将异常信息保存在日志文件中

}

catch(异常 对象名){

    处理异常的代码->将来开发会将异常信息保存在日志文件中

}

catch(异常 对象名){

    处理异常的代码->将来开发会将异常信息保存在日志文件中

}.........

注意:如果catch的多个异常之间有了子父类继承关系,我们可以直接catch父类异常

如果不知道多个异常之间是否有子父类继承关系,我们也可以直接catch Exception

import java.io.FileNotFoundException;

public class Demo08Exception {
    public static void main(String[] args)  {
        String s="a.txt";
        try {
            add(s);//添加功能
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }finally {
            System.out.println("我必须执行");
        }

    }




    private static void add(String s) throws FileNotFoundException {
        if (!s.endsWith(".txt")){
            //故意创造异常
            throw  new FileNotFoundException("文件找不到");
        }
        System.out.println("我要执行了");
    }
}

3.finally使用场景

Finally使用场景:关闭资源

原因:对象如果没有用了,GC(垃圾回收器),用来回收堆内存的垃圾,释放内存,但是有一些对象GC回收不了,比如连接对象(connection),socke对象,这些GC无法回收,就需要手动回收,手动关闭

将来不能回收的对象new完以后,后续操作不管是否操作成功是否有异常我们都需要手动关闭,此时我们就可以将关闭资源的代码放到finally中

4.抛异常时注意的问题

(1)如果父类中的方法抛异常,那么子类重写以后要不要抛?

可抛可不抛

(2)如果父类中的方法没有抛异常,那么子类重写以后要不要抛?

不要抛

public class Demo09Exception {
    public static void main(String[] args) {

    }


    class A{
        public void method()  /*throws Exception*/{

        }
    }

    class B extends A{
        @Override
        public void method(){

        }
    }


}

Try...catch和throws的使用时机

如果处理异常之后,还想让后续的代码正常执行我们使用try..catch

如果方法之间时递进关系(调用),我们可以先throws但是到了最后需要用try..catch做一个统一的异常处理

编译时期异常必须要处理,不处理爆红,无法往下写

运行时期异常我们一般不处理, 一旦出现,肯定是代码写得有问题,我们直接修改代码细节就行

5.自定义异常

需求:键盘录入一个用户名,实现登陆功能,如果登陆失败,抛出LoginUserException

import java.util.Scanner;

public class Demo10Exception {
    public static void main(String[] args) throws LoginUserException {

        //定义一个用户名代表已经注册过的用户
        String username="root";
        //录入用户名
        Scanner sc=new Scanner(System.in);
        System.out.println("请您输入用户名:");
        String name=sc.next();
        //判断用户名是否和已存在的一致
        if (name.equals(username)){
            System.out.println("登陆成功");
        }else {
//            try {
                throw new LoginUserException("登陆失败,用户名或密码有问题");
//            } catch (Exception e) {
//                System.out.println(e.toString());
//                System.out.println(e.getMessage());
//                System.out.println(e.printStackTrace(););
//            }
        }


    }
}
public class LoginUserException extends Throwable {


    public LoginUserException() {

    }

    public LoginUserException(String s) {
        super(s);
    }
}

定义一个类

如果继承Exception就是编译时期异常

如果继承Runtimeexception就是运行时期异常

6.打印异常信息的三种方法

Throwable类中的方法:

  String toString():输出的是异常类型和设置的异常信息

  String getMessage():输出的是异常信息

  Void printStackTrace():打印异常信息最全:包括异常类型,信息,以及出现的行数等

二、Object类

概述:所有类的根类(父类),所有的类都会直接或间接继承Object类

1.Object中的toString

Object中的toString

Object中的tostring方法:返回该对象的字符串表示形式

  Public  String   toString(){

      Return  getClass().getName() + '@' + Integer.toHexString(hashCode())

}

注意:如果没写Object中的tostring方法,直接输出对象名会默认object中的string方法直接输出地址值

如果重写了object中的tostring方法,在输出地址值,重写没有意义,重写完tostring之后,应该返回对象内容

如果直接输出对象名不想输出地址值,就重写tostring方法

2.Object中的equals

概述:比较两个对象的地址值是否相等

Public boolean equals(object obj){

          Return(this==obj);

}

==针对于基本数据类型来说,比较的是值

==针对一引用数据类型来说比较的是地址值

注意:如果没有重写Object中的equals方法,那么就会调用object中的equals方法,比较对象的地址值

如果重写了object中的equals方法,那么就会调用重写后的equals方法,应该比较对象的内容

3.Object中的clone方法

作用:克隆一个属性一样的新对象

使用:需要被克隆的对象实现cloneable

   重写clone方法

import java.util.Objects;

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

    public Person() {
    }

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

/*
    public String  toString(){
        return name+","+age;
    }*/


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




    /*
    * 问题:obj直接调用name和age调用不了,因为object接收了person类型的对象属于多态
    * 多态前提下不能直接调用子类特有的功能
    *
    * 解决问题:向下转型
    *
    * 问题2:如果传递的不是person类型就会出现类型转换异常
    *
    * 解决:先判断类型,如果是person类型在强转person
    *
    * 问题3:如果传递null就不用判断类型,直接给false
    *
    *问题4:如果传递自己呢?就不用判断非空了,直接给true
    * */

    /*public boolean  equals(Object obj){

        if (this==obj){
            return true;
        }
        if (obj==null){
            return false;
        }

        if (obj instanceof Person) {
            Person p = (Person) obj;
            return this.name.equals(p.name) && this.age == p.age;
        }
        return false;
    }*/


    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person person = (Person) o;
        return age == person.age &&
                Objects.equals(name, person.name);
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
import java.util.ArrayList;

public class Test01 {
    public static void main(String[] args) {
        Person p1 = new Person("名",18);
        System.out.println(p1);
        System.out.println(p1.toString());

        System.out.println("===============");


        ArrayList<Object> list = new ArrayList<>();
        list.add("张三");
        list.add("张");
        list.add("三");
        System.out.println(list);
        System.out.println(list.toString());
    }
}
import java.util.ArrayList;

public class Test02 {
    public static void main(String[] args) {
        Person p1 = new Person("名",18);
        Person p2 = new Person("怡",18);
        System.out.println(p1==p2);
        System.out.println(p1.equals(p2));


        ArrayList<Object> list = new ArrayList<>();
        System.out.println(p1.equals(list));


        System.out.println(p1.equals(null));


        System.out.println(p1.equals(p1));


        System.out.println("-=====");


        String s1=new String("abc");
        String s2=new String("abc");
        System.out.println(s1==s2);//比较地址值
        System.out.println(s1.equals(s2));//true比较内容

    }
}
public class Test03 {
    public static void main(String[] args) throws CloneNotSupportedException {
        Person p2 = new Person();
        Object o = p2.clone();
        Person p3=(Person)o;//克隆一个新对象


        System.out.println(p2==p3);//比较地址值
        System.out.println(p2.equals(p3));
    }
}

三、String基础知识

1.String介绍

概述:String类代表字符串

  Java程序中的所有字符串字面值(如“abc”)都作为此类的实例(对象)实现

  凡是带双引号的都是string对象

  String s=“abc”

  “abc”就是对象,string就是对象的数据类型,s就是对象名

字符串是常量,他们的值在创建之后不能更改

String s=“hello”

 S+=“world”会产生新对象

String对象是不可变的,所以可以共享

String s1=“abc”

String s2=“abc”

2.String的实现原理

在jdk8的时候:String就是一个被final修饰的char数组->private  final  char[] value;

字符串定义完以后,数组就创建好了,被final一修饰,数组的地址值直接定死

3.String的创建

String()->利用String的无参构造创建String对象

String(String orginal)->根据字符串创建string对象

String(char[] value)->根据char数组创建String对象

String(byte[] bytes)->通过使用平台的默认字符集解码指定的byte数组构造一个新的String

                    平台:操作系统

                     操作系统默认字符集:GBK(一个中文占2个字节)

                     UTF-8:一个中文占3个字节,而且中文对应的字节一般都是负数

                    

              代码在idea中写的,idea启动的时候,对自动加一个启动参数,此时启动参数为UTF-8

简化形式:

String 变量名=””

String(char[] value,int offset,int count)->将char数组的一部分转成String对象

        Value:要将String的char数组

        Offset:从数组的哪个索引开始转

        Count:转多少个

String(byte[] bytes,int offset,int length)->将byte数组的一部分转换成String对象

        Bytes:要转string的byte数组

        Offset:从数组的那个索引开始转

        Length:转多少个

public class Demo03String {
    public static void main(String[] args) {
       /* String(char[] value,int offset,int count)->将char数组的一部分转成String对象
        Value:要将String的char数组
        Offset:从数组的哪个索引开始转
        Count:转多少个*/

       char[] chars={'a','b','c','d','e','f'};
        String s1 = new String(chars,1,3);
        System.out.println(s1);


       /* String(byte[] bytes,int offset,int length)->将byte数组的一部分转换成String对象
        Bytes:要转string的byte数组
        Offset:从数组的那个索引开始转
        Length:转多少个*/

       byte[] bytes={97,98,99,100,101};
       String s2=new String(bytes,0,2);
        System.out.println(s2);

    }
}

4.笔试题

问:string s=new String(“abc”)共有几个对象?2个

一个new本身    一个是“abc”

问2:String s=newString(“abc”)共创建了几个对象?1个或2个

就看abc有没有提前创建出来了

public class Demo04String {
    public static void main(String[] args) {
        String s1="abc";
        String s2="abc";
        String s3=new String("abc");
        System.out.println(s1==s2);//true
        System.out.println(s1==s3);//false
        System.out.println(s2==s3);//false


    }
}
  1. 字符串拼接,如果等号右边是字符串字面值拼接,不会产生新对象
  2. 字符串拼接,如果等号右边有变量参数拼接,会产生新字符串对象
public class Demo05String {
    public static void main(String[] args) {
        String s1="hello";
        String s2="world";
        String s3="helloworld";
        String s4="hello"+"world";
        String s5=s1+"world";
        String s6=s1+s2;

        System.out.println(s3==s4);
        System.out.println(s3==s5);
        System.out.println(s3==s6);

    }
}

5.String常用方法

Boolean equals(String s)->比较字符串内容

Boolean  equalsIgnoreCase(String  s)->比较字符串内容,忽略大小写

public class Demo01String {
    public static void main(String[] args) {
        String s1="abc";
        String s2=new String("abc");
        System.out.println(s1==s2);//比较地址值

        String s3="Abc";


        System.out.println(s1.equals(s2));


        System.out.println(s1.equalsIgnoreCase(s3));
        

    }
}

已知用户名和密码,请用程序实现模拟用户登录,总共三次机会,登陆成功与否,给出相应提示

步骤:

  1. 先定义两个字符串,注册过的密码和用户名
  2. 创建Scanner对象,键盘录入
  3. 比较如果一样就登陆成功否则失败
import java.util.Scanner;

public class Demo02String {
    public static void main(String[] args) {
        String username="root";
        String password="123";

        Scanner sc=new Scanner(System.in);
        for (int i = 0; i < 3; i++) {
            System.out.println("请您输入用户名:");
            String name=sc.next();
            System.out.println("请您输入密码:");
            String pwd=sc.next();
            if (name.equals(username)&&pwd.equals(password)){
                System.out.println("登陆成功");
                break;
            }else {
                if (i==2){
                    System.out.println("账号冻结!");
                }else {
                    System.out.println("登陆失败!");
                }
            }
        }


    }
}
import java.util.Objects;

public class Demo03String {
    public static void main(String[] args) {
        String s="abc";
        String s1=null;
        method(s);
        String s2="abc";
        String s3="abc";
        method1(s2,s3);

    }

    /*
    * 工具类objects
    * 方法:判断两个对象是否相等->自带防空指针作用
    * public static  boolean equals(object a,object b){
    *
    * return(a==b)||(a!=null&&a.equals(b));
    * }
    *
    * */
    private static void method1(String s2, String s3) {

        if (Objects.equals(s2,s3)){
            System.out.println("是abc");
        }else {
            System.out.println("不是abc");
        }
    }


    //如果传递过来是null就是空指针
    //解决不要让一个字符串变量去点,用确定的字符串组点,可以防空

    private static void method(String s) {
        /*if (s.equals("abc")){
            System.out.println("是abc");
        }else {
            System.out.println("不是abc");
        }*/



        if ("abc".equals(s)){
            System.out.println("是abc");
        }else {
            System.out.println("不是abc");
        }
    }
}

6.获取功能

Int length()->获取字符串长度

String concat(String s)->字符串拼接,返回新串

Char  charAt(int index)->根据索引获取对应的字符

Int indexof(string s)->获取指定字符串在大字符串中第一次出现的索引位置

String  subString(int  beginIndex)->截取字符串,从指定索引开始截取到最后,返回新串

String  subString(int beginIndex,int endIndex)->截取字符串,从beginIndex开始到endIndex结束含头不含尾,返回新串

public class Demo04String {
    public static void main(String[] args) {

        String s1="adaddjhz";
        System.out.println(s1.length());

        System.out.println(s1.concat("haha"));

        System.out.println(s1.charAt(0));

        System.out.println(s1.indexOf("a"));

        System.out.println(s1.substring(3));

        System.out.println(s1.substring(3,5));
    }
}

7.遍历字符串

public class Demo05String {
    public static void main(String[] args) {

        String s="anxhhx";
        for (int i = 0; i < s.length(); i++) {
            System.out.println(s.charAt(i));
        }
    }
}

8.转换功能

Char[] tocharArray()->将字符串转换成char数组

Byte[] getBytes()->将字符串转换成byte数组

String  replace(charSequence c1,charSequence c2)->替换字符

                           charSequence->String接口

Byte[] getbytes(String  charsetName)->按照指定的编码将字符串转成byte数组

import java.io.UnsupportedEncodingException;

public class Demo06String {
    public static void main(String[] args) throws UnsupportedEncodingException {
        String s="abcgeee";

        char[] chars = s.toCharArray();
        for (int i = 0; i < chars.length; i++) {
            System.out.println(chars[i]);
        }
        System.out.println("=====");

        byte[]bytes=s.getBytes();
        for (int i = 0; i < bytes.length; i++) {
            System.out.println(bytes[i]);
        }


        System.out.println(s.replace("a","r"));

        byte[] bytes1 = "你好".getBytes("utf-8");
        for (int i = 0; i < bytes1.length; i++) {
            System.out.println(bytes1[i]);
        }

    }
}

9.练习

键盘录入字符串统计该字符中大写小写字符串字符,小写字母字符,数字字符出现的次数(不考虑其他字符)

  1. 创建Scanner对象
  2. 定义三个变量用来统计
  3. 调用next录入,遍历,将每个字符拿出来
  4. 统计大小写
  1. Z:65-90

比如B->66在这之间就是大写

  1. z:97-122

统计数字

0-9->48-57

  1. 打印结果

import java.util.Scanner;

public class Demo07String {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);
        int big=0;
        int small=0;
        int number=0;
        String data=sc.next();
        char[] chars = data.toCharArray();
        for (int i = 0; i < chars.length; i++) {
           char num= chars[i];
        if (num>='A'&&num<='Z'){
            big++;
        }
        if (num>='a'&&num<='z'){
            small++;
        }
        if (num>='0'&&num<='9'){
            number++;

        }

        }

        System.out.println("大写有"+big+"个");
        System.out.println("小写有"+small+"个");
        System.out.println("数字有"+number+"个");

    }
}

10.分割功能

String[] split(String  regex)->按照指定的规则分割字符串

注意:regex写的是正则表达书,在正则表达式中表示任意一个字符

public class Demo08String {
    public static void main(String[] args) {
        String s="abc,txt";
        String[] split=s.split(",");
        for (int i = 0; i < split.length; i++) {
            System.out.println(split[i]);
        }


        System.out.println("==============");
        String s2="hahahah.hehe";
        String[] split1=s2.split("\\.");
        for (int i = 0; i < split1.length; i++) {
            System.out.println(split1[i]);
        }
    }
}

11.其他方法

Boolean  contains(String s)->判断老串中是否包含指定的串

Boolean  endswith(String s)->判断老串是否以指定的串结尾

Boolean  startswith(String s)->判断老串是否以指定的串开头

String  touppercase()->将字母转换成大写

String  toLowerCase()->将自足转换成小写

String  trim()->去掉字符串两端空格

public class Demo09String {
    public static void main(String[] args) {

        String s="abcggdd";

        System.out.println(s.contains("a"));

        System.out.println(s.endsWith("d"));

        System.out.println(s.startsWith("a"));

        System.out.println("Adjjd".toLowerCase());
        System.out.println("axjxj".toUpperCase());


        System.out.println("===========");
        System.out.println("aadd   dddd  aawww  aad".replace(" ",""));
    }
}

四、StringBuilder类

概述:是一个可变的字符序列,此类提供了一个StringBuffer兼容的一套API,但是不保证同步(线程不安全,效率比较高)

作用:拼接字符串

问题:直接用+去拼接不就行为什么用StringBuilder去拼接

原因:String每拼接一次,就会产生新的字符串对象,就会在堆内存中开辟新的空间,拼接次数多了,效率比较低

StringBuilder,底层自带一个缓冲区(没有被final修饰的byte数组)拼接字符串之后都会在此缓冲区中保存,在拼接的过程中不会随意产生新对象,节省内存

特点:

底层自带缓冲区,此缓冲区是没有final修饰的byte数组,默认长度为16

如果超出了数组长度,数组会自动扩容(创建一个新长度的数组,将老数组的元素复制到新数组中然后将新数组的地址重新赋值给老数组)

默认每次扩容老数组的2倍+2(如果第一次性添加的数据超出了默认的扩容数组长度,比如存了36个字符,超出了第一次扩容的34,就按实际数据个数为准就是36扩容)

StringBuilder的使用

构造:

StringBuilder()

StringBuilder(String str)

public class Demo01StringBulider {
    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        System.out.println(sb);


        StringBuilder sb1 = new StringBuilder("abc");
        System.out.println(sb1);

    }
}

常用方法

StringBuilder  append(任意数据类型)->字符串拼接,返回的是StringBuilder自己

StringBuilder reverse()->字符串翻转,返回的时StringBuilder自己

String  toString()->将StringBuilder转成String->用StringBuilder拼接字符串时为了效率,为了不占内存,那么拼完之后可能会对拼接好的字符串进行处理,就需要调用String中的方法,所以需要将StringBuilder转成String

public class Demo02StringBuilder {
    public static void main(String[] args) {
        StringBuilder sb=new StringBuilder();
        StringBuilder sb1=sb.append("迷宫");
        System.out.println(sb1);
        System.out.println(sb);
        System.out.println(sb==sb1);
        System.out.println("=============");


        sb.append("名").append("怡").append("杨");
        System.out.println(sb);


        sb.reverse();
        System.out.println(sb);


        String s = sb.toString();
        System.out.println(s);


    }
}

练习

练习键盘输入字符串,判断是否为回文字符

public class Demo03StringBuilder {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        String data = sc.next();

        StringBuilder sb = new StringBuilder(data);
        sb.reverse();
        //将stringbuilder转换成string
        String s=sb.toString();
        if (data.equals(s)){
            System.out.println("是回文内容");
        }else {
            System.out.println("不是回文内容");
        }

    }
}

定义一个数组,以[元素1,元素2,元素3]的形式输出,用StringBuilder拼接

public class Demo04 {
        public static void main(String[] args) {
            /*
             * 拼接字符串
             * 需求:定义一个方法,把int数组中的数据按照指定的格式拼接成一个字符串返回。调用该方法,并在控制台输出结果
             * 举例:数组为int[] arr = {1,2,3};
             * 执行方法后的输出结果为:[1,2,3]
             * */

            //1.定义数组
            int[] arr = {1,2,3};

            //2.调用方法把数组变成字符串
            String str = arrToString(arr);
            System.out.println(str);
        }
        public static String arrToString(int[] arr){
            StringBuilder sb = new StringBuilder();
            sb.append("[");
            for (int i = 0; i < arr.length; i++) {
                if (i == arr.length - 1){
                    sb.append(arr[i]);
                }else{
                    sb.append(arr[i]).append(",");
                }
            }
            sb.append("]");
            return sb.toString();
        }

    }

  • 21
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值