十、《面向对象-封装》“二“

本文详细介绍了Java中的包、封装和this关键字。包通过类似文件夹的方式来方便管理和避免类名冲突,遵循公司域名反写规则进行命名。封装是面向对象的核心特性,用于保护内部数据安全,通过访问权限修饰符实现。this关键字用于指代当前对象,解决成员变量和局部变量的二义性,以及在构造方法间的调用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、包(package)

1.1 包的引入

先来看看我们之前写的代码结构(采用Eclips)

代码结构存在以下问题:

  1. 所有类写在一个目录下面,非常难管理,因为以后项目不可能只有这么几个类,当类数量很大的时候,就不容易管理了。
  2. 不能写同名但是不同需求的类。

那么我们要怎么解决这些问题呢?

我们可以通过生活中例子来获取经验,例如:假设我们有很多电影资源,那么我们是怎么管理这些片的?

通过文件夹

        国产

        欧美

                爱情

                动作

                恐怖

        日韩

                爱情

                动作

                恐怖

          …

所以,为了解决这些问题,我们就必须也要通过文件夹来完成管理。Java中的文件夹就是,所以接下来我们要学习一下

1.2 包package概念

概念:简单的理解包就是一个文件夹。

1.3 包作用

方便管理项目中的类等文件。

② 可以避免类名冲突的问题

1.4 如何使用包

1.4.1 定义包

包命名规范:一般是公司域名反写.项目名.模块名字.子模块名;

要求:包名是全英文小写。

例如 : xianshu.cn 域名

package  cn.xianshu.erp.oa.domain;自动化办公

package  cn.xianshu.erp.sa.entity; 系统管理

注意:不要写成nc.

// 例如:
package cn.xianshu.packagedemo; // 声明包

/**
 * 包package
 */
public class PackageDemo {

	public static void main(String[] args) {
		new java.util.Date();
		new java.sql.Date(1L);
		System.out.println();
	}
}

1.4.2 导入包

为什么要导包?

当我们需要使用别人或者JDK中的类的时候,就需要告知JVM从什么地方去加载这个类,这个过程就是导包

其实本质是导入包中的类。

导入包的语法 : import 包名.子包名.类名;

注意: 

  1. 导入包的代码应该在声明包(就是该类所在的包)的后面,声明类的前面。
  2. import java.util.*;  表示导入本包中所有会使用到的util包中的类,只会导入util包下面直接的类型,不包括util包的子包中的类型。
  3. java.lang是核心包,下面的直接类型是自动导入的;

例如:String、System类,lang包的子包中的类型不会自动导入,需要手动导入。

  1. 在一个类中会用到同名不同包的时候必须使用全限定路径

例如:同时使用java.util.Date和java.sql.Date

// 例如:
package cn.xianshu.packagedemo; //声明包
import java.util.*; // 只会导入util包下使用到的类

/**
 * 包package
 */
public class PackageDemo {

	public static void main(String[] args) { // String是java.lang核心包下的,程序会自动导入;
		// 使用Arrays类中的toString方法
//		String str = java.util.Arrays.toString(new int[]{1, 2, 3}); // 每次都写全限定类名比较麻烦
		
		// 使用Arrays类中的sort方法排序
//		java.util.Arrays.sort(new int[]{3, 2, 1});
		
		// 用自动导包可以简化上面代码
		String str = Arrays.toString(new int[]{1, 2, 3}); // 每次都写全限定类名比较麻烦
		System.out.println(str);
		Arrays.sort(new int[]{3, 2, 1});
		
		// 当使用同名不同包的多个类怎么用? 必须用全限定类名
		new java.util.Date(); // java.util包下
		new java.sql.Date(1L); // java.sql包下
	}

}

1.5 Java中的包

  •         java/ javax(java增强包)

        java.lang (java的核心包--基本包)

        java.util(java的工具包 --集合框架ArrayList LinkedList)

        java.io(java IO包input-output 读写文件)

        java.net(网络编程)

        java.awt/javax.swing(java的图形化界面)

        java.math 数学相关的包

        java.sql  数据库相关的包

        java.text 是文本格式化相关的包

        java.time 时间相关的包

2. 封装

2.1 为什么要封装?

先来下面一个案例:

package cn.xianshu.potting1;

/**
 *	账户Account类
 *	封装引入
 */
public class Account {
	/** String类型成员变量姓名name */
	protected String name;
	
	/** String类型成员变量密码password */
	String password;
	
	/** double类型成员变量余额money */
	double money;
	
	/** boolean类型成员变量是否是vip用户 */
	boolean vip;
	
	/**
	 * Account类无参构造
	 */
	public Account() {}
	
	/**
	 * 有4个参数构造方法
	 * @param n
	 * @param p
	 * @param m
	 * @param v
	 */
	public Account(String n, String p, double m, boolean v) {
		name = n;// 将局部变量n赋值给成员变量name
		password = p;// 将局部变量p赋值给成员变量password
		money = m;// 将局部变量m赋值给成员变量money
		vip = v;// 将局部变量v赋值给成员变量vip
	}
	
	/**
	 * 获取当前成员变量money的值
	 * @return
	 */
	public double getMoney() {
		return money;
	}
}

测试类: 

package cn.xianshu.potting1;

/**
 *	Account测试类
 *	封装的引入
 */
public class AccountTest {

	public static void main(String[] args) {
		// 创建Account对象,调用无参构造
		Account acc1 = new Account();
		// 给acc1成员变量赋值
		acc1.name = "某菲";
		acc1.password = "6969";
		acc1.money = 1.0;
		acc1.vip = false;
		// 打印acc1成员变量的值
		System.out.println(acc1.name);
		System.out.println(acc1.password);
		System.out.println(acc1.money);
		System.out.println(acc1.vip);
		// acc1调用getMoney方法
		double money = acc1.getMoney(); // 因为getMoney方法是非static修饰,并且有返回值,所以用acc1调用,用double变量接收
		System.out.println(money);
		
		// 需求:当money达到50000.00的时候,会将vip升级为true。现在,能不能没有达到5万就不能升级。 
		acc1.vip = true; // 这里没有经过任何权限判断,直接修改了值,不安全。所以,用封装解决这个问题。
		System.out.println(acc1.vip); // true
		
	}
}

出现上面测试类中的需求的时候,我们原来设计类的方式就不能满足需求了。那么我们怎么解决这个问题呢?

我们先来看看生活中我们是怎么解决类似问题的

  1. 大家想一想生活中封装是什么? 

例如:

  1. 网购一个娃娃我们都会发现,娃娃邮寄的时候,都是用箱子装起来。箱子是保护里面娃娃安全的。
  2. 台式机电脑,我们发现[主板、显卡、内存、电源、硬盘…]都是装在机箱中,其实机箱不是电脑运行必须的,那么其作用是什么呢?机箱是保护里面硬件的安全。

以上示例的共同点总结:

都是通过物理方式封装的操作,通过控制访问的方式达到保护内部成员的目的

而Java中是通过封装来完成保护内部成员的目的,所以,这就是我们学习封装的目的

2.2 封装作用

封装是为了保护内部数据的安全:

        1. 不希望在外部类中随意访问类中的成员变量

        2. 达到权限要求的才能访问。

        3. 只是获取数据的时候。例如:单例模式。

2.3 怎么封装

  1. 如何控制程序中的访问 ?

通过给类中的成员(字段,方法,构造方法)添加访问权限修饰符来实现封装(访问控制)。

  1. 什么是访问权限:简单的认为访问权限就是不同级别的人能够干不同级别的事,不同级别的人能看到的页面是不同的。

例子:比如做一个系统,不同人登录进去的访问权限不一样;

3. 访问权限修饰符:

public 最大权限,被其修饰的成员,在任意目录下,都可以访问到 (所有类)

protected 在同包类和子类中都可以访问

默认不写 只能在同包类中访问

private 只能在当前类中访问

2.4 封装的步骤

步骤:

1. 私有化成员变量(用private修饰成员变量)

2. 为每一个成员变量提供合理的public修饰的:

getXxx()方法 获取成员变量的值,如果当前成员变量类型是boolean类型,将getXxx()改为isXxx()

setXxx(...)方法 设置成员变量的值

3. 提供一个无参构造有参构造根据需求确定是否要写。

4. 该类用public修饰。

封装案例:

public class Account { // 4. 该类用public修饰
	/** String类型成员变量姓名name  1. 私有化成员变量(用private修饰成员变量)*/
	private String name;
	
	/** String类型成员变量密码password 1. 私有化成员变量(用private修饰成员变量)*/
	private String password;
	
	/** double类型成员变量余额money  1. 私有化成员变量(用private修饰成员变量)*/
	private double money;
	
	/** boolean类型成员变量是否是vip用户  1. 私有化成员变量(用private修饰成员变量)*/
	private boolean vip;
	
	/**
	 * 3. 提供一个无参构造
	 * Account类无参构造
	 */
	public Account() {}
	
	/**
	 * 有参构造根据实际需求,决定是否要写
	 * 有4个参数构造方法
	 * @param n
	 * @param p
	 * @param m
	 * @param v
	 */
	public Account(String n, String p, double m, boolean v) {
		name = n; // 将局部变量n赋值给成员变量name
		password = p; // 将局部变量p赋值给成员变量pwd
		money = m; // 将局部变量m赋值给成员变量money
		vip = v; // 将局部变量v赋值给成员变量vip
	}
	
	/**
	 *  2. 为每一个成员变量提供合理的public void setName(String n)方法
	 * 	给成员变量name赋值方法
	 * @param n
	 */
	public void setName(String n) {
		// 可以写判断条件
		name = n; // 将局部变量n赋值给成员变量name
	}
	
	/**
	 *  2. 为每一个成员变量提供合理的	public void setpassword(String p)方法
	 * 	给成员变量password赋值方法
	 * @param p
	 */
	public void setpassword(String p) {
		// 可以写判断条件
		password = p; // 将局部变量p赋值给成员变量pwd
	}
	
	/**
	 *  2. 为每一个成员变量提供合理的	public void setMoney(double m) 方法
	 * 	给成员变量money赋值方法
	 * @param m
	 */
	public void setMoney(double m) {
		// 可以写判断条件
		money = m; // 将局部变量m赋值给成员变量money
	}
	
	/**
	 *  2. 为每一个成员变量提供合理的	public void setVip(boolean v) 方法
	 * 	给成员变量vip赋值方法
	 * @param v
	 */
	public void setVip(boolean v) {
		// 可以写判断条件
		vip = v; // 将局部变量v赋值给成员变量vip
	}
	
	/**
	 * 2. 为每一个成员变量提供合理的	public String getName() 方法
	 * 获取成员变量name的值
	 * @return
	 */
	public String getName() {
		// 可以写判断条件
		return name; // 直接返回成员变量name
	}
	
	/**
	 * 2. 为每一个成员变量提供合理的	public String getPwd() 方法
	 * 获取成员变量pwd的值
	 * @return
	 */
	public String getpassword() {
		// 可以写判断条件
		return password; // 直接返回成员变量pwd
	}
	
	/**
	 * 2. 为每一个成员变量提供合理的	public double getMoney() 方法
	 * 获取成员变量money的值
	 * @return
	 */
	public double getMoney() {
		// 可以写判断条件
		return money; // 直接返回成员变量money
	}
	
	/**
	 * 2. 为每一个成员变量提供合理的	public boolean isVip() 方法
	 * 获取当前成员变量vip的值。如果当前成员变量类型是boolean类型,将getXxx()改为 isXxx()
	 * @return
	 */
	public boolean isVip() {
		// 可以写判断条件
		return vip; // 直接返回成员变量vip
	}
}

测试案例:

/**
 *	Account测试类
 *	封装的引入
 */
public class AccountTest {

	public static void main(String[] args) {
		// 创建Account对象,调用无参构造
//		Account acc1 = new Account();
		// 给acc1成员变量赋值
		/*
		 * 因为private修饰成员变量后,不能在其他类中使用了。
		acc1.name = "某菲";
		acc1.password = "6969";
		acc1.money = 1.0;
		acc1.vip = false;
		*/
		// 使用有参构造赋值
		Account acc1 = new Account("某菲", "6969", 1.0, false);
		
		// 打印acc1成员变量的值
//		System.out.println(acc1.name); // 因为private修饰成员变量后,不能在其他类中使用了。
//		System.out.println(acc1.pwd);
//		System.out.println(acc1.money);
//		System.out.println(acc1.vip);
		
		// 因为封装了,所以只能调用:public 返回值 getXxx() 获取成员变量的值
		String name = acc1.getName(); // acc1调用getName方法获取成员变量name的值
		String password = acc1.getpassword(); // acc1调用getPwd方法获取成员变量pwd的值
		double money = acc1.getMoney(); // acc1调用getMoney方法获取成员变量money的值
		boolean vip = acc1.isVip(); // acc1调用isVip方法获取成员变量vip的值
		// 打印上面获取的值
		System.out.println(name);
		System.out.println(password);
		System.out.println(money);
		System.out.println(vip);
		
		// 当需要修改创建好的对象的成员变量值,怎么办?用setXxx方法赋值
		acc1.setMoney(50000);// acc1调用setMoney方法给成员变量money赋值,值随便写一个即可
		acc1.setVip(true);// acc1调用setVip方法给成员变量vip赋值,值随便写一个即可
		
		// 重新调用getXxx()或者 isXxx() 方法获取上面修改的成员变量值
		// acc1调用getMoney方法
		double money2 = acc1.getMoney();// 因为getMoney方法是非static修饰,并且有返回值,所以用acc1调用,用double变量接收
		System.out.println(money2);
		
		// acc1调用isVip方法
		boolean vip2 = acc1.isVip();// 因为isVip方法是非static修饰,并且有返回值,所以用acc1调用,用boolean变量接收
		System.out.println(vip2);
		
	}

}

2.5 封装的注意事项

1. 不是只有private才叫封装,private只是最大限度的封装而已。

2. get和set方法都是只能获取或者赋值一个成员变量,不能set(String n, double m, boolean v)赋值3个成员变量。

3. 单一职能原则:功能最小化,不要想着一个方法写完所有的功能,因为代码复用率高。

2.6 封装小结

对象赋值的方式:

1. 有参构造 :new 类名(...);

2. 对象名.setXxx(...);

3. 对象名.成员变量 = 值; // 封装后不能用

一般配合使用,如果成员变量比较少,可以直接用有参构造。

如果成员变量比较多,一般用无参构造 + setXxx(...)。

如果对象已经创建,需要修改值,用setXxx(...)。

  1. 对象取值的方式:

  1. 对象名.getXxx(); // 对象名.isXxx()

  2. 对象名.成员变量 ; // 封装后不能用

3. this

3.1 this引入

先看我们上面写的代码,在有参构造和setXxx方法中形参应该按照见名知意原则来写,代码如下:

public class Student {
	private String name;
	public Student() {}
	
	public String getName() {
		return name;
	}
	public void setName(String name) { // name按照简明知意原则,应该将n改为name
		name = name;
	}
}

测试类:

public class StudentTest {

	public static void main(String[] args) {
		// 调用有参构造,创建对象并且直接赋值
		Student stu = new Student();
		stu.setName("隔壁老王");
		System.out.println(stu.getName()); // null(发现赋值是失败的,取的是默认值null)
	}
}

这是为什么呢?请看内存分析图

根据内存图,我们知道这是就近原则造成的,但是我们必须要解决这个问题。

那么我们怎么解决这个问题呢? 使用this

3.2 this介绍

  1. this的概念:this指代当前对象,即,哪个对象调用就指代哪个对象。
  2. this理解示意图:

        3. 测试this

public class Student {
	public void printThis() {
		System.out.println("this = " + this);
	}
}

 测试类:

public class StudentTest {

	public static void main(String[] args) {
		/*
		 * this表示的是当前对象,可看成this就是指代当前对象的地址; 
		 */
		Student stu1 = new Student();
		System.out.println("stu1= " + stu1);
		stu1.printThis(); // this所在方法正在被stu1调用 则 this指代stu1的地址

		// this指代当前对象,换了其他对象,this代表的就是其对象了
		Student stu2 = new Student();
		System.out.println("stu2= " + stu2);
		stu2.printThis(); // this所在方法正在被stu2调用 则 this指代stu2的地址	
	}
}
/**
打印结果:
stu1 = Student@15db9742
this = Student@15db9742
stu2 = Student@6d06d69c
this = Student@6d06d69c
 */

3.3 this使用

  1. 解决局部变量和成员变量的二义性set方法和有参构造中形参跟成员变量同名不同义
// 例如:
public Account(String name) {
	// 在方法中使用变量的时候,优先从局部范围找,就近原则
	// 这里因为成员变量和局部变量名字相同,存在二义性问题
	// 要解决二义性问题,就需要用到this,加上this,就会直接从成员变量位置找name
	this.name = name;
}

        2.本类中构造方法之间的相互调用,但是必须是构造方法内的第一句

/**
语法:this(...); 调用本类中的另一个构造方法,并不会创建额外的对象,会根据参数自动匹配调用对应的构造方法。
作用:
	1.可以创建对象的时候,给定某些成员变量默认值
	2.可以复用其它构造方法,简化给成员变量赋值的代码
例如:
*/
// 1.可以创建对象的时候,给定某些成员变量默认值
public Account(String name) {
	// name和111111都是String类型,只不过name是一个变量,而111111是一个写死的值
	// 并通过该构造方法创建的对象都有相同的   【默认密码】
	this(name,"111111"); // 必须是构造方法内的第一句,这里调用的是有两个String参数的构造方法
}
public Account(String name,String password) {
	// 要解决二义性问题,就需要用到this,加上this,就会直接从成员变量位置找name
	this.name = name;
	this.pwd = password;
}
			
// 2.可以复用其它构造方法,简化给成员变量赋值的代码
public Account(String name, String password, double money) {
	/*
		this.name = name;
		this.password = password;
		可以使用下面的方式,this(...)简化代码
	 */
	this(name, password);// 复用上面的有两个String参数的构造方法,简化代码作用
	this.money = money;
}

 

 3.4 this注意和小结

  1. this用途:
  1. 解决局部变量和成员变量的二义性
  2. 在本类之间构造方法之间的相互调用this()调用无参数的构造方法,this(...)可以添加参数,表示调用有参数的构造方法 
  3. this作为参数传递,this作为返回值 
  1. this注意事项:
  1. this不能在静态的方法中使用: 无法从静态上下文中引用非静态成员this
  2. static是级别,this是对象级别

static修饰的是属于类。

this是属于某一个具体的对象。

3.5 this综合代码案例

package cn.xianshu.this3;

/**
 *	账户Account类
 *  this
 */
public class Account {// 4. 该类用public修饰
	/** String类型成员变量姓名name  1. 私有化成员变量(用private修饰成员变量)*/
	private String name;
	
	/** String类型成员变量密码pwd  1. 私有化成员变量(用private修饰成员变量)*/
	private String pwd;
	
	/** double类型成员变量余额money  1. 私有化成员变量(用private修饰成员变量)*/
	private double money;
	
	/** boolean类型成员变量是否是vip用户  1. 私有化成员变量(用private修饰成员变量)*/
	private boolean vip;
	
	/**
	 * 3. 提供一个无参构造
	 * Account类无参构造
	 */
	public Account() {}
	
	/**
	 * 有2个String参数的构造方法,一个参数是name,一个参数是pwd
	 * @param name
	 * @param pwd
	 */
	public Account(String name, String pwd) {
		/*
		 *  因为就近原则,导致使用变量的时候,优先从局部范围查找,如果找到了,就直接使用,没找到才从成员变量查找
		 *  这里将将局部变量赋值给成员变量就会存在二义性问题,解决方案:在成员变量前加上: this.
		 */
		this.name = name;// 将局部变量name赋值给成员变量name,使用this解决了成员变量和局部变量二义性
		this.pwd = pwd;// 将局部变量pwd赋值给成员变量pwd,使用this解决了成员变量和局部变量二义性
	}

	/**
	 * 有参构造根据实际需求,决定是否要写
	 * 有4个参数构造方法
	 * @param name
	 * @param pwd
	 * @param money
	 * @param vip
	 */
	public Account(String name, String pwd, double money, boolean vip) {
		/*
		 *  因为就近原则,导致使用变量的时候,优先从局部范围查找,如果找到了,就直接使用,没找到才从成员变量查找
		 *  这里将将局部变量赋值给成员变量就会存在二义性问题,解决方案:在成员变量前加上: this.
		 */
		/*this.name = name;// 将局部变量name赋值给成员变量name
		this.pwd = pwd;// 将局部变量pwd赋值给成员变量pwd
		用this()第二种用法简化上面成员变量赋值代码: this(...); 表示在调用当前类中另外一个定义好的构造方法,调用的时候,会根据传入的实参自动匹配调用
		注意:this(...)只能在构造方法第一行。this()调用构造方法不会创建额外的对象,只是简化代码
		 */		
		this(name, pwd);// this(name, pwd);表示在调用上面2个String参数的构造方法
		this.money = money;// 将局部变量m赋值给成员变量money
		this.vip = vip;// 将局部变量v赋值给成员变量vip
	}
	
	/**
	 *  2. 为每一个成员变量提供合理的public void setName(String name)方法
	 * 	给成员变量name赋值方法
	 * @param name
	 */
	public void setName(String name) {
		// 可以写判断条件
		this.name = name;// 将局部变量name赋值给成员变量name
	}
	
	/**
	 *  2. 为每一个成员变量提供合理的	public void setPwd(String pwd)方法
	 * 	给成员变量pwd赋值方法
	 * @param pwd
	 */
	public void setPwd(String pwd) {
		// 可以写判断条件
		this.pwd = pwd;// 将局部变量pwd赋值给成员变量pwd
	}
	
	/**
	 *  2. 为每一个成员变量提供合理的	public void setMoney(double money) 方法
	 * 	给成员变量money赋值方法
	 * @param money
	 */
	public void setMoney(double money) {
		// 可以写判断条件
		this.money = money;// 将局部变量money赋值给成员变量money
	}
	
	/**
	 *  2. 为每一个成员变量提供合理的	public void setVip(boolean vip) 方法
	 * 	给成员变量vip赋值方法
	 * @param vip
	 */
	public void setVip(boolean vip) {
		// 可以写判断条件
		this.vip = vip;// 将局部变量vip赋值给成员变量vip
	}
	
	/**
	 * 2. 为每一个成员变量提供合理的	public String getName() 方法
	 * 获取成员变量name的值
	 * @return
	 */
	public String getName() {
		// 可以写判断条件
		return name;// 直接返回成员变量name
	}
	
	/**
	 * 2. 为每一个成员变量提供合理的	public String getPwd() 方法
	 * 获取成员变量pwd的值
	 * @return
	 */
	public String getPwd() {
		// 可以写判断条件
		return pwd;// 直接返回成员变量pwd
	}
	
	/**
	 * 2. 为每一个成员变量提供合理的	public double getMoney() 方法
	 * 获取成员变量money的值
	 * @return
	 */
	public double getMoney() {
		// 可以写判断条件
		return money;// 直接返回成员变量money
	}
	
	/**
	 * 2. 为每一个成员变量提供合理的	public boolean isVip() 方法
	 * 获取当前成员变量vip的值。如果当前成员变量类型是boolean类型,将getXxx()改为 isXxx()
	 * @return
	 */
	public boolean isVip() {
		// 可以写判断条件
		return vip;// 直接返回成员变量vip
	}
}

测试代码:

package cn.xianshu.this3;

/**
 *	Account 中this测试类
 */
public class AccountTest {

	public static void main(String[] args) {
		// 使用有参构造赋值
		Account acc1 = new Account("某菲", "6969", 1.0, false);
		
		String name = acc1.getName();// acc1调用getName方法获取成员变量name的值
		String pwd = acc1.getPwd();// acc1调用getPwd方法获取成员变量pwd的值
		double money = acc1.getMoney();// acc1调用getMoney方法获取成员变量money的值
		boolean vip = acc1.isVip();// acc1调用isVip方法获取成员变量vip的值
		// 打印上面获取的值
		System.out.println(name);
		System.out.println(pwd);
		System.out.println(money);
		System.out.println(vip);
		
		// 当需要修改创建好的对象的成员变量值,怎么办?用setXxx方法赋值
		acc1.setMoney(50000);// acc1调用setMoney方法给成员变量money赋值,值随便写一个即可
		
		// 重新调用getXxx()或者 isXxx() 方法获取上面修改的成员变量值
		// acc1调用getMoney方法
		double money2 = acc1.getMoney();// 因为getMoney方法是非static修饰,并且有返回值,所以用acc1调用,用double变量接收
		System.out.println(money2);
		
	}

}

下一章   十一、《面向对象-继承、抽象、方法重写》"三"

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值