Java反射详解,还有什么理由学不会

STM32F103用软件I2C读取IP2366电量数据,实测避坑指南(附完整源码) 本文详细介绍了如何使用STM32F103的软件I2C驱动读取IP2366电池管理芯片的电量数据,包括GPIO初始化、I2C时序实现、关键延时优化及常见问题解决方案。通过实测避坑指南和完整源码,帮助开发者快速实现稳定的电量数据读取,适用于嵌入式电池管理系统开发。 阅读详情

简述

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

反射基础

RTTI(Run-Time Type Indentification) 运行时类型识别,就是在运行时识别使用一个对象/类的信息,不同于编译时已经确定好的类型

反射就是将一个类中的各种属性和方法等解剖为一个个对象

Class类

Class(java.lang)类 Java应用里每一个类或接口都是Class类的实例,每个Java类在jvm都表现为一个Class对象,基本数据类型和void数组也是Class类的对象

public final class Class<T> implements java.io.Serializable,
                              GenericDeclaration,
                              Type,
                              AnnotatedElement {
    private static final int ANNOTATION= 0x00002000;
    private static final int ENUM      = 0x00004000;
    private static final int SYNTHETIC = 0x00001000;

    private static native void registerNatives();
    static {
        registerNatives();
    }

    /*
     * Private constructor. Only the Java Virtual Machine creates Class objects.
     * This constructor is not used and prevents the default constructor being
     * generated.
     */
    private Class(ClassLoader loader) {
        // Initialize final field for classLoader.  The initialization value of non-null
        // prevents future JIT optimizations from assuming this final field is null.
        classLoader = loader;
    }
复制代码

阅读源码可得:

  • Class也是类,区别于class关键字
  • Class类构造方法是private,仅由JVM调用创建和加载

类加载

类加载机制图解

  • Java文件编译后会生成对应的class文件,里面记录着类一切的信息,jvm创建类都是依据Class对象来创建的
  • class文件在加载到内存中后,会生成唯一的Class对象,一个类全局仅存一个对应的Class对象

反射的基本使用

在Java中,Class类和java.lang.reflect类库共同支持反射技术

其中,Constructor类表示Class对象所表示类的构造方法,Field类表示成员变量,Method类表示成员方法等

方法介绍

方法说明
forName()(1)获取Class对象的一个引用,但引用的类还没有加载(该类的第一个对象没有生成)就加载了这个类。
(2)为了产生Class引用,forName()立即就进行了初始化。
Object-getClass()获取Class对象的一个引用,返回表示该对象的实际类型的Class引用。
getName()取全限定的类名(包括包名),即类的完整名字。
getSimpleName()获取类名(不包括包名)
getCanonicalName()获取全限定规范 的类名(包括包名,一般在log时使用)
isXXX()判断是否为某一类型,比如isInterface()是否为接口,isEnum()等
getXXX()获取类的某一个信息,比如getFiled(String name)获取名字为name的属性,getMethod(),getAnnotation()等
getXXXs()获取某个信息的数组,比如getInterfaces(),getMethods,getFileds() 注意:后两个方法会获取到包括父类所拥有的全部信息
getDeclredXXX/s()获取已经声明的信息,仅包含本类,不包含父类 ,比如:getDeclaredAnnotations() ,getDeclaredMethod()
newInstance()返回一个Oject对象,是实现“虚拟构造器”的一种途径。使用该方法创建的类,必须带有无参的构造器。

Class对象的读取

在类加载的时候,JVM会创建一个class对象 class对象是可以说是反射中最常用的,获取class对象的方式的主要有三种

  • 根据类名:类名.class
  • 根据对象:对象.getClass()
  • 根据全限定类名:Class.forName(全限定类名)
    tips:如果是加载内部类,格式为package.ClassName$InnerClass
        logger.info("根据类名: \t"+test.class);   //根据类名: 	class zjamss.test
        logger.info("根据对象: \t"+this.getClass());   //根据对象: 	class zjamss.test
        logger.info("根据全限定类名: \t"+Class.forName("zjamss.test"));    //根据全限定类名: 	class zjamss.test
        Class test = zjamss.test.class;
        // 常用的方法
        logger.info("获取全限定类名:\t" + test.getName());   //获取全限定类名:	zjamss.test
        logger.info("获取类名:\t" + test.getSimpleName());   //获取类名:	test
        logger.info("实例化:\t" + test.newInstance());   //实例化:	zjamss.test@17d10166
复制代码

Construct类及使用方法

Constructor类存在于反射包(java.lang.reflect)中,反映的是Class 对象所表示的类的构造方法。

    //Constructor使用
    @Test
    public void t2() throws Exception {
        Class<?> clazz = Class.forName("zjamss.reflect.User");
        User user = (User) clazz.newInstance();  //调用无参构造函数
        System.out.println(user);   //User{name='null', age=0}

        Constructor cs1 = clazz.getConstructor(int.class);
        User user1 = (User) cs1.newInstance(10);  //调用一个参数的构造函数
        System.out.println(user1);   //User{name='null', age=10}

        Constructor cs2 = clazz.getDeclaredConstructor(String.class,int.class);
        User user2 = (User) cs2.newInstance("12", 12);  //调用两个参数的构造函数
        System.out.println(user2);   //User{name='12', age=12}

        Constructor[] constructors = clazz.getDeclaredConstructors();  //获取User类里所有的构造方法
        for(Constructor constructor : constructors){
            System.out.print(constructor.toGenericString+":\t");
            Class[] parameterTypes = constructor.getParameterTypes();   //获取构造方法的所有形参类型
            for(Class param : parameterTypes){
                System.out.print(param.getCanonicalName()+"\t");
            }
            System.out.println();
        }
    }
    
                    //public zjamss.reflect.User(int):	int	
					//public zjamss.reflect.User(java.lang.String,int):	java.lang.String	int	
					//public zjamss.reflect.User():	
复制代码
        
public class User{
    private String name;
    public int age;

    public User() {
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
复制代码

Field类及其用法

Field 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。反射的字段可能是一个类静态字段或实例字段。

    //Field
    @Test
    public void t3() throws Exception{
        Class clazz = User.class;
        //获取指定字段名称且修饰符为public的字段  包括父类
        Field age = clazz.getField("age");
        System.out.println("age: "+age);   //age: public int zjamss.reflect.User.age

        //获取所有修饰符为public的字段  包括父类
        Field[] fields = clazz.getFields();
        for(Field field : fields){
            System.out.println(field.getName()+": "+field.getDeclaringClass());
             //age: class zjamss.reflect.User
			//score: class zjamss.reflect.User
        }

        //获取当前类所有字段
        Field[] declaredFields = clazz.getDeclaredFields();
        for(Field field : declaredFields){
            System.out.println(field.getName()+": "+field.getDeclaringClass());
            	//name: class zjamss.reflect.User
				//tel: class zjamss.reflect.User
                //age: class zjamss.reflect.User
				//score: class zjamss.reflect.User
        }

        //获取当前类指定字段,任意修饰符都可
        Field name = clazz.getDeclaredField("name");
        System.out.println(name.getName()+": "+name);   //name: private java.lang.String zjamss.reflect.User.name
    }
复制代码

上述方法需要注意的是,如果我们不期望获取其父类的字段,则需使用Class类的getDeclaredField/getDeclaredFields方法来获取字段即可,倘若需要连带获取到父类的字段,那么请使用Class类的getField/getFields,但是也只能获取到public修饰的的字段,无法获取父类的私有字段。

设置字段

        Class clazz = User.class;
        final Field name = clazz.getDeclaredField("name");
        final Constructor constructor = clazz.getConstructor(int.class);
        final User user = (User) constructor.newInstance(10);
        System.out.println(user);  //User{name='null', age=10}
        name.setAccessible(true); //解除private
        name.set(user,"name");
        System.out.println(user);  //User{name='name', age=10}
        System.out.println(name.get(user));  //name
复制代码

Method类及其用法

        Class clazz = User.class;
        //获取所有public的方法,包括父类
        Method[] methods =clazz.getMethods();
        for (Method m:methods){
            System.out.println("m::"+m);
        } 
        //m::public int zjamss.reflect.User.getAge()
        //m::public java.lang.String zjamss.reflect.User.toString()
        //m::public final void java.lang.Object.wait() throws java.lang.InterruptedException
        //m::public final void java.lang.Object.wait(long,int) throws java.lang.InterruptedException
        //m::public final native void java.lang.Object.wait(long) throws java.lang.InterruptedException
        //m::public boolean java.lang.Object.equals(java.lang.Object)
        //m::public native int java.lang.Object.hashCode()
        //m::public final native java.lang.Class java.lang.Object.getClass()
        //m::public final native void java.lang.Object.notify()
        //m::public final native void java.lang.Object.notifyAll()
        //获取当前类的方法包含private,该方法无法获取继承自父类的method
        Method method1 = clazz.getDeclaredMethod("display");
        System.out.println("method1::"+method1);  //method1::private void zjamss.reflect.User.display()
        method1.setAccessible(true);  //修改访问权限
        method1.invoke(clazz.newInstance());  //调用方法  User{name='null', age=0}  12

        Method method2 = clazz.getDeclaredMethod("getAge");
        System.out.println("method2:"+method2);  //method2:public int zjamss.reflect.User.getAge()
        int age = (int) method2.invoke(new User(12));  //获取方法返回值
        System.out.println(age);
        //获取当前类的所有方法包含private,该方法无法获取继承自父类的method
        Method[] methods1=clazz.getDeclaredMethods();
        for (Method m:methods1){
            System.out.println("m1::"+m);
        } 
        //m1::private void zjamss.reflect.User.display()
        //m1::public int zjamss.reflect.User.getAge()
        //m1::public java.lang.String zjamss.reflect.User.toString()
复制代码

反射的使用案例

Spring框架想必大家都耳熟能详了,是一个提供IOC和AOP支持等等的框架,那里面的IOC又是怎么实现的呢?其实就是反射,比如最使用的@Autowired注解,自动类型注入

简单来说,当spring扫描bean的时候,会获取一个bean的Class对象,然后获取所有的field,遍历查找属性上是否有@Autowired注解,如果有,则先设置Accessile为true,接着就将字段赋值为对应的bean对象

【嵌入式 – GD32开发实战指南(ARM版本)】第1部分 基础篇 - 第1章 开发环境搭建 开发环境: MDK:Keil 5.30 MCU:GD32F207IK 1.1 GD32F207I-EVAL开发板简介 笔者使用的开发板是兆易创新设计的GD32F207I-EVAL开发板。 GD32F207I-EVAL开发板使用 GD32F207IK作为主控制器,主频120MHz、集成3MB Flash、256KB SRAM、通用定时器*10、Adv. TM*2、Basic TM*2、系统时钟*1、看门狗*2、RTC*1、USART*4、UART*4、I2C*3、SPI*3、I2S*1、SDIO*1、CAN 阅读详情

相关推荐

RcisTarget实战:从差异基因到转录因子调控网络的完整分析流程(附代码)

本文详细介绍了RcisTarget工具在转录因子调控网络分析中的完整流程,从差异基因到motif富集分析,再到结果可视化与生物学解读。通过实战代码演示,帮助研究者掌握这一强大的R包应用,揭示基因表达背后的调控机制,特别适用于基因组学和生物信息学研究。

weixin_29214199的博客 228

Java注解反射例子

Java注解和反射 根据 https://blog.youkuaiyun.com/qq1404510094/article/details/80577555 这篇博客里的案例 自己敲了一遍 做个记录。 需要被测试的方法都写上了Test注解 public class Calculation { @Test public void add(){ System.out.println("add result: " + (1 + 0)); } @Test public void sub(){

qq_44304221的博客 244

SimpleFOC STM32实战:基于F103与HAL库,剖析速度环与电流环的协同控制

本文详细介绍了基于STM32F103与HAL库的SimpleFOC实战应用,重点剖析速度闭环控制与电流环的协同工作原理。通过开发环境搭建、参数调试技巧及性能优化方案,帮助开发者高效实现无刷电机精准控制,适用于机器人、无人机等高精度应用场景。

weixin_29170327的博客 478

java反射机制深入详解_Java反射机制深入详解

一.概念反射就是把Java的各种成分映射成相应的Java类。Class类的构造方法是private,由JVM创建。反射是java语言的一个特性,它允程序在运行时(注意不是编译的时候)来进行自我检查并且对内部的成员进行操作。例如它允许一个java的类获取他所有的成员变量和方法并且显示出来。Java 的这一能力在实际应用中也许用得不是很多,但是在其它的程序设计语言中根本就不存在这一特性。例如,Pasc...

weixin_39868959的博客 223

西电计组实验二 运算器实验

算术逻辑运算实验 一.实验目的   1.了解简单运算器的数据传输通路。   2.验证运算功能发生器的组合功能。   3.掌握算术逻辑运算加、减、与的工作原理。   4.验证实验台运算的8位加、减、与、直通功能。   5.按给定数据,完成几种指定的算术和逻辑运算。 二.实验原理   算术逻辑单元ALU的数据通路如图2-1所示。其中运算器ALU181根据74LS181的功能用VHDL硬件描述语言编辑而成,构成8位字长的ALU。参加运算的两个8位数据分别为A[7…0]和B[7…0],运算模式由S[3…0]的16种

Polaris的博客 1万+

使用gsplat进行3D高斯泼溅的方案

gsplat 不是一个软件,而是一个深度优化CUDA的开源Python库。它的作者是 Nerfstudio 团队,这个团队最出名的项目是 Nerfstudio,是对 NeRFs 方法支持最好的一套框架。据其所述,出于对新一代技术的好奇,他们构建了 gsplat 这个库。它支持 Windows/Linux 两个系统,使用前必须准备好 Nvidia 显卡。跑这个项目真是特别费劲,官方的文档支持不够完善,以至于遇到问题,开发者们都只能在issue区里抱团取暖。

兴趣使然的创作者 2111

Java反射详解,还有什么理由学不会?

logger.info("根据全限定类名: \t"+Class.forName("zjamss.test"));Class(java.lang)类 Java应用里每一个类或接口都是Class类的实例,每个Java类在jvm都表现为一个Class对象,基本数据类型和void数组也是Class类的对象。logger.info("获取全限定类名:\t" + test.getName());logger.info("获取类名:\t" + test.getSimpleName());//获取类名: test。...

m0_73257876的博客 107

数控系统(CNC)系列:Fanuc 31i-B_(16).CNC系统的网络连接与数据传输

硬件连接:包括网络接口的类型、连接方式等。网络协议:常用的网络协议包括Ethernet、Modbus TCP、Profinet等。网络配置:如何在CNC系统中配置网络参数,使其能够正确接入网络。在网络化的现代工业生产环境中,CNC系统的网络连接和数据传输能力变得越来越重要。通过以太网、Modbus TCP和Profinet等网络协议,可以实现CNC系统与上位机、其他CNC系统以及各种工业设备之间的高效通信。

2401_87715305的博客 2438

还在为学不会Java而找理由?别找了,这篇文章足够你学通Java了

老生常谈的一些问题,小编再和你们谈一谈! 现在的java在编程界基础已经根深蒂固了,随之带来的影响就是有大量的岗位,大量的工作方向,虽然现在很多的新兴语言势头都非常的猛烈,但是这并不影响java依然体量最大的编程语言,而且丝毫也看不出这门语言有任何衰减的趋势,依然有大量的从业人员在java开源领域贡献着大量的代码,在新兴的领域java切入进来也是毫不费力。 在目前阶段学习java,不存在晚与不...

李旭的博客 2133

六种光耦综合对比——《器件手册--光耦》

可控硅输出光耦(SCR Optocoupler)是一种特殊的光电耦合器,由红外发光二极管(LED)和双向可控硅(SCR)组成,用于实现输入和输出之间的电气隔离和信号传输。逻辑输出光耦是一种高效、可靠的数字信号隔离和电平转换器件,通过电气隔离和逻辑电平输出,确保了系统的安全性和信号的稳定性。固态继电器(可控硅输出,SSR)是一种无触点电子开关设备,利用可控硅(SCR或Triac)作为主要开关元件,通过光耦合器实现输入和输出之间的电气隔离。光耦作为一种成熟的电气隔离器件,在电子电路设计中具有重要的地位。

XU157303764的博客 1729

【教程4>第8章>第10节】OFDM完整通信链路项目的FPGA开发4——插入导频

本文介绍了基于MATLAB和Verilog的导频插入设计与实现方法。首先回顾了MATLAB中导频插入的算法实现,展示了每32个数据插入一个导频的设计。接着详细说明了Verilog硬件实现方案,包括导频序列定义、计数器设计、FIFO模块等关键部分。通过仿真测试验证了设计的正确性,输出了插入导频后的序列、导频序列以及调整时序后的序列。最后提供了相关视频教程资源,帮助读者理解设计过程。该设计实现了数据与导频的精确插入,为OFDM等通信系统开发提供了实用参考。

FPGA/MATLAB学习教程/源码/项目合作开发 396

再学Java基础——反射

Java中的反射(Reflection)是一种强大的工具,它允许程序在运行时检查类、接口、字段和方法的信息,并且允许对这些对象进行实例化、调用等操作。这种能力使Java代码具有高度的动态性和灵活性。

层楼终究误少年 331

21天学会基于 Linux 的 NPU 固件开发--2.2 固件加载流程:request_firmware() 深度解析

本文深度解析Linux内核中NPU固件加载流程,重点剖析request_firmware()机制。内容涵盖:1)内核态与用户态的交互机制,包括同步/异步加载方式;2)NPU固件的特殊格式与加载逻辑;3)调试技巧与安全验证方案;4)提供最小化固件加载器实验。文章揭示了从文件系统到硬件初始化的完整链路,探讨了大模型时代面临的性能挑战与优化方案,如零拷贝加载技术,并提出了版本兼容性、断电恢复等关键问题的思考方向。

amy_mhd的博客 59

Java反射

在学习Java基础的时候,一般都会学过反射。我在初学反射的时候,并不能理解反射是用来干嘛的。学了一些API发现:“明明我自己能直接new一个对象,为什么它要绕一个圈子,先拿到Class对象,再调用Class对象的方法来创建对象呢,这不是多余吗?” 我现在认为用反射主要有两个原因: 提高程序的灵活性 屏蔽掉实现的细节,让使用者更加方便好用 理由很简单,人们不想修改代码。只要存在有变动的地方,我写在配置里边,不香吗?但凡有一天,我的username,password,url甚至是数据库都改了,我都能够通过修改配

weixin_48669196的博客 122

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

Java进阶篇之反射

反射就好比自己与镜子里的自己,镜子里可以折射出自己的身影。用Java的话说就是指对于任何有个Class类,在"运行的时候"都可以直接得到这个类的全部成分。

weixin_54679968的博客 578

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

反射为什么慢?

平时在反射这块用的比较少,也没针对性的去学习一下。在工作之余,还是得保持一个学习的习惯,这样子才不会出现今天这种被一个问题难倒的情况,而且才能产出更多、更优秀的方案。

IT枫斗者的博客 984

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

当Java反射遇到了类加载器

以前经常偷懒用反射实现一些方便的功能()

Kotlin 1797

反射详解~Go进阶

Go语言的反射就是建立在类型之上的,Golang的指定类型的变量的类型是静态的(也就是指定int、string这些的变量,它的type是static type),在创建变量的时候就已经确定,反射主要与Golang的interface类型相关(它的type是concrete type),只有interface类型才有反射一说。当向接口变量赋予一个实体类型的时候,接口会存储实体的类型信息,反射就是通过接口的类型信息实现的,反射建立在类型的基础上。value是实际变量值,type是实际变量的类型。

m0_63230155的博客 595

深入理解Java中的反射技术

在 Java 中的反射机制是指在运行状态中,对于任意一个类都能够知道这个类所有的属性和方法;并且对于任意一个对象,都能够调用它的任意一个方法;这种动态获取信息以及动态调用对象方法的功能成为 Java 语言的反射机制。 文章目录 ...

wh柒八九的博客 348

Java反射、类加载、初始化 【java基础-反射】

Java反射、类加载、初始化 【java基础-反射】

伟庭的博客 1307

Java语法基础:反射reflect

Java中的反射是非常重要的一部分,很多框架主要也是应用了反射和设计模式,所以深入了解Java的反射实在Java的基础学习中非常重要的一部分。

Hicodden的博客 282

Java基础加强第二讲 反射(下)——数组的反射

具有相同维数和元素类型的数组属于同一个类型,即具有相同的Class实例对象(此处比较与值无关)。例如, 此处,我再介绍两个方法,如下: 方法 描述 public String getName() 以String的形式返回此Class对象所表示的实体(类、接口、数组类、基本类型或void)名称 public Class&amp;amp;lt;? super T&amp;amp;gt; getSuperclas...

李阿昀的博客 1392

【重难点】【Java基础 05】说一说你平时遇到的异常、什么情景下会用到反射、反射的底层原理

说一说你平时遇到的异常、什么情景下会用到反射、反射的底层原理

2022年毕业的萌新程序猿,输出一下自己的学习内容~ 549

JAVA反射机制

正常的JAVA编程情况,我们只是对源码进行操作编程。而反射机制的存在,使得我们可以对JAVA字节码进行操作,就是我们编写的JAVA反射源码是对JAVA程序运行时的对象进行操作。   反射(Reflection)能够让运行于JVM中的程序检测和修改运行时的行为(官网解释-http://docs.oracle.com/javase/tutorial/reflect/index.html:Ref...

ghods的专栏 132

【Go语言反射reflect】

不同语言的反射模型不尽相同,有些语言还不支持反射。《Go 语言圣经》中是这样定义反射的:Go 语言提供了一种机制在运行时更新变量和检查它们的值、调用它们的方法,但是在编译时并不知道这些变量的具体类型,这称为反射机制。为什么要用反射。

m0_46168848的博客 1312

Java反射源码学习之旅 | 京东云技术团队

在我刚开始了解反射这个Java特性的时候,几乎看到的每一篇文章都会有“Java反射不能频繁使用”、“反射影响性能”之类的话语,当时只是当一个结论记下了这些话,却没有深究过为什么,所以正好借此机会来探究一下Java反射的代码。

JDDTechTalk的博客 689
上一篇: 金九银十:20道前端手写面试题
下一篇: Alibaba架构师纯手工打造神仙级“2022版Java面试手册”
程序员职业指南
博客等级 码龄4年 2138粉丝 960原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值