Java:16-多态的概念和语法

多态的概念和语法

多态的概念------------------------------
封装的基础上衍生出来继承,基于继承之上衍生出来的特性就叫做多态
多态主要指同一种事物表现出来的多种形态
饮料:可乐,雪碧,红牛,脉动,…
宠物:猫,狗,鸟,小强,鱼,…
人:学生,教师,工人,保安,…
图形:矩形,圆形,梯形,三角形,…
父类类型 引用变量名 = new 子类类型();
ctrl + r可以替换全部一样的单词
//如
Shape sr = new Rect();
sr.show();
编程实现Shape类的封装,特征有:横纵坐标,要求打印所有特征的方法
编程实现Rect类的封装并继承自Shape类,特征有:长度和宽度
编程实现ShapeRectTest类,在main方法中分别创建Shape和Rect类型对象并打印特征
package com.lagou.task09;

/**
 *
 */
public class Shape {
    private int x;
    private int y;

    public Shape() {
    }

    public Shape(int x, int y) {
        setX(x);
        setY(y);
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }
    public void show(){
        System.out.println("横坐标:" + getX() + ",纵坐标:" + getY());
    }
    //自定义静态方法
    public static void test(){
        System.out.println("Shape类中的静态方法");
    }
}

package com.lagou.task09;

/**
 *
 */
public class Rect extends Shape{
    private int len;
    private int wid;

    public Rect() {
    }

    public Rect(int x, int y, int len, int wid) {
        super(x, y);
        setLen(len);
        setWid(wid);
    }

    public int getLen() {
        return len;
    }

    public void setLen(int len) {
        if(len > 0) {
            this.len = len;
        }else{
            System.out.println("长度不合理哦");
        }
    }

    public int getWid() {
        return wid;
    }

    public void setWid(int wid) {
        if(wid > 0){
            this.wid = wid;
        }else{
            System.out.println("宽度不合理哦");
        }
    }

    @Override
    public void show() {
        super.show();
        System.out.println("长度是:" + getLen() + ",宽度是:" + getWid());
    }
    //自定义静态方法
    //@Override Error:历史原因,不是真正意义上的重写,因为静态代表自己,首先是自己,才说其他的要求,所以这里自然不会操作到
    public static void test(){
        System.out.println("---Rect类中的静态方法");
    }
}

package com.lagou.task09;

/**
 *
 */
public class Circle extends Shape{
    private int ir;

    public Circle() {
    }

    public Circle(int x, int y, int ir) {
        super(x, y);
        this.ir = ir;
    }

    public int getIr() {
        return ir;
    }

    public void setIr(int ir) {
        if(ir > 0) {
            this.ir = ir;
        }else{
            System.out.println("半径不合理哦");
        }
    }
    //ctrl + o重写快捷键
    @Override
    public void show() {
        super.show();
        System.out.println("半径值:" + getIr());
    }
}

package com.lagou.task09;

/**
 *
 */
public class ShapeRectTest {
    public static void main(String[] args) {
        //声明Shape类型的引用指向Shape类型的对象并打印特征
        Shape s1 = new Shape(1,2);
        //当Rect类中没有重写show()方法时,下面调用Shape类中的show()方法
        //当Rect类中重写show()方法时,下面调用Shape类中的show()方法
        s1.show(); // 1 2
        //使用ctrl+d复制当前行
        System.out.println("-------------------");
        System.out.println("-------------------");
        //声明Rect类型的引用指向Rect类型的对象并打印特征
        Rect r1 = new Rect(3,4,5,6);
        //当Rect类中没有重写show()方法时,下面调用Shape类中的show()方法
        //当Rect类中重写show()方法时,下面调用Rect类中的show()方法
        r1.show(); //3 4 5 6
        //使用alt+shift+上下方向键 可以移动代码
        System.out.println("-------------------");
        //声明Shape类型的引用指向Rect类型的对象并打印特征
        //相当于从Rect类型到shape类型的转换 也就是子类到父类的转换
        Shape sr = new Rect(7,8,9,10);
        //当Rect类中没有重写show()方法时,下面调用Shape类中的show()方法
        //当Rect类中重写show()方法时,下面的代码在编译阶段认为是调用Shape类的方法(简单来说,是在检查阶段,而非字节码时候,以后的异常会进行说明的)
        //在运行阶段调用Rect类中的show()方法,即只看对象的调用,而编译一般只会看当前
        sr.show(); //7 8 9 10
        System.out.println("-------------------");
        //测试Shape类型的引用能否直接调用父类和子类独有的方法呢
        int ia = sr.getX();
        System.out.println("获取到的横坐标是:" + ia); //7
        //sr.getLen(); error Shape类中找不到getLen方法,也就是还在shape类中查找,编译都没有过去,自然运行也不行,虽然最终可能运行是对的,编译可不是idea的检查,而是jdk自带的,只不过idea的检查会给出具体位置而已,但也只是一个提示,所以有时候我们认为idea检查是编译期也没有问题
        //调用静态方法
        sr.test(); //test是斜体 即他是静态的方法 提示不建议使用引用.的方式访问
        Shape.test(); // 推荐使用类名.的方式访问
        //对于父子类都有的静态方法来说,编译和运行阶段都调用父类的版本(这里针对类型为父的,后面也是)
        //即对于静态方法的调用只取决于变量类型,与指向什么的对象无关,即在调用方法时,是会先看方法区的,然后才是堆哦,这也是为什么编译期是优先的原因,如果在方法区里没有找到,那么自然不会操作对象,这也是为什么上面说明"Shape类中找不到getLen方法,也就是还在shape类中查找,编译都没有过去"的原因
        System.out.println("-------------------");
        //使用父类类型的引用调用子类独有方法的方式
        //相当于从Shape类型向Rect类型的转换,也就是父类到子类的转换 强制类型转换,既然转换了,那么自然找的就是相关的类信息,那么编译期可以通过了(基本是父类的,因为父到子,所以可以变化),子到父也行,只不过范围小了,即方法区只看自己的,然后看自己父的,而我直接到父,自然没有
        int ib =  ((Rect) sr).getLen();
        System.out.println("获取到的长度是:" + ib);
        //希望将Shape类型转换为String类型 强制类型转换
        //String str1 = (String)sr; Error 要求必须拥有父子类关系
        //希望将Shape类型转换为Circle类型,下面没有报错
        //Circle c1 = (Circle)sr; // ClassCastException 可能会有类型转换异常
        //编译ok,但运行阶段发生ClassCastException类型转换异常
        //因为运行阶段Shape会表示为Rect,即对于Circle来说编译不错,但运行时发生错误
        //而强转为Rect不会报错
        //在强制类型转换之前应该使用instanceof进行类型的判断
        //用来判断引用变量指向的对象是否为后面的数据类型
        //若是则为true,否则为false
        //判断sr指向堆区内存中的对象是否为Circle类型或者其子类类型
         //由于是单继承,那么若我指向的对象是你的类型,那么必然可以强转成你的,让你来指向,而强转成父类不用担心,因为我可以指向,那么父类自然也可以指向
       if(sr instanceof Circle){
           System.out.println("Circle是sr的数据类型");
           Circle c1 = (Circle)sr;
       }else{
           System.out.println("Circle不是sr的数据类型");
       }

    }
}

package com.lagou.task09;

/**
 *
 */
public class ShapeTest {
    //自定义成员方法实现将参数指定矩形对象特征打印出来的行为
    //也就是绘制图形的行为
    //Rect r = new Rect(1,2,3,4);
    //public static void draw(Rect r){
    //    r.show(); // 1 2 3 4
    //}
    //自定义成员方法实现将参数指定圆形对象特征打印出来的行为
    //public static void draw(Circle c){ //重载
    //    c.show(); // 1 2 3
    //}
    //自定义成员方法实现既能打印矩形对象又能打印圆形对象的特征
    //对象由参数传入,子类is a 父类
    //Shape r = new Rect(1,2,3,4);
    //Shape r = new Circle(1,2,3);
    //多态的使用场合之一,通过参数传递形成了多态
    public static void draw(Shape s){ //重载
        // 父类类型的引用指向子类类型的对象,这就是多态
        //编译阶段调用父类的版本,运行阶段调用子类重写后的版本
        s.show(); // 1 2 3 4
    }
    public static void main(String[] args) {
        //Rect r = new Rect(1,2,3,4);
        ShapeTest.draw(new Rect(1,2,3,4));
        ShapeTest.draw(new Circle(1,2,3));


    }
}

多态的特点------------------------------
当父类类型的引用指向子类类型的对象时
父类类型的引用可以直接调用父类独有的方法
父类类型的引用不可以直接调用子类独有的方法
对于父子类都有的非静态方法来说,编译阶段调用父类版本,运行阶段调用子类重写的版本(动态绑定)
对于父子类都有的静态方法来说,编译和运行阶段都调用父类的版本,即对于静态方法的调用只取决于变量类型
与指向什么的对象无关
引用数据类型之间转换的方式------------------------------
引用数据类型之间的转换方式有两种:自动类型转换和强制类型转换
自动类型转换主要指小类型向大类型的转换,也就是子类转为父类,也叫做向上转型
强制类型转换主要指大类型向小类型的转换,也就是父类转为子类,也叫做向下转型或显式类型转换
引用数据类型之间的转换必须发生在父子类之间,否则编译报错
若强转的目标类型并不是该引用真正指向的数据类型时,则编译通过,运行阶段发生类型转换错误
为避免上述错误的发生,应该在强转之前进行判断,格式如下:
if(引用变量 instanceof 数据类型)
判断引用变量指向的对象是否为后面的数据类型
对于引用的自动转换,与基本数据类型不同,基本数据类型实际上就是小到大自动转换,大到小强制转换
而引用类型在名称上是小到大自动转换,大到小强制转换,即子类自动转换为父类,父类必须要强制转换为子类
这是名称上的描述,具体情况请看下分析
//父类 fulei
//子类 zilei
//fulei fu = new fulei();
//zilei zi = new zilei();
//new fulei()会在堆区里,假设空间为1M
//new zilei()由于继承了父类,那么自身的东西加上父类的东西,假设空间就分为1M+0.5M,其中0.5M是子类的
//可以看成两个格子,父类一个,子类一个,父类格子在子类格子里面
//看如下
fulei fu = new zilei();
//由于new zilei()有两个格子,所以fu引用可以选择两个
//但对于对象来说,类引用指向类的对象,那么他就会指向子类里的父类格子
//即fu指向的是子类格子里的父类格子,即削弱版的zilei,因为他有父类的格子
//所以相当于子类自动转换为父类--------------------------
//再看如下
zilei zi = (zilei)fu
//由于对于对象来说,类引用指向类的对象,那么我们将fu的指向换个选择,即指向子类
//因为我们已经指向了,要改指向,需要强制转换
//所以相当于父类强制转换为子类-------------------------

  //当然无论怎么解释,最终都是规定好的,为了保证多态的

-
多态的实际意义------------------------------
多态的实际意义在于屏蔽不同子类的差异性实现通用的编程带来不同的效果
抽象方法的概念------------------------------
抽象方法主要指不能具体实现的方法并且使用abstract关键字修饰,也就是没有方法体
具体格式如下
//访问权限 abstract 返回值类型 方法名(形参列表);
//比如
public abstract void cry();
抽象类的概念------------------------------
抽象类主要指不能具体实例化的类并且使用abstract关键字修饰,也就是不能创建对象
抽象类中可以有成员变量,构造方法,成员方法
抽象类中可以没有抽象方法,也可以有抽象方法
拥有抽象方法的类必须是抽象类,因此真正意义上的抽象类应该是具有抽象方法并且使用abstract关键字修饰的类
抽象类不能实例化的原因是因为他里面可以有抽象方法,而实例化的话,就有可能会调用该抽象方法(实际上这是为了解释而解释,更多是一个规定,及针对开发语言对现实需要的规定)
而抽象方法没有方法体,即调用无意义,那么规定,有抽象类就不可以实例化,防止他里面有抽象方法
即通过前面的学习,则可以证明Java是一门安全的语言
抽象类的实际意义------------------------------
抽象类的实际意义不在于创建对象而在于被继承
抽象类可以防止有人实例化
当一个类继承抽象类后必须重写抽象方法,否则该类也变成抽象类,要不然报错
也就是抽象类对子类具有强制性和规范性,因此叫做模板设计模式
在以后的开发中推荐使用多态的格式,此时父类类型引用直接调用的所有方法一定是父类中拥有的方法
若以后更换子类时,只需要将new关键字后面的子类类型修改而其他地方无需改变就可以立即生效
从而提高了代码的可维护性和可扩展性
该方式的缺点就是:父类引用不能直接调用子类独有的方法,若调用则需要强制类型转换
package com.lagou.task09;

/**
 *
 */
public abstract class AbstractTest { //一般抽象类都是abstract或Abstract开头的名字
    //抽象类除了不能实例化外,成员变量和成员方法和构造方法都可以有
    private int cnt;

    public AbstractTest() {
    }

    public AbstractTest(int cnt) {
        setCnt(cnt);
    }

    public int getCnt() {
        return cnt;
    }

    public void setCnt(int cnt) {
        this.cnt = cnt;
    }
    //自定义抽象方法,可以不写,但是写了类就必须是抽象类,即抽象类可以没有抽象方法,但是有抽象方法的一定是抽象类,抽象方法一般不可以写方法体(可能随着版本更替会发生改变),因为他只是用来重写的
    public abstract void show();

    public static void main(String[] args) {
        //声明该类类型的引用指向该类类型的对象
        //AbstractTest at = new AbstractTest();
        //System.out.println("at.cnt = " + at.cnt); //0
    }
}

package com.lagou.task09;

import com.lagou.task08.SubSuperTest;

/**
 *
 */
//继承抽象类必须自己是抽象类或者重写抽象类
public class SubAbstractTest extends AbstractTest{

    @Override
    public void show() {
        System.out.println("其实我是被迫重写的,否则我也得变成抽象的呀");
    }
    public static void main(String[] args) {
        //声明本类类型的引用指向本类类型的对象,没有多态
        SubAbstractTest sat = new SubAbstractTest();
        // 直接写new SubSuperTest();在这一行按下 alt和enter再按enter就可以直接自动写上引用
        //引用名字自己写
        sat.show();

        System.out.println("-------------------------");
        //声明AbstractTest类型的引用指向子类的对象,形成了多态,多态的使用场合之二
        //多态的使用场合之二:直接在方法体中使用抽象类的引用指向子类类型的对象
        AbstractTest at = new SubAbstractTest2();
        //编译阶段调用父类版本,运行阶段调用子类版本
        at.show();
        ((SubAbstractTest2)at).test();
        SubAbstractTest2 sat2 = new SubAbstractTest2();
        sat2.test();
    }
}

package com.lagou.task09;

/**
 *
 */
public class SubAbstractTest2 extends AbstractTest {

    @Override
    public void show() {
        System.out.println("使用多态方式可以提高代码的可维护性哦");
    }
    public void test(){
        System.out.println("第二个子类中独有的方法");
    }
}

案例题目------------------------------
银行有定期账户和活期账户,继承自账户类,账户类中:
public class Account{
    private double money;
    public double getLixi(){}
}
package com.lagou.task09;

/**
 *
 */
public /*final*/abstract class Account { 
    //final修饰的类不可继承
    //而抽象类必须要继承,所以抽象类不可修饰final

    private int money;

    public Account() {
    }

    public Account(int money) {
        setMoney(money);
    }

    public int getMoney() {
        return money;
    }

    public void setMoney(int money) {
        if(money >= 0) {
            this.money = money;
        }else{
            System.out.println("金额不合理哦");
        }
    }
    //自定义抽象方法实现计算利息并返回的功能描述
    public abstract double getLiXi();
    //private和abstract关键字不能共同修饰一个方法
    //private abstract double getLiXi();
    //由于有private修饰的方法在其他类里不可使用,所以抽象方法不可用这个修饰符
    //因为抽象类必须要继承,而其他类要重写这个方法
    //final 和  abstract 关键字不能共同修饰一个方法
    //因为final不能被重写,而抽象方法必须要重写,否则无意义
    //public final abstract double getLiXi();
    //因为static修饰的抽象方法提升为类层级
    //可以用类来调用,而抽象方法没方法体,即调用无意义
    //所以不可用static修饰抽象类
    //public static abstract double getLiXi();
    //上面的不可以用的,基本都是会提示,即报错(编译期,idea只是提示而已)
    
}

package com.lagou.task09;

/**
 *
 */
public class FixedAccount extends Account{

    public FixedAccount() {
    }

    public FixedAccount(int i) {
        super(i); //表示调用父类的有参构造方法
    }

    @Override
    public double getLiXi() {
        //利息 = 本金 * 利率 * 时间
        return getMoney() * 0.03 * 1;
    }

    public static void main(String[] args) {
        //声明Account类型的引用指向子类类型的对象,形成了多态
        //Account acc = new FixedAccount(1000);
        Account acc = new FixedAccount();
        acc.setMoney(1000);
        double res = acc.getLiXi();
        System.out.println("计算的利息是:" +res);
    }
}

接口的基本概念------------------------------
接口就是一种比抽象类还抽象的类,体现在所有方法都为抽象方法
即所有的方法都是抽象方法
定义类的关键字是class,而定义接口的关键字是interface
如:金属接口,货币接口,黄金类
package com.lagou.task09;

/**
 *
 */
public interface InterfaceTest {
    //只有抽象方法(没方法体,弱化版的抽象类)和常量
    //接口主要用于抽象方法
    //由于类只可以单继承,虽然接口是弱化的抽象类,但可以让类多实现接口,由于抽象类被继承时,必须重写抽象方法,那么实现接口就必须重写所有的对应方法(因为都是抽象方法),而正是因为这样,所以导致他可以被多实现,因为基本都是使用自己的方法,而不是他的,所以这是一个特别的
    //int a = 0;
    //这里的a其实是常量,因为在接口里成员变量会变成常量
    //即默认加上了public static final
    //其中static和final可以互换位置
    //只不过他没有给你看到,隐式的变为常量了
    //public final int b = 0;
    //且必须要用final,因为必须要初始化
    //public final static int b = 0;
    //因为接口是抽象类的一种,比抽象类还要抽象
    //即接口是不能实例化,当我们需要用他的变量时,必须要用类名.的方式去使用
    //所以加上static
    //其中被static final修饰的变量称为常量
    //所以接口里面只能有常量
    //之所以抽象类没有这样,是因为他可以被继承,而接口只可被实现
    //所以接口必须要常量,而抽象类可以没有
    //private void show(){} //新特性:从jdk1.9(java9)开始允许接口出现私有方法
    //java8开始出现默认方法
    //也可以定义static方法
    //如static void fa(){}
    //如public default void fb(){}
    /*public abstract*/
    void show(); //接口中的抽象方法不能有方法体
    //里面只能有抽象方法(新特性除外)
    //可以省略public和abstract但建议写上
    //protected和private不可修饰抽象方法,前者规定,后者也不可写(虽然需要方法体)
    //对于protected来说,可以被抽象方法修饰,但不可被接口的抽象方法修饰,这是规定的
    //对于private来说,因为使得他只可以在本类中使用,但接口要被实现,即被其他类使用
    //所以不可以用private修饰
        //具体情况也可以认为接口需要公开
    public default void fa(){
        System.out.println("换行");

    }
    public default void fa1(){ //default默认方法,接口可以定义默认方法
        //用来调用私有方法的
        System.out.println("换行");
        bb();
    }
    private void bb(){
        System.out.println("hh1");
    }
    public static void fb(){
        System.out.println("换行");

    }
    public static void fb1(){
        System.out.println("换行");
        cc();
    }
    private static void cc(){
        System.out.println("hh1");
    }





}

package com.lagou.task09;

/**
 *
 */
public interface Metal {

    //自定义抽象方法描述发光的行为
    public abstract void shine();

}

package com.lagou.task09;

/**
 *
 */
public interface Money {

    //自定义抽象方法描述购物的行为
    public abstract void boy();
}

package com.lagou.task09;

/**
 *
 */
public class Gold implements Metal,Money{
    //抽象类舍弃了一些东西,变成接口,从但继承变成多实现(继承)了


    @Override
    public void shine() {
        System.out.println("发出金黄色的光芒");
    }

    @Override
    public void boy() {
        System.out.println("买了好多好吃的");
    }

    public static void main(String[] args) {
        //声明接口(特殊的抽象类)类型的引用指向实现类的对象,形成了多态
        Metal st = new Gold();
        st.shine();
        Money mn = new Gold();
        mn.boy();
        //接口弥补Java不可以多继承的不足
    }
}

案例题目------------------------------
编程实现Runner接口,提供一个描述奔跑的行为的抽象方法
编程实现Hunter接口继承Runner接口,并提供一个描述捕猎行为的抽象方法
编程实现Man类实现Hunter接口并重写抽象方法,在main方法中使用多态方式测试

在这里插入图片描述

package com.lagou.task09;

/**
 *
 */
public interface Runner {
    //自定义抽象方法描述奔跑的行为
    public abstract void run();
}

package com.lagou.task09;

/**
 *
 */
//接口只能继承接口,且可以实现多继承
public interface Hunter extends Runner/*,Metal*/{

    //自定义成员方法描述捕猎的行为
    public abstract void hunt(); //成员变量和成员方法多个单词写时
    //通常要求从第二个单词起每个单词的首字母大写
    //增加一个抽象方法
    //public abstract void show1();
    //也可以增加非抽象方法

    //将两个默认的方法中重复的代码可以提取出来打包成一个方法在下面的两个方法中分别调用即可
    private void show(){
        System.out.println("在以后的开发中尽量减少重复的代码,也就是减少代码的冗余");
    }
    public default void show1(){
        //System.out.println("在以后的开发中尽量减少重复的代码,也就是减少代码的冗余");
        show();
        System.out.println("show1方法中:这里仅仅是接口中的默认功能,实现类可以自由选择是否重写");
    }
    public default void show2(){
        //System.out.println("在以后的开发中尽量减少重复的代码,也就是减少代码的冗余");
        show();
        System.out.println("show2方法中:这里仅仅是接口中的默认功能,实现类可以自由选择是否重写");
    }
    //增加静态方法 隶属于类层级,也就是接口层级
    public static void test() {
        System.out.println("这里是静态方法,可以直接通过接口名.的方式调用,省略对象的创建");
    }


}

package com.lagou.task09;

/**
 *
 */
public class Man implements Hunter{
    //当类名由多个单词组成时,要求每个单词首字母都要大写
    //alt+enter快速找出错误的解决方式,需要鼠标标上
    @Override
    public void hunt() {
        System.out.println("正在追赶小白兔");
    }

    @Override
    public void run() {
        System.out.println("被大熊追赶,正在亡命的奔跑");
    }

    @Override
    public void show1() {
        System.out.println("为了给你几分薄面,我决定重写一下");
    }

    public static void main(String[] args) {
        //声明接口类型的引用指向实现类的对象,形成了多态
        Runner runner = new Man();
        runner.run();
        Hunter hunter = new Man();
        hunter.hunt();
        System.out.println("--------------------");
        //可以使用接口名称.的方式调用接口中的静态方法
        //静态方法主要描述功能的
        Hunter.test();
    }

}

抽象类和接口的主要区别------------------------------
定义抽象类的关键字是abstract class,而定义接口的关键字是interface
继承抽象类的关键字是extends,而实现接口的关键字是implements
继承抽象类支持单继承,而实现接口支持多实现,且接口可以多继承接口
抽象类可以有构造方法,而接口中不可以有构造方法
抽象类中可以有成员变量,而接口中只可以有常量
抽象类中可以有成员方法,而接口中只可以有抽象方法(java9开始允许接口出现私有方法除外)
抽象类中增加的方法时子类可以不用重写,而接口中增加方法时实现类需要重写(Java8以前的版本)
java9开始允许接口出现私有方法,java8开始允许接口出现默认方法
从Java8开始增加新特性,接口中允许出现非抽象方法和静态方法,但非抽象方法需要使用default关键字修饰
从Java9开始增加新特性,接口中允许出现私有方法
虽然我们说idea是提示,但是并非都是提示,也会影响jdk判断的,他也是能够实现的,所以我们应该要认为编译期就是idea以及jdk他们共同的提示和操作结果
重写后,对应的变量名称可以随便改,没有要求
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值