黑马程序员_Java基础_前期准备01_2.2

---------------------------------------- JavaEE+云物联、期待与您交流!---------------------------------------------

前期准备01-2.2

 

十三、内部类

将一个类,定义在了另一个类的里面,对里面的那个类,就称为内部类,也可以称为内置类、嵌套类。而被嵌套的那个类,则就被称为外部类。

注意:非被嵌套的外部类,此处定义为其它外部类。

①内部类的意义:

当描述事物时,事物的内部还有事物,该事物就用内部类来描述,因为内部事物在使用外部事物中的内容。

②内部类的访问特点:

❶内部类可以直接访问外部类中的成员,包括私有成员。

内部类之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式为:外部类名.this

❷外部类若要访问内部类中的非静态成员,则必须建立内部类的对象。

❸当内部类定义在外部类的成员位置上时,内部类就是外部类的一个成员,可以被成员修饰符所修饰。

private:将内部类在外部类中进行封装。

static:内部类具备了静态的特性。

❹成员内部类的访问方式:

对于在其它外部类中创建非私有成员内部类的对象:

格式:外部类名.内部类名 变量名=new 外部类名().new 内部类名();

对于在其它外部类中访问,静态成员内部类的非静态成员:

格式:new 外部类名.内部类名().内部类的非静态成员

对于在其它外部类中访问,静态成员内部类的静态成员:

格式:外部类名.内部类名.内部类的静态成员

注意:当成员内部类中定义了静态成员时,则内部类必须是静态的。当外部类中的静态方法访问成员内部类时,内部类也必须是静态的。

❺局部内部类:

当内部类定义在局部时,不可以被成员修饰符所修饰;可以直接访问外部类中的成员,因为还持有外部类中的引用;只能够访问它所在的局部的被final修饰的局部变量。

③匿名内部类:

匿名内部类,就是内部类的简写格式。其实,匿名内部类是一个对象。

❶定义匿名内部类的前提:

必须继承了一个类或者实现接口。

❷匿名内部类的格式:

new 父类或接口(){定义子类内容}

创建父类对象,补足子类功能。

匿名内部类其实就是一个匿名的子类对象。多态的一种体现。

❸匿名内部类的弊端:

匿名内部类中定义的方法一般不超过2个,因为匿名内部类是为了简化书写而存在的;一个匿名内部类只能调用一个方法。

❹匿名内部类的应用:

当一个函数的参数列表是一个接口类型,并且该接口中的方法不超过2个时,就可以通过定义匿名内部类,完成向函数传递参数的动作。

 

十四、异常

问题也是现实生活中的一个具体的事物,也可以通过Java类的形式进行描述,并封装成对象。把问题封装成对象就是异常。

①异常的体系:

Throwable(['θrəuˌeibl])

Java中所有错误和异常的超类。只有当对象是此类或者其子类的实例时,才能够通过Java虚拟机或throw语句抛出,才可以是catch子句中的参数类型。可抛性是Throwable体系独有的特点。

❶Error(['erə])

通常出现重大问题:如,运行的类不存在或者内存溢出等。

一般不编写针对代码对其处理。

❷Exception([ik'sepʃən])

在运行时,运行出现了一些状况,可以通过try、catch、finally处理。

❸Error和Exception的子类名都是以父类名作为后缀的。

②异常的声明方式:

关键字throws:用在函数上,声明方法可能会抛出的异常类型。

❶异常的声明可以提高程序的安全性,对于编译异常,调用者必须要处理。

❷声明异常时,建议声明为更加具体的异常,这样在处理时也会更加有针对性。

❸一个方法可以抛出多个异常类型,用逗号将其隔开。

③处理异常的格式:

❶try{异常代码}catch(异常类型 参数){处理方式}finally{关闭资源}

❷try{异常代码}catch(异常类型 参数){处理方式}

❸try-catch的跳转操作,也可以应用于程序执行时对某些代码的跨越。

④对捕获的异常对象进行处理的简单方法:

❶getMessage方法(['getˌmesidʒ])

public String getMessage()

返回此throwable对象的详细消息字符串。

❷printStackTrace方法([print][stæk][treis])

public void printStackTrace()

将此throwable对象及其被追踪的信息输出至标准错误流。输出堆栈跟踪,包含异常类型、异常信息、异常帧的位置。Java虚拟机默认的处理方式。

❸toString方法

public String toString()

返回此throwable对象的简短描述。

结果为:

此对象的类名:调用此对象getLocalizedMessage()方法的结果

❹getLocalizedMessage方法([get]['ləukə'laizd]['mesidʒ])

public String getLocalizedMessage()

创建此throwable对象的本地化描述。子类可以重写此方法,以便生成特定于其所处语言环境的消息。对于不重写此方法的子类,默认实现返回与getMessage()相同的结果。

❺fillInStackTrace方法([fil][in][stæk][treis])

public Throwable fillInStackTrace()

返回对此Throwable实例的引用(异常帧)。在异常堆栈跟踪中的填充,此方法在Throwable对象的信息中,记录有关当前线程堆栈帧的当前状态。

⑤异常的处理原则:

❶方法中只要发生一个未被处理的异常,方法就会被终止。

❷方法中发生了未被抛出的异常,则应停止运行,方便于对程序的修正。

❸方法中抛出几种异常类型,就处理几种类型的异常,一个catch块对应一个异常类型。

❹处理多个异常类型时,若是异常类型间存在继承关系,则应该将最父类的异常类型,放在最后面处理。否则,其子类异常将没有被执行的机会,并且编译时不会被通过。

❺处理异常时,一定要使用具体的处理方式,如:异常日志。

❻异常是由谁造成的就由谁去处理。

❼在程序的互动环节发生异常时,遵循异常处理的分层原则,处理自己的异常,抛出交互的异常。

⑥自定义异常:

实际的项目中,会出现特有的问题。而这些问题,并未被Java所描述和封装。对于这些特有的问题,可以借鉴Java对问题进行封装的思想,通过对Java异常类的继承,对其进行自定义的封装。

❶自定义异常的方法:

定义一个类,继承Java的一个异常类,描写自定义的处理方式。

之所以要继承Java的异常类,是为了让其具有可抛性。

❷自定义异常的使用:

Java虚拟机,既能识别被自动抛出的异常对象,也能识别被手动抛出的异常对象。对于自定义异常,需要被手动抛出。

❸关键字throw:

用于在函数内部,手动抛出异常的对象。

如果throw语句单独存在,其后面就不能够再定义其它语句,因为必然会发生异常,后面的语句执行不到。而且,编译会失败。类似于continue、break、return,单独存在时,其后面都不能够有任何语句。

❹只要方法中用throw抛出了异常对象,就必须要对异常做出处理动作,要么throws(在方法上声明),要么try(在内部捕捉并处理)。运行异常除外。

一般情况下,只是在函数上声明出来,让该函数的调用者去处理。

❺在自定义的异常类中,可以通过构造函数向父类的构造函数中传值,用以调用父类的方法。当然,也可以定义自己的方法,获取需要的内容。

⑦RuntimeException(['rʌntaim][ik'sepʃən])

当此类及其子类的对象被抛出时,函数上可以不用声明。如果在函数上声明了这种类型的异常,调用者也可以不用处理。

❶此类异常不用声明,是因为不需要调用者去处理。当该类异常发生时,希望程序停止。因为,在程序运行时,出现了让程序无法继续运行的情况,需要在程序停止后,对相应的代码进行修正。

❷在自定义异常时,如果该异常的发生,让程序无法继续运行,就让它继承RuntimeException。

❸异常在编译时的两种处理方式:一是编译时被检测的异常;二是编译时不被检测的异常(RuntimeException及其子类)。

即异常可以被分为:编译时异常和运行时异常。

❹RuntimeException中的几个常见的子类:

ArithmeticException

([ə'riθmətik][ik'sepʃən])

在出现异常的运算条件时抛出。算术异常。

IndexOutOfBoundsException

(['indeks][aut][əv]['baundz][ik'sepʃən])

在某排序索引(例如对数组、字符串或向量的排序)超出范围时抛出。角标越界异常。

NullPointerException

([nʌl]['pɔintə][ik'sepʃən])

当程序试图在需要对象的地方使用null时,抛出此异常。空指针异常。

IllegalArgumentException

([i'li:gl]['a:gjumənt][ik'sepʃən])

在向方法传递了一个不合法或者不正确的参数时抛出。参数异常。

⑧关键字finally

❶和try搭配使用,表示不管try语句是否发生异常,都要执行finally中的代码,一般用于关闭与资源的连接。

❷只有一种情况例外,finally中的代码不被执行,即Java虚拟机被立刻终止(System.exit(0))。

❸try{异常代码}finally{关闭资源}(此处没有catch,没有处理异常)

⑨异常的覆盖

❶如果父类方法中抛出异常,那么子类在覆盖该方法时,只能抛出父类的异常或者该异常的子类。

❷如果父类方法中抛出了多个异常,那么子类在覆盖该方法时,只能抛出父类异常的子集。

❸如果父类方法中没有抛出异常,那么子类在覆盖该方法时,也不可以抛出异常。如果子类的方法中发生了异常,就只能用try-catch处理。

⑩异常的应用

❶在开发过程中,一旦需要描述问题,就用异常的方式进行封装。

❷异常的使用,可以将正常流程代码和问题处理代码相分离,提高程序的阅读性。

 

十五、包

①关键字package:

用于定义包,一系列相关的类,组成一个包。

②包的意义:

❶包也是一种封装的形式。

❷给类提供了多层的命名空间。

❸方便于对类文件的管理。

❹可以将类文件与源文件相分离。

③包的定义方式:

package 包名;

❶包的定义,一定要放在程序代码的第一行。

❷包名的所有字母都小写。

❸为了避免包名不会重复,可以使用url来定义,因为url是唯一的。一般使用其反序的排列。

url(Uniform Resource Locator)统一资源定位器

(['ju:nifɔ:m][ri'zɔ:s][ləu'keitə])

④包的实现方式:

❶编译Java源文件时,要为包的存放指定位置。

格式为:

javac -d 包的存放目录 源文件名

❷对于包的存放路径,用句点表示当前目录。若是被指定的文件夹不存在,系统会自动新建一个。

❸当定义了包之后,类名的全称是:包名.类名。执行类文件时,要使用类的全称。在使用某一包中的类时,也要使用该类的全称。

❹当定义了包之后,classpath中定义的路径应是包的父目录。

⑤包的访问:

❶跨包访问时,被访问的类,其所有的权限修饰都必须是公有的,包括类自身,也包括类中的成员。

❷关键字protected

受保护的,用于修饰类中的成员变量和成员函数。被protected修饰的成员,可以被本类中的成员访问,可以被同一包内的其它成员访问,可以被其子类的成员访问。

❸访问权限列表

 

public

protected

default

private

同一个类中

可以访问

可以访问

可以访问

可以访问

同一个包中

可以访问

可以访问

可以访问

 

子类

可以访问

可以访问

 

 

不同包中

可以访问

 

 

 

❹关键字import

导入类。

Java中使用import导入类,有两种方式:一是单类型导入,好处是编译速度快,可以避免命名冲突,缺点是导入语句可能会很长;二是按需类型导入(使用通配符*),这种形式会增加Java代码的编译时间,而且有可能会造成命名冲突。

开发时,一般使用单类型导入,开发工具会有相关的技术支持。

 

十六、多线程

①进程

❶进程的概念

进程是操作系统结构的基础;是一次程序的执行;是一个程序及其数据,在处理机上顺序执行时所发生的活动;是程序在一个数据集合上运行的过程;它是系统进行资源分配和调度的一个独立单位。

❷进程的特点

从概念上来说,有两点:一是,进程是一个实体(包括文本区、数据区、堆栈);二是,进程是一个正在执行中的程序。

从结构上来说,有三点:包含程序、数据、进程控制块。

从执行上来说,有四点:动态性、并发性、独立性、异步性。

②线程

❶线程的概念

线程是进程中的某一个单一顺序的控制流;是进程中程序的最基本的调度单位;是程序执行流的最小单元。也被称为轻量进程。线程存在于进程之中,依附于进程而存在。

❷多线程

当一个进程中,存在多个执行路径(控制单元)时,即可以称为多线程。

❸线程的特点

必然性:一个进程至少包含一个线程

独立性:是一个可以独立执行的控制单元

并发性:多个线程之间可以并发执行

动态性:多个线程并发执行,必然使得线程在执行时会有短暂的停顿

异步性:多个线程并发执行,必然使得线程在执行时会有不和谐的时候

共享性:多个线程同时存在时,共享该进程的所有资源

关联性:一个线程可以创建和撤销本进程的另一个线程

中断性:多个线程并发运行时,某些线程可以在执行过程中暂停或等待

③进程与线程的关系

❶进程是资源分配的基本单位

❷线程是程序执行的基本单位

❸线程依附于进程存在,进程中至少有一个线程,即其自身

④多线程的意义

多线程的出现,提高了程序的执行效率。

多线程提高的并不是CPU的运行效率,而是通过提高对资源的使用效率,来提升系统的性能,进而提高了程序的执行效率。

⑤JVM中的主线程

JVM启动时,会有一个进程,即java.exe。该进程中至少有一个线程负责Java程序的执行,而且这个线程运行的代码存放于main方法中,该线程称之为主线程。

JVM是一个多线程,因为在主线程启动时,同时还有可能会有垃圾回收机制的线程也在被执行。

⑥在程序中自定义线程

创建新的执行线程有两种方法:

❶Thread([θred])

将类声明为Thread的子类,然后在子类中覆盖Thread类的run方法。public void run(){}

创建了子类的对象之后,就已经创建了一个线程,只是还没有被启动。

通过调用start方法(对象名.start()),来启动该线程;并且,JVM会自动调用该对象的run方法。

之所以在子类中一定要覆盖Thread类的run方法,是因为Thread类是用于描述线程的,其内部就定义了一个功能,用于存放线程要运行的代码,该存储功能就是run方法。每一个线程都应该拥有自己独特的执行代码。

❷调用方法start和run的区别:

如果直接用子类对象调用run方法,则仅仅是一个对象在调用自己的方法,此时的执行者是主线程,该对象的线程虽然被创建了,但是没有被启动。

如果调用start方法,就可以启动该线程,同时,run方法也会被JVM自动调用并执行。

❸Runnable(['rʌnəbl])

将类声明为实现Runnable接口的类,然后在该类中实现run方法。

创建该类的对象,并将它当做参数传递给Thread对象(Thread对象被创建后,就有了新的线程)的构造函数,再由Thread对象去调用其start方法,实现新线程的创建并被运行。这时Thread对象执行的run方法,是实现了Runnable接口的类的run方法。

Runnable为非Thread子类的类提供了一种激活方式。

❹Thread和Runnable区别:

线程代码存放的位置不同。

Runnable避免了Java中的单继承的局限性。

建议使用实现Runnable接口的方式,创建新的线程。

⑦线程的五种状态

❶被创建,线程存在,没有执行资格,没有执行权

❷运行,有执行资格,有执行权

❸阻塞状态(临时状态),有执行资格,没有执行权

❹冻结(包括睡眠和等待),没有执行资格,没有执行权

❺消亡,进程结束

线程的五种状态的关系,见下图:

 

⑧自定义线程的名称

❶系统有默认名称,从Thread-0开始,编号为int型。

❷可以通过构造函数,自定义名称,需要调用父类相应的构造函数。也可以通过setName()来设置线程的名称。

❸Thread中的方法

static Thread currentThread()

(['stætik][θred]['kʌrənt][θred])

获取当前线程的对象,通用格式,应用环境大于this。

public final void setName(String name):

改变线程名称,使之与参数name相同。

public final String getName():

获取线程名称。

public static void sleep(long millis,int nanos)  (['milis]['nænəuz])

throws InterruptedException  ([intə'rʌptid][ik'sepʃn])

在指定毫秒数加指定的纳秒数这段时间,让当前正在执行的线程休眠(暂停执行)。该线程不会丢失任何监视器的所属权。可以只传入一个毫秒值。

⑨同步

为了解决多线程在并发执行时,程序的安全问题。

❶多线程的安全问题

当一个进程的共享数据被多条语句操作时,某个线程对多条语句只执行了一部分,还没有执行完,其它线程就参与进来执行,导致了共享数据被执行了错误的操作。

❷对于多线程安全问题的解决方式

对于多条的操作共享数据的语句,只能让一个线程都执行完。在其执行过程中,其它线程不可以参与执行。

❸关键字synchronized

同步,表示在同一时间只能由一个线程访问的代码块或者函数。同步函数使用的锁对象有两个,静态函数使用的是类名.class对象,非静态函数使用的是this对象。

格式:synchronized(对象){需要同步的代码;}

❹同步的前提:

必须要有两个或两个以上的线程在操作共享数据;必须是所有参与同步的线程使用同一把锁。

❺同步的好处

解决了多线程的安全问题。

❻同步的弊端

多个线程判断锁的动作,会消耗系统的资源。

❼同步的两种方式

同步代码块,将需要同步的代码封装起来。

同步函数,将需要同步的函数用synchronized修饰。

❽判断如何实现同步的方法

明确哪些代码是多线程运行代码。

明确哪些是共享数据。

明确多线程运行代码中哪些语句是操作共享数据的。

❾多线程中的单例设计模式

在多线程中,懒汉式容易出现异常。可以用同步来解决此问题,同步函数比较低效,每一个线程在使用该对象时都要判断一次锁;用同步代码块配合if语句的双重判断,可以稍微提高一下程序的运行效率。

采用单例设计模式时,建议使用饿汉式。

❿死锁

同步中嵌套同步,而锁却不同,容易发生死锁现象。

⑩多线程间通信

❶多线程间通信要解决的问题

当多个线程对共享数据做不同的操作时,即便添加了同步也依然会出现问题,每个线程会各做各的。这时就需要各个线程间有信息的互动,才能让程序正常运行。

❷等待唤醒机制

多线程间通信的一种方式。

设置一个标志位,各个线程操作共享数据时,同时操作标志位。通过对标志位的判断,以wait、notify的方法来实现CPU执行权的转移,完成通信的动作。

❸线程池

线程池中的线程都是后台线程。处于等待状态的线程都被放置在线程池中。notify唤醒的通常是第一个被等待的线程,当然这是不确定的。

❹wait()、notify()、notifyAll()  ([weit]['nəutifai]['nəutifai][ɔl])

此三个方法都只能使用在同步中。因为要对持有监视器(同步锁)的线程进行操作,而只有同步中才有锁,所以要使用在同步中。

调用方式为:锁对象.wait()、锁对象.notify()、锁对象.notifyAll()。

之所以要把这些操作线程的方法定义在Object类中,是因为锁可以是任意对象。

这些方法在操作同步中的线程时,都必须要标识它们所操作的线程持有的锁,只有在同一个锁上的被等待线程,才可以被同一个锁上的notify唤醒,不可以对不同锁上的线程进行唤醒。即,被等待和唤醒的进程,必须持有同一个锁。

❺notify和notifyAll

if和notify搭配使用,适用于只有两个线程,对共享资源进行各自不同的操作。

while和notifyAll搭配使用,适用于多个线程对共享资源进行不同的操作。唤醒所有线程,循环判断标记。

❻lock([lɔk]锁)(JDK1.5之后)

public interface Lock

一个接口。

Lock实现,提供了比使用synchronized方法和语句,可获得的更广泛的锁定操作。此实现允许更灵活的结构,可以具有差别很大的属性,可以支持多个相关的condition([kən'diʃn]条件)对象。

Lock替代了synchronized方法和语句的使用,将之前的隐式调用,变为显示调用。

❼ReentrantLock([ri:'entrənt][lɔk]可重入锁)

实现了Lock接口的类。通过创建它的对象,可以使用Lock接口的所有功能。

public void lock():获取锁。

public void unlock():释放锁。

public Condition newCondition():返回与此Lock实例一起使用的Condition实例。即返回一个锁对象。一个Lock实例可以捆绑多个锁对象,方便区别唤醒。

❽Condition([kən'diʃn]条件)

一个接口。

Condition将Object监视器(同步锁)方法(wait、notify、notifyAll)分解成截然不同的对象,以便通过将这些对象与任意Lock实现组合使用,为每个对象提供多个等待设置(wait-set)。

Lock替代了synchronized方法和语句的使用,Condition替代了Object监视器(同步锁)方法的使用。

public void await() throws InterruptedException:

([ə'weit]等待[θrəuz][intə'rʌptid]中断[ik'sepʃn])

使得当前线程在接到信号或被中断之前一直处于等待状态,调用者需要做异常处理。try-finally,将释放锁作为必须执行的语句。

public void signal()(['signl]信号):唤醒一个等待线程。如果所有的线程都在等待此条件,则选择其中的一个唤醒,通常是第一个进入等待状态的线程。

public void signalAll()([vɔid]['signl][ɔl]):唤醒所有等待线程。如果所有的线程都在等待此条件,则唤醒所有线程。

⑪停止线程

❶stop方法已经过时。

❷将run方法结束。

开启多线程运行,所运行的代码通常都是循环结构。只要控制住循环,就可以让run方法结束,也就是让线程结束。

可以在run方法中设置一个标记,当标记为true时,线程继续运行;当标记为false时,线程结束。

如果线程处于冻结状态,就不会读到标记,那么线程就不会结束。这时,就可以使用该线程的interrupt方法,解除此线程的冻结状态,并修改标记位,让该线程结束。

❸interrupt(Thread中的方法)

public void interrupt()

(['pʌblik][vɔid][intə'rʌpt])

中断线程。清除线程的冻结状态。

当线程在调用Object类的wait方法或Thread类的join、sleep方法过程中受阻,则其中断状态(冻结状态)将被清除,并且同时收到一个InterruptedException([intə'rʌptid][ik'sepʃn])。

当没有指定的方式让冻结的线程恢复到运行状态时,就需要对冻结状态进行清除,强制让线程恢复到运行状态中来。这时被中断的程序会抛出中断异常,就需要捕捉并处理此异常。在处理异常的同时,可以通过修改标记,让线程的运行条件变为false,从而中断该线程。

⑫Thread类的其它常用方法

❶public final voidsetDaemon(boolean on)

(['pʌblik]['fainl][vɔid][set]['di:mən]['buliən][ɔn])

将该线程标记为守护线程(后台线程)或用户线程。当正在运行的线程都是守护线程(后台线程)时,Java虚拟机退出。

该方法必须在启动线程前调用。on为true时,标记为守护线程。

后台线程的特点:当前台线程在运行时,与前台线程并发运行;当前台线程结束时,后台线程也结束。后台线程依赖于前台线程,就像是在守护前台线程一样。

❷public final void join()throws InterruptedException

(['pʌblik]['fainl][vɔid][dʒɔin]加入[θrəuz][intə'rʌptid][ik'sepʃn])

等待该线程终止。当前线程等待该方法调用者的运行结束。

当A线程执行到了B线程.join()方法时,A就会进入等待状态,等B线程都执行完,A才会执行。也就是说,A线程会一直等待B线程的运行结束,才能够获取执行资格。B线程可以与非A的线程并发执行。

此方法可以用于临时加入线程执行。

当A线程需要用到B线程的运算结果,才可以继续运行时,就可以让A线程调用B.join(),一直等待B线程的运行结束。

如果任何线程中断了处于等待状态的线程,处于等待状态的线程就会抛出中断异常,同时该线程的中断状态将被清除,并再次获得执行资格。

❸public String toString()

返回该线程的字符串表示形式,包括线程的名称、优先级和所属的线程组。

❹public final voidsetPriority(int newPriority)

(['pʌblik]['fainl][vɔid][set][prai'ɔriti])

更改线程的优先级。(1~10,1最低,10最高)

默认情况下,线程的优先级都是5。

MIN_PRIORITY:线程可以具有最低优先级[min][prai'ɔriti]

NORM_PRIORITY:分配给线程的默认优先级[nɔ:m][prai'ɔriti]

MAX_PRIORITY:线程可以具有最高的优先级[mæks][prai'ɔriti]

线程的优先级越大,获取执行资格的几率就越高。

❺public static void yield()

(['pʌblik]['stætik][vɔid][ji:ld])

暂停当前正在被执行的线程对象,然后让当前线程同其他线程,再次一起抢夺执行权。此方法能够让每个线程都可以比较均衡的获取到执行权。

⑬多线程的设计

❶当有某些程序需要被同时执行时,就用单独的线程进行封装。

❷使用Thread定义匿名内部类,可以直接调用start运行一个新的线程。

❸使用Runnable创建一个内部类,并new一个对象r,再用Thread创建一个匿名对象并传入r,然后调用其start方法,运行一个新的线程。

---------------------------------------- JavaEE+云物联、期待与您交流!---------------------------------------------

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值