Java SE 学习之继承,抽象,代码块,接口,多态,内部类

这篇博客深入探讨了Java SE中的核心概念,包括类的继承、抽象类与抽象方法、构造代码块、接口的使用以及多态的实现。讲解了继承的优缺点、方法重写、模板设计模式,同时介绍了final关键字在防止方法和类被重写中的应用。此外,还详细阐述了代码块的作用,如局部、构造和静态代码块,以及内部类的分类和访问特点。最后,文章讨论了接口的定义、实现和多态带来的灵活性,以及匿名内部类和Lambda表达式的应用场景和差异。

Java SE 学习之继承,抽象,代码块,接口,多态,内部类

1知识点

1.1继承

1.1.1引入
  • 根据上面的案例,老师类和学生类有相同的属性,相同的方法放,具有共性,向上抽取,关键字extend,特点 :子类可以直接使用父类中非私有的成员
1.1.2优点
  • 提高代码的复用性,维护性,并且让类与类产生了联系,是多态的前提
1.1.3缺点
  • 继承是侵入性的,降低代码的灵活性:子类必须拥有父类非私有的属性和方法
    增强了代码的耦合性
1.1.4使用场景
  • 1 有共性 2:产生了is a 的关系 :例子 我是帅哥 ,你也是帅哥 ,提取帅哥为父类,
1.1.5继承特点
  • 只支持单继承和多层继承(爷祖)
1.1.6继承的成员变量访问特点
  • 就近原则
public class one {
    public static void main(String[] args) {
        zi zi = new zi();
        zi.mothed1();
        zi.mothed2();
        zi.mothed3();
    }
}
//fu类
class fu {
    int a = 10;
}
//子类
class zi extends fu {
    int a = 20;
    public void mothed1() {
        System.out.println(a+"就近原则");
    }
    public void mothed2() {
        int a =30;
        System.out.println(this.a+"this关键字返回本类成员变量");
        System.out.println(a+"局部变量");
    }
    public void mothed3() {
        System.out.println(super.a+"super返回父类");
    }
}
1.1.6.1 this and super
  • this&super关键字:
    • this:代表本类对象的引用
    • super:代表父类存储空间的标识(可以理解为父类对象引用)
  • this和super的使用分别
    • 成员变量:
      • this.成员变量 - 访问本类成员变量
      • super.成员变量 - 访问父类成员变量
    • 成员方法:
      • this.成员方法 - 访问本类成员方法
      • super.成员方法 - 访问父类成员方法
  • 构造方法:
    • this(…) - 访问本类构造方法
    • super(…) - 访问父类构造方法
1.1.7继承的成员方法访问特点
  • 先去子类找 ,没有再去父类找
public class Two {
    public static void main(String[] args) {
        zi2 zi = new zi2();
        zi.mothed2();
        zi.mothed3();

    }
}

//fu类
class fu2 {
    //fu类方法
    public void mothed() {
        System.out.println("fu2类方法");
    }
}

//子类
class zi2 extends fu2 {

    //子类与父类同名方法
    public void mothed() {
        System.out.println("zi2类方法");
    }

//子类中的方法通过super调用父类同名方法
    public void mothed2() {
        super.mothed();
    }
// 默认有个this.  -- 调用子类方法
    public void mothed3() {
        mothed();
    }
}
1.1.8方法的重写
  • 1、方法重写概念
    • 子类出现了和父类中一模一样的方法声明(方法名一样,参数列表也必须一样)
  • 2、方法重写的应用场景
    • 当子类需要父类的功能,而功能主体子类有自己特有内容时,可以重写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容
//需求 升级手机功能
public class Three {
    public static void main(String[] args) {
        ipear2  i =new ipear2();
        i.smallBlack();

    }
}

//ipear1类-----一代
class ipear1 {
    //打电话
    public void call(String name) {
        System.out.println("给" + name + "打电话");
    }
//只会说英文
    public void smallBlack() {
        System.out.println("speak English");
    }
}

//二代
class ipear2 extends ipear1 {
    //进行重写
    public void smallBlack() {
        //调用父类的方法
        super.smallBlack();
        //添加自己的方法
        System.out.println("speak Chinese");
    }

}
1.1.8.1方法重写的注意事项
  1. 私有方法不能被重写(父类私有成员子类是不能继承的)
  2. 子类方法访问权限不能低于父类的访问权限
  3. 静态方法不能被重写,如果子类也有相同的方法,并不是重写的父类的方法,子类只是将父类的方法隐藏起来了
1.1.9权限修饰符

在这里插入图片描述

1.1.10继承中构造方法的访问特点(idea自动生成)

在这里插入图片描述
注意:子类中所有的构造方法默认都会访问父类中无参的构造方法

​ 子类会继承父类中的数据,可能还会使用父类的数据。所以,子类初始化之前,一定要先完成父类数据的初始化,原因在于,每一个子类构造方法的第一条语句默认都是:super()

问题:如果父类中没有无参构造方法,只有带参构造方法,该怎么办呢?

1. 通过使用super关键字去显示的调用父类的带参构造方法
2. 子类通过this去调用本类的其他构造方法,本类其他构造方法再通过super去手动调用父类的带参的构造方法

注意: this(…)super(…) 必须放在构造方法的第一行有效语句,并且二者不能共存

注意:super 会在堆内存开辟自己的存储空间来存放父类成员

1.2抽象类

1.2.1概述
  • 抽象方法:父类中的某些方法不能明确具体实现方式,就需要定义成抽象方法,子类要重写父类中的抽象方法(完成方法体内容的编写)
  • 抽象类:一个类中存在抽象方法,则该类必须声明为抽象类
  • 如何定义抽象类和抽象方法
    abstract关键字
//抽象类的定义
public abstract class 类名 {}
//抽象方法的定义
public abstract void eat();
1.2.2抽象类的注意事项
  • 抽象类中可以没有抽象方法,有抽象方法的类一定是抽象类

  • 抽象类不能实例化(实例化就是创建对象)

  • 抽象类可以有构造方法

    • 但是无法创建对象
    • 构造方法主要用于初始化自己成员变量,以供子类使用
  • 抽象类的子类

    • 要么重写父类所有的抽象方法(推荐)
    • 要么自己也是一个抽象类(工作中可能会用到)
1.2.3模板设计模式
  • 把抽象类整体就可以看做成一个模板,模板中不能决定的东西定义成抽象方法

让使用模板的类(继承模板抽象类的子类)去重写抽象方法实现需求,下面是一个写作文的模板

package Day02;

public abstract class Composition {
//模板
    public void write() {
        System.out.println("《我的dady》");
        body();
        System.out.println("哈哈哈");
    }
//抽象主题方法
    public abstract void body();

}


//创建子类重写抽象方法
class Tom extends Composition {

    @Override
    public void body() {
        System.out.println("俺不会写作文");
    }

}
//创建子类对象,调用父类方法
class test {
    public static void main(String[] args) {

        Tom tom=new Tom();
        tom.write();

    }
}
1.2.4 finall关键字
  • 根据模板设计思想,模板的骨架最好不被重写,
  • finall-最终
  • 被其修饰的方法无法被子类重写
  • 被其修饰的类不能拥有子类
  • 被其修饰的变量不能再被赋值:基本数据类型–值 ;引用数据类型:地址值
  • 如果要修饰成员变量,要注意初始化时机:
    1.在定义final修饰的变量(常量)的时候, 直接赋值(推荐)2. 在构造方法结束之前(白话:就是在构造方法中), 完成赋值
  package com.itheima.mfinal;
  
  public class TestFinal {
      /*
          final修饰变量:
  
              基本数据类型变量: 其值不能被更改
  
              引用数据类型变量: 地址值不能被更改, 但是可以修改对象的属性值
       */
      public static void main(String[] args) {
          // 常量的命名规范: 如果是一个单词, 所有字母大写, 如果是多个单词, 所有字母大写, 但是中间需要使用_分隔
          final int A = 10;//A变量的值是不能被修改
          // a = 10;
          final int MAX = 10;
          final int MAX_VALUE = 20;
  
          final Student stu = new Student();
          stu.setName("张三");
          stu.setName("李四");
  
          // stu = new Student();
      }
  }
  
  class Student {
      // final修饰成员变量 初始化时机
      // 1. 在创建的时候, 直接给值
      // 2. 在构造方法结束之前, 完成赋值
      final int a = 10;
  
      private String name;
  
      public String getName() {
          return name;
      }
  
      public void setName(String name) {
          this.name = name;
      }
  }

1.3代码块

  • 引出:系统调试不方便
  • 目的:每当程序启动完毕以后,系统就初始化一部分学生数据
  • 分类:局部代码块,构造代码块,静态代码块
1.3.1 局部代码块
  • 位置:方法中定义
  • 作用:限定变量的生命周期,及早释放,提高内存利用率
  • 示例代码
 public class Test {
      /*
          局部代码块
              位置:方法中定义
              作用:限定变量的生命周期,及早释放,提高内存利用率
       */
      public static void main(String[] args) {
          {
              int a = 10;
              System.out.println(a);
          }

         // System.out.println(a);
      }
  }
1.3.2 构造代码块
  • 位置:类中方法外定义
  • 特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
  • 作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
  • 示例代码
  public class Test {
      /*
          构造代码块:
              位置:类中方法外定义
              特点:每次构造方法执行的时,都会执行该代码块中的代码,并且在构造方法执行前执行
              作用:将多个构造方法中相同的代码,抽取到构造代码块中,提高代码的复用性
       */
      public static void main(String[] args) {
          Student stu1 = new Student();
          Student stu2 = new Student(10);
      }
  }
  
  class Student {
  
      {
          System.out.println("好好学习");
      }
  
      public Student(){
          System.out.println("空参数构造方法");
      }
  
      public Student(int a){
          System.out.println("带参数构造方法...........");
      }
  }
1.3.3 静态代码块
  • 位置:类中方法外定义
  • 特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
  • 作用:在类加载的时候做一些数据初始化的操作
  • 示例代码
  public class Test {
      /*
          静态代码块:
              位置:类中方法外定义
              特点:需要通过static关键字修饰,随着类的加载而加载,并且只执行一次
              作用:在类加载的时候做一些数据初始化的操作
       */
      public static void main(String[] args) {
          Person p1 = new Person();
          Person p2 = new Person(10);
      }
  }
  
  class Person {
      static {
          System.out.println("我是静态代码块, 我执行了");
      }
  
      public Person(){
          System.out.println("我是Person类的空参数构造方法");
      }
  
      public Person(int a){
          System.out.println("我是Person类的带...........参数构造方法");
      }
  }

1.4接口

1.4.1接口的引出
  • 根据2.2.4.5的改进,出现了一个全是抽象方法的类,
  • 接口就是一种公共的规范标准,只要符合规范标准,大家都可以通用。
1.4.2接口的意义
  1. 用来定义规范
  2. 用来做功能的拓展
1.4.3接口的特点
  • 接口用关键字interface修饰
		  public interface 接口名 {} 
  • 类实现接口用implements表示
  public class 类名 implements 接口名 {}

接口不能实例化,我们可以创建接口的实现类对象使用

  • 接口的子类
    ​ 要么重写接口中的所有抽象方法
    ​ 要么子类也是抽象类
1.4.4接口中成员特点
  • 成员变量
    ​ 只能是常量
    ​ 默认修饰符:public static final
  • 构造方法
    ​ 没有,因为接口主要是扩展功能的,而没有具体存在
  • 成员方法
    ​ 只能是抽象方法
    ​ 默认修饰符:public abstract
    ​ 关于接口中的方法,JDK8和JDK9中有一些新特性
    • JDK8:用default可以定义非抽象方法,用static定义静态方法,静态方法通过类名 . 的方式调用,注意default和static只能有一个
    • JDK9:允许接口中定义private私有的方法,(private和static会吗,默认带上default,反正就是不用写default)
1.4.4类与接口的关系
  • 类与类的关系
    ​ 继承关系,只能单继承,但是可以多层继承
  • 类与接口的关系
    ​ 实现关系,可以单实现,也可以多实现,还可以在继承一个类的同时实现多个接口(亲爹更亲,类和接口有一样的方法,执行类中的方法)
  • 接口与接口的关系
    ​ 继承关系,可以单继承,也可以多继承(如果继承的接口有重名且方法体不一样的方法,需要重写该方法)

1.5多态

1.5.1多态的概念

​ 同一个对象,在不同时刻表现出来的不同形态

1.5.2多态的前提
  • 要有继承或实现关系
  • 要有方法的重写
  • 要有父类引用指向子类对象
1.5.3多态中成员访问的特点
  • 成员访问特点

    • 成员变量

      ​ 编译看父类,运行看父类

    • 成员方法

      ​ 编译看父类,运行看子类,父类中要有方法,不然会编译失败,运行则运行子类中重写的方法

    • 代码展示

class Fu {
    int num = 10;

    public void method(){
        System.out.println("Fu.. method");
    }
}

class Zi extends Fu {
    int num = 20;

    public void method(){
        System.out.println("Zi.. method");
    }
}

public class Test2Polymorpic {
    /*
         多态的成员访问特点:

                成员变量: 编译看左边 (父类), 运行看左边 (父类)

                成员方法: 编译看左边 (父类), 运行看右边 (子类)
     */
    public static void main(String[] args) {
        Fu f = new Zi();
        System.out.println(f.num);
        f.method();
    }
}
1.5.4多态的好处与弊端
  • 好处
    ​ 提高程序的扩展性。定义方法时候,使用父类型作为参数,在使用的时候,使用具体的子类型参与操作
  • 弊端
    ​ 不能使用子类的特有成员,因为要先编译,如果父类中没有调用的方法,编译会失败
1.5.5多态的转型及其风险
  • 向上转型

    ​ 父类引用指向子类对象就是向上转型

  • 向下转型

    ​ 格式:子类型 对象名 = (子类型)父类引用;

1.5.5多态的风险(解决向下转型的风险)

如果被转的引用类型变量,对应的实际类型和目标类型不是同一种类型,那么在转换的时候就会出现ClassCastException

  • 解决方案
    • 关键字
      instanceof
    • 使用格式
      变量名 instanceof 类型
      通俗的理解:判断关键字左边的变量,是否是右边的类型,返回boolean类型结果
//父类 动物
abstract class Animal {
    public abstract void eat();
}
//狗继承了动物类 ,除了吃还能看家
class Dog extends Animal {
    public void eat() {
        System.out.println("狗吃肉");
    }

    public void watchHome(){
        System.out.println("看家");
    }
}
// 猫也继承了动物
class Cat extends Animal {
    public void eat() {
        System.out.println("猫吃鱼");
    }
}
//测试类
public class Test4Polymorpic {
    public static void main(String[] args) {
    //创建了一条狗,调用方法
        useAnimal(new Dog());
    //创建了一只猫,调用方法
        useAnimal(new Cat());
    }

    public static void useAnimal(Animal a){  
    // Animal a = new Dog();
    // Animal a = new Cat();
    
    //这个方法可以调用父类动物所有子类对象
    
        a.eat();
        //a.watchHome();

//        Dog dog = (Dog) a;
//        dog.watchHome();  // ClassCastException  类型转换异常
      
        // 判断a变量记录的类型, 是否是Dog
        if(a instanceof Dog){
            Dog dog = (Dog) a;
            dog.watchHome();
        }
    }
}

1.6内部类

1.6.1 概念

  • 在一个类中定义一个类。举例:在一个类A的内部定义一个类B,类B就被称为内部类
  • 成员内部类:可以被private和state修饰
  • 局部内部类
  • 匿名内部类

1.6.2成员内部类的访问特点

  • 内部类可以直接访问外部类的成员,包括私有
  • 外部类要访问内部类的成员,必须创建对象
  • 以下是成员内部类的 演示代码
//外部类
public class Four {

    public static void main(String[] args) {
        Outer.Inner i = new Outer().new Inner();
        //外部类想要访问内部类 ,必须要创建内部类对象
        System.out.println(i.num);
        i.show();

    }
}

//外部类
class Outer {
    //外部类私有的值
    private int a = 20;
    //成员内部类
    public class Inner {
        int num = 10;
        //内部类里面的方法
        public void show() {
            //可以直接访问,内部类访问外部类
            System.out.println(a);
            System.out.println("hh");
        }
    }
}
  • 成员内部类被pivate修饰 ,需要在创建一下方法,方法中调用私有的方法
public class Five {

    public static void main(String[] args) {
        //创建外部类对象
        Outer1 i = new Outer1();
        //调用方法
        i.mothed();
    }
}

//外部类
class Outer1 {
    //外部类私有的值
    private int a = 20;

    //私有成员内部类
    private class Inner {
        int num = 10;
        //内部类里面的方法
        public void show() {
            //可以直接访问,内部类访问外部类
            System.out.println(a);
            System.out.println("hh");

            System.out.println("内部类私有方法");
        }
    }
    //创建方法调用私有内部类
    public void mothed() {
        Inner i = new Inner();
        i.show();
    }
}
  • 成员内部类被state修饰,调用正常方法和state方法
  • 访问格式为:Outer2.Inner i = new Outer2.Inner();少一个括号和new
public class Six {

    public static void main(String[] args) {
        //创建静态类对象
        Outer2.Inner i = new Outer2.Inner();
        //调用静态类非state方法
        i.show();
        //调用静态类中静态的方法
        Outer2.Inner.mothed();
    }
}

//外部类
class Outer2 {
    //私有成员内部类
    static class Inner {
        //内部类里面的方法
        public void show() {
            System.out.println("我是静态内部类");
        }
        public static void mothed() {
            System.out.println("我是静态内部类中静态的方法");
        }
    }
}

1.6.3局部内部类

  • 定义:在方法中定义的类,外界无法直接使用,需要在方法内部创建对象并使用
  • 可以访问外部类中的成员,也可以访内部类中的局部变量
package Day3_31;
public class Seven {
    public static void main(String[] args) {
        //创建外部类对象
        Outer3 outer3=new Outer3();
        //调用外部类的方法
        outer3.mothed();

    }
}
//外部类
class Outer3 {
    //成员变量
    int a  =10 ;
    //创建方法
    public void mothed() {
        //在方法中有个类 ,称之为局部内部类
        class Inner {
            //局部变量
            int b  =20 ;
            //类中存在方法
            public void show() {
                System.out.println("a = " + a);
                System.out.println("b = " + b);
                System.out.println("我是局部内部类中的方法");
            }
        }
        //在外部类中创建具备内部类的对象
        Inner I = new Inner();
        //调用方法
        I.show();
    }
}

1.6.4匿名内部类

  • 本质上是个特殊的局部内部类(定义在方法内部)
  • 前提:需要存在一个接口或者类
  • 目的:把继承|实现,方法重写,创建对象放在了一部进行
    一般接口实现过程:1. 创建实现类2. 重写接口的方法3. 创建实现类对象4. 调用实现类对象的方法
  • 匿名内部类:一部完成, 若接口存在多个方法,使用父类接口来接收,来调用方法,父类引用指向子类对象 :多态
package TextInter;

public class Eight {
    public static void main(String[] args) {
//        1. 创建实现类
//        2. 重写接口的方法
//        3. 创建实现类对象
//        4. 调用实现类对象的方法

        //创建对象
        InterImpl ii = new InterImpl();
        //调用方法
        ii.show();


        new Inter() {
            @Override
            public void show() {
                System.out.println("我是匿名内部类的show方法");
            }
        }.show();

        //一个接口存在多个方法,使用父类接口来接收,来调用方法
        //父类引用指向子类对象 :多态
        Inter2 inter2 = new Inter2() {
            @Override
            public void show1() {
                System.out.println("我是show1");
            }
            @Override
            public void show2() {
                System.out.println("我是show2");
            }
        };
        //调用方法
        inter2.show1();
        inter2.show2();
    }
}

//创造一个接口
interface Inter {
    void show();
}

interface Inter2 {
    void show1();

    void show2();
}

//接口的实现类
class InterImpl implements Inter {

    @Override
    public void show() {
        System.out.println("我是接口show方法的重写");
    }
}
1.6.4.1匿名内部类的使用场景
  • 当方法的形式参数是接口或者是抽象类时,可以将匿名内部类作为实际参数进行传递
package TextInter2;


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


        goSwiming(
                //匿名内部类创建接口对象
                new Swiming() {
                    @Override
                    //重写方法
                    public void swim() {
                        System.out.println("我们去游泳把");
                    }
                });
    }

    //创造一个方法调用接口
    //方法体是调用里面的show方法
    public static void goSwiming(Swiming swiming) {
        swiming.swim();
    }
}

//创造一个游泳接口
interface Swiming {
    void swim();
}

1.6.5 Lambda表达式

  • 对匿名内部类的优化,但两者本质上是有区别的
  • 函数式思想,怎么做是重点
        goSwiming(
                //匿名内部类创建接口对象
                //lambda表达式
                () -> System.out.println("我们去游泳把"));
    }

  • 标准格式:(形式参数)->{方法体}
  • 使用前提:有一个接口,并且有且只有一个抽象方法
    无参数无返回值
package Lamble01;


public class Ten {
    public static void main(String[] args) {
        //匿名内部类方法
        useShowHander(new ShowHander() {
            @Override
            public void show() {
                System.out.println("重写方法");
            }
        });

        //lambda表达式的方法
        useShowHander(() -> {
            System.out.println("重写方法");
        });
    }

    //需要调用接口的方法
    public static void useShowHander(ShowHander showHander) {
        showHander.show();
    }

}

//创建接口
interface ShowHander {
    void show();
}

有参数无返回值

package Lambda02;


public class Eleven {
    public static void main(String[] args) {
        //匿名内部类方法
        useShowHander(new ShowHander() {
            @Override
            public void show(String msg) {
                System.out.println("我是匿名内部类" + msg);
            }
        });
        //lambda表达式的方法
        useShowHander((String msg) -> {
            System.out.println("我是lambda表达式" + msg);
        });
    }

    //需要调用接口的方法
    public static void useShowHander(ShowHander showHander) {
        showHander.show("手动给出");
    }

}

//创建接口
interface ShowHander {
    void show(String msg);
}
  • 无参数有返回值:需要用return语句将结果返回
  • 下面是一个产生随机数的问题
package Lambda03;


import java.util.Random;

public class Twelven {
    public static void main(String[] args) {
        //匿名内部类方法
        useRanNumHandler(new RanNumHandler() {
            @Override
            public int getNumber() {
                //产生随机数
                Random random = new Random();
                return random.nextInt(10) + 1;
            }
        });
        //lambda方法
        useRanNumHandler(() -> {
            Random random = new Random();
            //返回
            return random.nextInt(10) + 1;
        });
    }

    //需要调用接口的方法
    public static void useRanNumHandler(RanNumHandler ranNumHandler) {
        int number = ranNumHandler.getNumber();
        System.out.println(number);
    }
}
//创建接口

interface RanNumHandler {
    int getNumber();
}

带参数带返回值

package Lambda04;


public class DMOO13 {
    public static void main(String[] args) {
        useCalculatuor(new Calculatuor() {
            @Override
            public int calc(int a, int b) {
                return a + b;
            }
        });

        useCalculatuor((int a, int b) -> {
            return a + b;
        });


    }

    public static void useCalculatuor(Calculatuor calculatuor) {
        int calc = calculatuor.calc(10, 20);
        System.out.println(calc);
    }
}


interface Calculatuor {
    int calc(int a, int b);
}
1.6.5.1 Lambda表达式的省略格式
  • 参数类型可以省略,但有多个参数的情况下,不能只省略一个
  • 如果参数有且仅有一个,括号可以省略
  • 如果代码块的语句只有一个,可以省略 大括号,分好和return

1.6.6 两者的区别

  • 匿名内部类:可以是接口,也可以是抽象类,还可以是具体类
    • 原理 编译之后产生一个单独的。class文件
  • lambda表达式:只能是接口,并且接口中只有一个抽象方法
    • 字节码文件动态生成,不会产生到本地文件当中
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Gold 大龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值