Java复习——面向对象

面向对象

Java六大存储区域

首先来了解一下Java的六大存储区域

  1. 寄存器

  2. 堆栈:存放基本类型的变量与数据、对象的引用;但对象本身不存放在栈中,创建程序时,Java编译器必须知道存储在堆栈内的所有数据的确切大小和生命周期,因为它必须生成相应的代码,以便上下移动堆栈指针。栈的大小越大可分配的线程数就越少。

  3. 堆:开辟内存的速度比堆栈慢得多。存放所有new出来的对象。不必知道大小和生命周期,需要在运行时分配内存。

  4. 静态存储:又叫方法区,存放如class、static变量

  5. 常量存储:final修饰、String(其实也是final修饰),但final static 为常量存储区

  6. 非Ram存储:磁带、磁盘

     public class Sample {
         int s1 = 0;
         Sample mSample1 = new Sample();
         
         public void method() {
             int s2 = 1;
             Sample mSample2 = new Sample();
         }
     }
     Sample mSample3 = new Sample();
    

Sample 类的局部变量 s2 和引用变量 mSample2 都是存在于栈中,但 mSample2 指向的对象是存在于堆上的。

mSample3 指向的对象实体存放在堆上,包括这个对象的所有成员变量 s1 和 mSample1,而它自己存在于栈中。

结论:

局部变量的基本数据类型和引用存储于栈中,引用的对象实体存储于堆中。—— 因为它们属于方法中的变量,生命周期随方法而结束。
成员变量全部存储于堆中(包括基本数据类型,引用和引用的对象实体)—— 因为它们属于类,类对象终究是要被new出来使用的。

面向对象简介

三大特性

  1. 封装性

    • 将对象的属性和行为看成一个整体,“封装”成一个实体,即对象。
    • 另一个含义是指“信息的隐蔽”,有些对象属性,只允许外界读取,不允许更改;亦可指功能的实现细节
  2. 继承性

     父类的属性和行为,在子类中完成可以使用,子类也可以自定义自己的属性和行为。Java只允许单集成,通过interface弥补这个缺陷
    
  3. 多态性

    • 方法的重载
    • 对象多态:子类对象与父类对象进行相互转换,同一个行为,根据子类的不同,实现的功能也不相同(前提是子类有复写该方法)

类与对象的简单理解

类是对象的模板,而对象是类的实例

引用传递

引用传递是整个Java的精髓所在,而引用传递的核心概念也只有一个:一块堆内存空间(保存对象的属性信息)可以同时被多个栈内存所共同指向,则每一个栈内存都可以修改同一块堆内存空间的属性值。

封装

为什么要封装

隐藏实体的内部细节,不想被外部直接操纵,也符合现实世界的做法。(如存在银行中的存款(银行当成一个实体),不可能由存款人直接随意的修改金额,而是应该由银行内部去操作)

构造方法

定义

  • 构造方法的名称和类名称保持一致
  • 构造方法没有返回值
  • 对象实例化一定需要构造方法,如果类中没有声明构造方法,则会自动生成一个无参数、无方法内容的构造方法。如果类中已经声明了一个构造方法,则不会生成默认的构造方法。即,类中至少存在一个构造函数。

类中定义属性的默认值,只有在构造执行完毕后(不是构造方法)才可以真正赋值。

构造方法实际上严格来讲是属于整个对象构造过程的最后一步,对象的构造需要为其分配空间,之后设置默认值(指的是类型的默认值),最后留给构造方法进行其他操作。所以可以定义的构造方法是对象实例化的最后一步,而其他的几步用户根本就看不见,也无法操作:

public class Temp {

    public static void main(String[] args){
        Person person = new Person();
    }
}

class Person{
    private String name = "tom";// 此属性只有在构造完成后,才能赋值
    public Person(){
        System.out.print(name);
    }
}

匿名对象

一句话概括:没有栈内存指向的堆内存空间,就是匿名对象。并且只能使用一次,之后就被GC回收。
public class Temp {

    public static void main(String[] args){
        new Person().say();// 匿名对象
    }
}

class Person{
    private String name = "tom";// 此属性只有在构造完成后,才能赋值
    public Person(){
        System.out.print(name);
    }
    public void say(){
        System.out.print("my name is "+name);
    }
}

数组

常见的数据结构,牵扯到内存分配的问题。

public class Temp {
    public static void main(String[] args) {
        int[] arrs = {9, 6, 3, 2, 5, 7, 8, 4, 0, 1};
        bubbleSort(arrs);
        printArrs(arrs);
    }

    private static void printArrs(int[] arrs) {
        for (int i = 0;i < arrs.length;i++){
            System.out.print(arrs[i]+" , ");
        }
        System.out.println();
    }

    public static void bubbleSort(int[] arrs) {
        for (int i = 0; i < arrs.length - 1; i++) {// 比较的趟数
            for (int j = 0;j < arrs.length -1 - i;j++){// 每趟比较的次数
                if (arrs[j] > arrs[j+1]) {
                    int temp = arrs[j];
                    arrs[j] = arrs[j+1];
                    arrs[j+1] = temp;
                }
            }
        }
    }
}

对象数组内存图

String

每一个定义的字符串都表示一个String对象,是String类的一个匿名对象。

两种实例化String对象的区别

public class Temp {
    public static void main(String[] args) {
        // 因为每个字符串是一个匿名的String对象,所以,以new创建的String对象,在堆中,会开辟两块空间,其中一块成为垃圾,被GC回收,真正指向的是以new创建的内存
        String str1 = new String("hello");//不入池
        String str2 = "hello";// 入池
        String str3 = "hello";// 使用池里存在的字符串
        System.out.println(str1 == str2);// false
        System.out.println(str1 == str3);// false
        System.out.println(str2 == str3);// true
    }
}

public class Temp {
    public static void main(String[] args) {
        // 因为每个字符串是一个匿名的String对象,所以,以new创建的String对象,在堆中,会开辟两块空间,其中一块成为垃圾,被GC回收,真正指向的是以new创建的内存
        String str1 = new String("hello").intern();//入池
        String str2 = "hello";// 使用池里存在的字符串
        String str3 = "hello";// 使用池里存在的字符串
        System.out.println(str1 == str2);// true
        System.out.println(str1 == str3);// true
        System.out.println(str2 == str3);// true
    }
}

字符串的内容一旦声明,则不可改变

public class Temp {
    public static void main(String[] args) {
		// 每一次字符串的拼接操作,都会产生垃圾,字符串本身的内容没有任何改变。改变的只是对象实例的指向
        String str = "hello ";// 使用池里存在的字符串
        str += "world";
        str += "!!!";
        System.out.print(str);// hello world!!!
    }
}

this

public class Temp {
    public static void main(String[] args) {
        Person person = new Person("tim",11);
        System.out.println(person);// Person{name='null', age=0}
    }
}

class Person{
    private String name;
    private int age;
    public Person(String name,int age){
        name = name;// 这样赋值是无效的,因为name为局部变量
        age = age;
    }

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


public class Temp {
    public static void main(String[] args) {
        Person person = new Person("tim",11);
        System.out.println(person);// Person{name='tim', age=11}
    }
}

class Person{
    private String name;
    private int age;
    public Person(String name,int age){
        this.name = name;// 这样赋值是无效的,因为name为局部变量,用this指明为全局变量
        this.age = age;
    }

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
  • 使用this调用构造方法的操作,一定要放在构造方法的首行
  • 如果一个类中存在了多个构造方法,并且这些构造方法都是用了this()相互调用,那么至少要保留一个构造方法没有调用其他构造,以作程序的出口。

static关键字

  1. static定义的方法不能调用非static的方法或者属性
  2. 非static定义的方法可以调用static的属性或方法

代码块

普通代码块

public class Temp {
    public static void main(String[] args){
        {
            int x = 100;
            System.out.println(x);//100
        }
        int x = 10;
        System.out.println(x);//10
    }
}

构造块

public class Temp {
    public static void main(String[] args){
        new Person();
        new Person();
        new Person();
    }
}

class Person{
    {
        System.out.println("构造块");
    }
    public Person(){
        System.out.println("构造方法");
    }
}

执行结果:

构造块

构造方法

构造块

构造方法

构造块

构造方法

可以定义不同构造函数的共性代码,构造块在成员变量显示初始化以后执行

构造方法执行顺序:

  1. super();
  2. 成员变量显示初始化
  3. 构造代码块初始化
  4. 构造函数自定义内容初始化

静态块

public class Temp {
    public static void main(String[] args){
        new Student();
        new Student();
        new Student();
    }
}

class Person{
    public Person(){
        System.out.println("父类构造方法");
    }
}

class Student extends Person{
    static{
        System.out.println("静态块");
    }

    {
        System.out.println("构造块");
    }
    public Student(){
        System.out.println("构造方法");
    }
}

执行结果:

静态块

父类构造方法

构造块

构造方法

父类构造方法

构造块

构造方法

父类构造方法

构造块

构造方法

随着类的加载而执行,仅执行一次;在静态变量显示初始化以后执行

内部类

当描述事物时,事物的内部还有事物,这个内部的事物还在访问外部事物中的内容。这时就将这个事物通过内部类来描述。

访问方式:
内部类可以直接访问外部类的所有成员,包含私有成员;而外部类想要访问内部类中的成员,必须创建内部类对象。

内部类被修饰为public不多见,因为更多的时候内部类已经被封装到了外部类中,不直接对外提供。

非静态内部类中,不允许定义静态成员,仅允许在非静态内部类中定义静态常量static final,如果想要在内部类中定义静态成员,内部类必须也要被修饰为static。

内部类最大的优点:可以方便地访问外部类的私有操作,或者是由外部类方便地访问内部类的私有操作(那是因为内部类其实持有了外部类的引用:外部类.this,对于静态内部类不持外部类.this,而是直接使用外部类名):

public class Temp {
    public static void main(String[] args){
        new Outter().outterPrint();
    }
}

class Outter{
    private final String outString = "Outter";
    class Inner{
        private final String innerString = "inner";
        private void innerPrint(){
            System.out.println(Outter.this.outString);
        }
    }
    public void outterPrint(){
        Inner inner = new Inner();
        inner.innerPrint();
        System.out.println(inner.innerString);
    }
}

输出:

Outter

inner

内部类生成的class文件:Outter$Inner.class

实例化内部类对象

public class Temp {
    public static void main(String[] args){
        new Outter().new Inner().innerPrint();
    }
}

class Outter{
    private final String outString = "Outter";
    class Inner{
        private final String innerString = "inner";
        public void innerPrint(){
            System.out.println(Outter.this.outString);
        }
    }
    public void outterPrint(){
        Inner inner = new Inner();
        inner.innerPrint();
        System.out.println(inner.innerString);
    }
}

之所以实例化外部类对象,主要因为内部类需要访问外部类中的普通属性,那么普通属性只有实例化后才可以使用。

如果内部类不希望被其他类所使用,那么也可以使用private关键字修饰,使其成为私有内部类:

public class Temp {
    public static void main(String[] args){
        // 编译器会报错
        new Outter().new Inner().innerPrint();
    }
}

class Outter{
    private final String outString = "Outter";
    private class Inner{
        private final String innerString = "inner";
        public void innerPrint(){
            System.out.println(Outter.this.outString);
        }
    }
    public void outterPrint(){
        Inner inner = new Inner();
        inner.innerPrint();
        System.out.println(inner.innerString);
    }
}

static定义内部类

相当于外部类,并且只能访问外部类中static的成员

当静态方法访问内部类时,内部类必须是静态的

实例化方式:

外部类.内部类 内部类对象 = new 外部类.内部类();

方法中定义内部类(又称局部内部类)

public class Temp {
    public static void main(String[] args){
        new Outter().method();
    }
}
class Outter{
    private String outString = "outString";
    public void method(){
        class Inner{
            private void method(){
                System.out.println(outString);
            }
        }
        new Inner().method();
    }
}

方法中的内部类如果要访问方法的参数或者方法中的变量,这些参数后者变量前一定要加final关键字修饰,否则无法使用(因为编译生成的class中,直接操作那个最终数值了(生命周期))

public class Temp {
    public static void main(String[] args){
        new Outter().method("hello");
    }
}
class Outter{
    private String outString = "outString";
    public void method(final String str){
        class Inner{
            private void method(){
                System.out.println(outString);
                System.out.println(str);
            }
        }
        new Inner().method();
    }
}

继承

指的是扩充一个类已有的功能。

格式:

[类的修饰符] class 子类 extends 父类{}

子类又称为派生类,父类又称作超类。

public class Temp {
    public static void main(String[] args){
        Student student = new Student();
        student.setAge(18);
        student.setName("tom");
        System.out.println(student.toString());
    }
}
class Person{
    private String name;
    private int 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;
    }

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

class Student extends Person {

}


public class Temp {
    public static void main(String[] args){
        Student student = new Student();
        student.setAge(18);
        student.setName("tom");
        System.out.println(student.toString());
        System.out.println(student.getSchool());
    }
}
class Person{
    private String name;
    private int 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;
    }

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

/**
 * 另外定义父类中没有的方法
 */
class Student extends Person {
    private String school;

    public String getSchool() {
        return school;
    }

    public void setSchool(String school) {
        this.school = school;
    }
}

子类可以继承父类中的全部内容,但是对于私有操作属于隐式继承,而非私有操作属于显示继承。

继承的限制

  1. 只能多层继承,不允许多重继承。

  2. 父类中的私有也被继承下来,但却无法直接使用。

  3. 在继承中,如果要实例化子类对象,会默认先调用父类构造,为父类中的属性初始化,之后再调用子类构造,为子类中的属性初始化,即默认情况下,子类会找到父类中的无参构造函数。

    public class Temp {
    public static void main(String[] args){
    new Son();
    }
    }
    class Father{
    public Father(){
    System.out.println(“父类构造”);
    }
    }
    class Son extends Father{
    public Son(){
    // 第一行默认调用super();
    System.out.println(“子类构造”);
    }
    }

原因:子类会继承父类中的内容(显示初始化),所以子类在初始化时,必须先到父类中去执行父类的初始化操作。才可以更方便的使用父类中的内容。

在默认情况下,子类调用的是父类中的无参构造方法,而如果这个时候父类中没有无参构造,则子类必须通过super()显示调用指定参数的构造方法。

this和super调用构造方法时,不能够同时出现,两者是二选一的关系。

覆写

方法的覆写

构造方法不能被继承,因此不能覆写,但可以被重载。

当子类定义了和父类在方法名称、返回值类型、参数类型及个数完全相同的方法时,称为方法的覆写。

而当一个类中的方法被覆写后,如果实例化的是这个子类对象,则调用的方法就是覆写过的方法。

被子类所覆写的方法不能拥有比父类更严格的访问控制权限。(所以如果父类的方法为private,子类是无法覆写的,也不会这样去编码)

静态覆盖静态

当一个子类覆写了一个父类方法时,子类要想调用父类的被覆写过的方法,要在子类方法内加上super.

  • this.方法():先从本类查找是否存在指定的方法,如果没有找到,则调用父类操纵;
  • super.方法():直接由子类调用父类之中的制定方法,不再找子类。

属性的覆写

子父类中定义了一模一样的成员变量,都存在于子类对象中

public class Temp {
    public static void main(String[] args){
        new Son();
    }
}
class Father{

    public String msg = "father";// 此处暂时没有封装,严格来讲不符合开发标准,这种操作几乎没有意义,属性一定要封装,封装以后,就没有覆盖这一概念了

    public Father(){
        System.out.println("父类构造");
    }
}
class Son extends Father{
    public int msg =10;
    public Son(){
        System.out.println("子类构造");
        System.out.println("msg = "+this.msg);
        System.out.println("msg = "+super.msg);
    }
}

构造方法不能被继承,因此不能被重写,但可以被重载

final关键字

  1. 使用final定义的类不能有子类,即无法被其他类所继承
  2. 使用final定义的方法不能被重写
  3. 使用final定义的变量,为常量,必须在定义时候就指定默认值,并且无法修改

多例设计模式(可用枚举代替)

public class Temp {
    public static void main(String[] args) {
        System.out.println(Sex.getInstance("male").getStr());
    }
}

class Sex {
    private static final Sex MALE = new Sex("male");
    private static final Sex FEMALE = new Sex("female");
    private String str;

    private Sex(String sex) {
        this.str = sex;
    }

    public static Sex getInstance(String sex) {
        switch (sex) {
            case "male":
                return MALE;
            case "female":
                return FEMALE;
            default:
                return null;
        }
    }

    public String getStr(){
        return this.str;
    }
}

多态

  1. 方法的多态性

    • 重写(父类与子类之间,多态性的表现)
    • 重载(一个类内,多态性的表现)
  2. 对象的多态性

    • 向上转型:自动完成
    • 向下转型:依赖于向上转型,需强制
    • 对象的多态性和方法重写是紧密联系在一起的

public class Temp {
    public static void main(String[] args) {
        Father father = new Son();// 向上转型
        father.print();// 因为子类重写了父类的方法,所以调用的是子类的print()
    }
}

class Father{
    public void print(){
        System.out.println("Father print()");
    }
}

class Son extends Father{
    @Override
    public void print(){// 重写方法
        System.out.println("Son print()");
    }
}

public class Temp {
    public static void main(String[] args) {
        Father father = new Father();// 向上转型
        Son son = (Son) father;//ClassCastException 因为向下转型必须依赖于向上转型
        father.print();// 因为子类重写了父类的方法,所以调用的是子类的print()
    }
}

class Father{
    public void print(){
        System.out.println("Father print()");
    }
}

class Son extends Father{
    @Override
    public void print(){// 重写方法
        System.out.println("Son print()");
    }
}

instanceof

判断某个对象是否为某个类的实例

public class Temp {
    public static void main(String[] args) {
        Father father = new Son();// 向上转型
        System.out.println("father instanceof Father --- "+(father instanceof Father));
        System.out.println("father instanceof Son --- "+(father instanceof Son));
        father.print();// 因为子类重写了父类的方法,所以调用的是子类的print()
//        father.extendMethod();// 父类没有此方法,调用不了
        Son son = (Son) father;// 向下转型
        if (son instanceof Son) {
            son.extendMethod();
        }
//        结果:
//        father instanceof Father --- true
//        father instanceof Son --- true
//        Son print()
//        Son extendMethod()
    }
}

class Father{
    public void print(){
        System.out.println("Father print()");
    }
}

class Son extends Father{
    @Override
    public void print(){// 重写方法
        System.out.println("Son print()");
    }

    public void extendMethod(){// 子类拓展的方法
        System.out.println("Son extendMethod()");
    }
}

抽象类

最大特点:包含了抽象方法(只声明而未实现方法体的方法,定义时用abstract关键字完成,一定存在于抽象类中),用abstract声明。

  • 抽象类不能直接实例化。必须有子类,使用extends继承
  • 子类如果不是抽象类,必须重写父抽象类的全部抽象方法
  1. 抽象类不能用final定义,因为必须有子类
  2. 抽象类可以有构造方法,因为除了抽象方法之外,其还包括普通方法和属性,而属性一定要在构造方法执行完毕后,才可以进行初始化操作。
  3. 抽象类中可以不包含抽象方法,但是如果有抽象方法,则一定为抽象类。
  4. 抽象类能否用static定义?
    • 如果直接使用static,肯定无法定义一个抽象类(abstract的类不能生产对象,但是static是属于类,而类已经是一个存在的对象(类其实也是一个对象,他是在class文件加载到虚拟机以后就会产生的对象,通常来说它是单例的,就是整个虚拟机中只有一个这样的类对象),这两个关键字在这上面有一个关键的矛盾点);

    • 在内部类定义时,可以用static,表示定义了一个静态的内部抽象类

        public class Temp {
            public static void main(String[] args) {
                Father.Son impl = new Impl();
                impl.print();
            }
        }
        
        class Father{
            static abstract class Son extends Father{
                public abstract void print();
            }
        }
        
        class Impl extends Father.Son{
        
            @Override
            public void print() {
                System.out.println("Impl print()");
            }
        }
      

public class Temp {
    public static void main(String[] args) {
        Demo demo = new DemoImpl(33);
    }
}

abstract class Demo{
    public Demo(){
        this.print();
    }
    abstract void print();
}

class DemoImpl extends Demo{
    private int x = 100;

    /**
     * 一个类只有执行了构造方法后,才可以为类中的属性进行初始化操作,而在属性没有初始化之前,类中的所有属性,都是其对应数据类型的默认值
     * @param x
     */
    public DemoImpl(int x){
        this.x = x;
    }
    @Override
    void print() {
        System.out.println(x);
    }
}

上例中,实例化的是子类对象,根据对象的实例化流程,子类对象实例化前会首先调用父类构造,为父类中的属性初始化,但是这个时候子类对象由于没有被实例化,所以在DemoImpl类中的x的值为默认值0。父类中的构造又调用了print(),而此时实例化的是子类对象,所以调用的是子类重写的方法,结果为“x=0”

接口

定义时,全部由抽象方法和全局常量组成。使用interface关键字定义:

interface InterfaceName{
    public static final ConstantType CONSTANT_NAME = "CONSTANT_NAME";
    public abstract MethodType method(MethodParmType...parmName);
}

一个类可以同时实现多个接口,但是只能集成一个父类(或抽象类):

public class Temp {
    public static void main(String[] args){
        Son son = new Son();
        System.out.println(son.NUMBER);
        System.out.println(son.CONSTANT_NAME);
        System.out.println("-------------------");
        son.method("hello");
        son.print();
        // 输出结果:
//        5
//        CONSTANT_NAME
//        -------------------
//        hello
//        5 , CONSTANT_NAME
    }
}
interface A{
    public static final String CONSTANT_NAME = "CONSTANT_NAME";
    public abstract void method(String str);
}

/**
 * 简化形式定义
 */
interface B{
    int NUMBER = 5;
    void print();
}

class Son implements A,B{

    @Override
    public void method(String str) {
        System.out.println(str);
    }

    @Override
    public void print() {
        System.out.print(NUMBER+" , "+CONSTANT_NAME);
    }
}

在Java中,每一个抽象类都可以实现多个接口,一个接口却不能继承抽象类,也不能继承一个父类,但是一个接口却可以同时继承多个接口,以实现接口的多继承操作。

接口与抽象类的区别

public class Temp {
    public static void main(String[] args){
        Son son = new Son();
        Object obj = son;
        C c = (C) obj;
        System.out.print(c);
        // 输出:C toString
    }
}
interface A{
    public static final String CONSTANT_NAME = "CONSTANT_NAME";
    public abstract void method(String str);
}


/**
 * 简化形式定义
 */
interface B{
    int NUMBER = 5;
    void print();
}

abstract class C{
    @Override
    public String toString() {
        return "C toString";
    }
}

class Son extends C{
}

包装类

public class Temp {
    public static void main(String[] args){
        Integer integer = new Integer(33);// 装箱
        int num = integer.intValue();// 拆箱
        System.out.println(num);
    }
}

public class Temp {
    public static void main(String[] args){
        Integer integer = 33;// 自动装箱
        int num = integer;// 自动拆箱
        System.out.println(num);
    }
}

对象池

public class Temp {
    /**
     * 与String类似,有池的概念
     * @param args
     */
    public static void main(String[] args){
        Integer integer = new Integer(33); //不入池
        Integer integer1 = 10;// 入池
        Integer integer2 = 10;// 复用池里的对象
        System.out.println(integer == integer1);// false
        System.out.println(integer == integer2);// false
        System.out.println(integer1 == integer2);// true
        System.out.println(integer.equals(integer1));// false
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值