黑马程序员--集合(二)

黑马程序员--集合(二)

------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

一、泛型

1、定义
泛型(generic):一般的。JDK1.5版本以后出现的新特性。用于解决安全问题,是一个类型安全机制。
格式:通过<>来定义要操作的引用数据类型。<>就是用来接收类型的。

PS:
由来:借鉴数组的定义和操作。
JDK1.5之前定义Object来完成扩展(存在强制问题),现在定义泛型来完成扩展。
2、好处:
2.1 将运行时期出现问题,转移到了编译时期。方便于程序员解决问题,让运行时期问题减少,安全。
2.2 避免了强制转换麻烦。

一般方法:

import java.util.*;
class GenericDemo1
{
	public static void main(String[] args)
	{
		ArrayList al = new ArrayList();

		al.add("abc01");
		al.add("abc0234");
		al.add("abc012");

		//同时存入字符串和数字时,存在类型转换异常。
		al.add(4);

		for(Iterator it = al.iterator();it.hasNext();)
		{
			//向下转型。使用自定义内容。
			String s = (String)it.next();
			System.out.println(s+".."+s.length());
		}
	}
}
运行结果:

泛型方法:

import java.util.*;
class GenericDemo
{
	public static void main(String[] args)
	{
		/*
		在集合定义时就定义数据类型,这样就把不同类型的数据区分开,防止类型转换异常。
		这样的做法借鉴了数组格式。有利于将运行时期出现问题,转移到编译时期。
		*/
		ArrayList<String> al = new ArrayList<String>();

		al.add("abc01");
		al.add("abc0234");
		al.add("abc012");

		//同时存入字符串和数字时,存在类型转换异常。
		al.add(4);//al.add(new Integer(4));

		//指定迭代器类型,避免强转问题。
		for(Iterator<String> it = al.iterator();it.hasNext();)
		{
			String s = it.next();

			System.out.println(s+".."+s.length());
		}
	}
}
运行结果:

3、应用:
3.1 定义在集合框架中。通常在集合框架中很常见。只要见到<>就要定义泛型。
3.2 定义在接口上
3.3 定义在类中。当类中要操作的引用数据类型不确定的时候(注意:基本数据不确定无法自定义)。
3.3.1 泛型类存在局限性。因为方法接收的对象类型依据是对象定义的类型,所以一旦对象定义好类型,
方法接收的对象类型也将被固定。
3.3.2 泛型定义在方法上:可操作不同数据类型。它可以避免泛型类的局限性。
格式:放在返回值类型前、修饰符后。
3.3.3 静态方法不可以访问类上定义的泛型。因为它优先于对象加载。
如果静态方法操作的应用数据类型不确定,可以将泛型定义在方法上。

//泛型类。适用于当类中要操作的引用数据类型不确定的时候(注意:基本数据不确定无法自定义)。
class Demo<T> 
{
	public void show(T t)
	{
		System.out.println("show:"+t);
	}
	//方法上定义泛型:可操作不同数据类型。
	public <Q> void print(Q q)
	{
		System.out.println("print:"+q);
	}
	//将泛型定义在静态方法上
	public static <W> void method(W t)
	{
		System.out.println("method:"+t);
	}
}
class GenericDemo2
{
	public static void main(String[] args)
	{
		Demo<Integer> d = new Demo<Integer>();
		//泛型类的局限性
		//d.show("hah");
		d.show(4);

		d.print("hehe");
		d.print(4);
	
		//调用静态方法
		Demo.method("dhdh");
	}
}
运行结果:

3.4 ? 通配符。可理解为占位符。它用于定义泛型未明确的类型。
3.4.1泛型的高级应用
泛型限定 作用:用于功能扩展。
? extends E:可接收E类型或E的子类型。 上限。
? super E:可接收E类型或E的父类型。 下限。

//泛型限定
import java.util.*;
class Person
{
	private String name;
	Person(String name)
	{
		this.name = name;
	}
	public String getName()
	{
		return name;
	}
} 
class Student extends Person
{
	Student(String name)
	{
		super(name);
	}	 
}
//泛型下限应用,扩展了数据类型
class Comp implements Comparator<Person>//<? super E>
{
	public int compare(Person s1,Person s2)
	{
		return s1.getName().compareTo(s2.getName());
	}
}
class GenericDemo3
{
	public static void main(String[] args)
	{
		ArrayList<Person> al = new ArrayList<Person>();

		al.add(new Person("abc1"));
		al.add(new Person("abc2"));
		al.add(new Person("abc3"));

		//printColl(al);

		ArrayList<Student> al1 = new ArrayList<Student>();

		al1.add(new Student("abc---1"));
		al1.add(new Student("abc---2"));
		al1.add(new Student("abc---3"));

		printColl(al1); 

		TreeSet<Student> ts = new TreeSet<Student>(new Comp());
		ts.add(new Student("abc1"));
		ts.add(new Student("abc2"));
		ts.add(new Student("abc3"));

		//下限-->只接受Student及其父类。
		for(Iterator<? super Student> it = ts.iterator();it.hasNext();)
		{
			System.out.println(it.next());
		}
	}
	//上限-->只接受Person及其子类。
	public static void printColl(ArrayList<? extends Person> al)
	{
		for(Iterator<? extends Person> it = al.iterator();it.hasNext();)
		{
			System.out.println(it.next().getName());
		}
	}
}
运行结果:

二、Map集合


1、Map集合:双列集合,该集合存储键值对。必须保证键的唯一性。Collection单列集合,一次添加一个元素。
2、常用方法:
2.1 添加
value put(key,value):返回前一个和key关联的值,如果没有返回null。
putAll(Map<? extends K,? extends V> m)
2.2 删除
void clear():清空集合。
value remove(Object key):根据指定的key删除这个键值对。
2.3 判断
boolean containsValue(Object value);
boolean containsKey(Object key);
boolean isEmpty();
2.4 获取
value get(Object key):通过获取值,如果没有该键返回null。
int size():获取键值对个数。

Collection<> Values():返回键值对值。

//Map集合常见用法:
import java.util.*;
class MapDemo
{
	public static void main(String[] args)
	{
		Map<String,String> map = new HashMap<String,String>();

		//put()返回值为V,add()返回值为boolean。添加相同的键时,后添加的值会覆盖并返回

原有键对应值。
		sop("put:"+map.put("01","dou"));
		sop("put:"+map.put("01","bi"));
		map.put("02","ni");
		map.put("03","zhen");
		map.put("04","dour");
		
		//删除
		sop("remove:"+map.remove("01"));
		sop("map:"+map);

		//判读键是否存在
		sop("containsKey:"+map.containsKey("022"));
		//判读值是否存在
		sop("containsValue:"+map.containsValue("ni"));

		//获取键对应的值
		sop("get:"+map.get("02"));

		//可通过get方法的返回值判断键是否存在。一次取一个值。
		map.put("0192",null);
		sop("get:"+map.get("0192"));		
		
		//获取map集合中所有的值。
		Collection<String> coll = map.values();

		sop(coll);
		sop("map:"+map);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行结果:

Map集合的两种取出方式:
Set<K> keySet:将Map中所有的键存入到Set集合。一次可取出多个值。
Set<Map.Entry<k,v>> entrySet:将Map集合中的映射关系存入到set集合中,而这个关系的数据类型就是:Map.Entry。
Entry是Map接口的一个内部接口。
/*
每一个学生都有对应的归属地。
学生Student,地址String.
学生属性:姓名,年龄。
注意:姓名和年龄相同的视为同一个学生。
保证学生的唯一性。

思路:
1. 描述学生。//描述事物时,系统默认比较哈希地址值。所以要注意按元素自身条件判断唯一性。
		//具体做法:复写hashCode、equals方法。
		//同时需要注意数据排序,这可以方便数据多时的整理。
	总结:数据多时,必须做:实现、覆盖两方法。
2. 定义map容器。将学生作为键,地址作为值存入。
3. 获取map集合中的元素。
*/
import java.util.*;
//同时创建多个对象备用时,实现和复写必须要进行。
class Student implements Comparable<Student>
{
	private String name;
	private int age;
	Student(String name,int age)
	{
		this.name = name;
		this.age = age;
	}
	public int compareTo(Student s)
	{
		int num = new Integer(this.age).compareTo(new Integer(s.age));

		if(num==0)
			return this.name.compareTo(s.name);
		return num;
	}

	public int hashCode()
	{
		return name.hashCode()+age*23;
	}
	public boolean equals(Object obj)
	{
		if(!(obj instanceof Student))
			throw new ClassCastException("类型不匹配");

		Student s = (Student)obj;

		return this.name.equals(s.name) && this.age == s.age;
	}
	public String getName()
	{
		return name;
	}
	public int getAge()
	{
		return age;
	}
	public String toString()
	{
		return name+":"+age;
	}
}
class MapTest
{
	public static void main(String[] args)
	{
		HashMap<Student,String> hm = new HashMap<Student,String>();

		hm.put(new Student("lisi1",21),"beijing");
		hm.put(new Student("lisi2",22),"nanjing");
		hm.put(new Student("lisi3",23),"tianjin");
		hm.put(new Student("lisi4",24),"shanghai");

		//第一种取出方式 keySet	
		Set<Student> keySet = hm.keySet();

		for(Iterator<Student> it = keySet.iterator();it.hasNext();)
		{
			Student stu = it.next();
			String addr = hm.get(stu);
			System.out.println("学生信息:"+stu+",地址"+addr);
		}

		//第二种取出方式 entrySet
		Set<Map.Entry<Student,String>> entrySet = hm.entrySet();

		for(Iterator<Map.Entry<Student,String>> it = entrySet.iterator();it.hasNext();)
		{
			Map.Entry<Student,String> me = it.next();
			Student stu = me.getKey();
			String addr = me.getValue();
			System.out.println(stu+"........"+addr);
		}
	}
}
运行结果:

PS:
1、Map和Set很像,因为Set底层使用了Map集合。
2、Map集合的取出原理:将Map集合转成set集合,再通过迭代器取出。

三、工具类

1、Collections类
Collections: 是集合框架的工具类,它的方法都是静态的。无对外提供构造函数,不需要封装对象。
sort(List<?> list):根据元素的自然顺序 对指定列表按升序进行排序。
max():获取对象中最大元素。 
binarySearch():二分搜索法。必须是有序集合。包含索引键,返回索引;不含,返回“插入点-1”。
replaceAll(List<T> list,T oldVal,T newVal):使用另一个值替换列表中出现的所有某一指定值。
swap(List<?> list,i,j):在指定列表的指定位置处交换元素。
shuffle(List<?> list):随机重置元素位置。
reverse(List<?> list):反转指定列表中元素的顺序。

fill(List<? super T> list,T obj):使用指定元素替换指定列表中的所有元素。

//Collections: 集合工具类
import java.util.*;
class CollectionsDemo
{
	public static void main(String[] args)
	{
		collsDemo();
	}
	public static void collsDemo()
	{
		List<String> list = new ArrayList<String>();

		list.add("adss");
		list.add("sdfd");
		list.add("sfd");
		list.add("cc");
		list.add("w");
		list.add("sfd");

		sop(list);

		//1、sort 接收自定义比较器,按长度比较。只能给List排序。
		Collections.sort(list,new StrLenComparator());
		sop("sort1:"+list);
		//自然排序
		Collections.sort(list);
		sop("sort2:"+list);

		//2、max 获取最大元素
		String max = Collections.max(list);	
		sop("max="+max);

		//3、binarySearch 二分查找,必须是自然排序
		int index = Collections.binarySearch(list,"cc");
		sop("index="+index);

		//4、replaceAll 替换指定元素。等效于list.set(index,"pp");
		Collections.replaceAll(list,"cc","pp");
		sop("replaceAll:"+list);

		//5、swap 置换指定位置元素
		Collections.swap(list,1,2);
		sop("swap:"+list);

		//6、shuffle 随机排序(验证码)
		Collections.shuffle(list);
		sop("shuffle:"+list);

		//7、reverse 反转
		Collections.reverse(list);
		sop("reverse:"+list);

		//8、fill 把集合中值全换成pp。
		Collections.fill(list,"pp");
		sop("fill:"+list);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
//自定义比较器
class StrLenComparator implements Comparator<String>
{
	public int compare(String s1,String s2)
	{
		if(s1.length()>s2.length())
			return 1;
		if(s1.length()<s2.length())
			return -1;
		return s1.compareTo(s2);
	}
}
运行结果:

PS:
SynchronizedList(List<T> list):返回指定列表支持的同步(线程安全的)列表。存在线程不安全问题是集合的共同特点。
2、Arrays类
Arrays:用于操作数组的工具类。里面都是静态方法。
equals():比较两个数组中内容是否相同。
deepEquals():比较两个数组及其内部内容是否相同。
2.1 List asList:将数组变成list集合。
优点:可以使用集合的思想和方法来操作数组中的元素,更加便捷。
缺点:集合不可以增删数组内容,因为数组的长度固定。否则发生UnsupportedOperationException。
如果数组中的元素都是对象,那么变成集合时,"数组中的元素"就直接转成集合中的元素。
如果数组中的元素都是基本数据类型,那么会将"该数组"作为集合中的元素存在。
2.2 集合变数组
操作:使用Collection接口中的toArray方法。可对集合中的元素操作的方法进行限定,不允许对其增删。
指定类型的数组到底要定义多长?
如果长度小于集合的size,那么该方法内部会创建一个新的数组。
如果长度大于集合的size,就不会创建一个新的数组。使用传递进来的数组,其他位置默认为null。
所以创建一个刚刚好的数组内存处置最优。
//Arrays:用于操作数组的工具类。
import java.util.*;
class ArraysDemo
{
	public static void main(String[] args)
	{
		int[] arr1 = {2,4,5};

		System.out.println(Arrays.toString(arr1));

		String[] arr2 = {"abc","cc","kkkk"};

		List<String> list = Arrays.asList(arr2);
		sop("contains:"+list.contains("cc"));
		//注意打印的是list,不是arr.
		sop(list);

		//将数组中的对象转成集合
		Integer[] nums1 = {2,4,5};
		List<Integer> list1 = Arrays.asList(nums1);
		sop("数组对象:"+list1);

		//基本数据类型转成集合
		int[] nums2 = {2,4,5};
		List<int[]> list2 =Arrays.asList(nums2);
		sop("基本数据类型:"+list2);
		
		List<String> list3 = new ArrayList<String>();
		list3.add("abc1");
		list3.add("abc2");
		list3.add("abc3");

		//集合转数组
		String[] arr = list3.toArray(new String[2]);
		sop(Arrays.toString(arr));
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行结果:

3、System类

System类中的方法和属性都是静态的。out:标准输出,默认是控制台。in:标准输入,默认是键盘。
常见方法:
long currentTimeMillis():获取当前时间的毫秒值。作用:检测程序的执行时间。
Properties getProperties():获取系统属性信息。Properties集合中存储的都是String类型的键和值。
最好使用它自己的存储和取出的方法来完成元素的操作。
Windows系统中换行为\r\n两个转义字符,Linux只有一个\n。

//System:类中的方法和属性都是静态的。
import java.util.*;
class SystemDemo
{
	public static void main(String[] args)
	{
		long l1 = System.currentTimeMillis();
		sop("计时开始:"+l1);
		Properties prop = System.getProperties();

		//因为Properties是Hashtable的子类,也就是Map集合的一个子类对象。
		//那么可以通过map的方法取出该集合中的元素。
		//该集合中存储都是字符串,没有泛型定义。

		//获取指定属性信息
		String value = System.getProperty("os.name");
		sop("value="+value);

		sop("转义字符\r\n:"+"hello-\r\n world");
		//定义跨系统信息
		final String LINE_SEPARATOR = System.getProperty("line.separator");
		sop("hello"+LINE_SEPARATOR+"java");

		long l2 = System.currentTimeMillis();
		sop("共用时:"+(l2-l1));	
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行结果:

4、Runtime类

每个Java应用程序都有一个Runtime类实例,使应用程序能和其运行的环境相连接。应用程序不能创建自己的Runtime类实例。
该类并没有提供构造函数。说明不可以创建对象。那么该类中的方法应该都是静态的。但发现该类中还有非静态方法。
说明该类肯定会提供静态方法获取本类对象。而且只有一个,说明该类使用了单例设计模式。
static Runtime  getRuntime():获取Runtime类。
//Runtime对象     
class RuntimeDemo
{
	public static void main(String[] args) throws Exception
	{
		Runtime r = Runtime.getRuntime();

		//exec:在单独的进程中执行指定的字符串命令。
		Process p = r.exec("notepad.exe StaticImport.java");

		Thread.sleep(4000);
		//杀进程
		p.destroy();
	}
}

5、Math类

该类提供了静态的操作数学运算的方法。
常用方法:
ceil():返回大于参数的最小整数。
floor():返回小于参数的最大整数。
round():返回四舍五入的整数。
pow(a,b):a的b次方。
//Math类
import java.util.*;
class MathDemo
{
	public static void main(String[] args)
	{
		show();
		//返回大于或等于 0.0 但小于 1.0 的伪随机 double 值。
		Random r = new Random();
		for(int x=0; x<10;x++)
		{
			//强转成int类型数值
			int d = (int)(Math.random()*10+1);
			System.out.print(d+" ");
		}
		System.out.println();

		for(int x=0; x<10;x++)
		{
			int d1 = r.nextInt(10)+1;
			System.out.print(d1+" ");
		}
		System.out.println();
	}
	public static void show()
	{
		//ceil返回大于指定数据的最小整数。
		double d = Math.ceil(16.34);

		//floor返回小于指定数据的最大整数。
		double d1 = Math.floor(14.78);
	
		//四舍五入
		long l = Math.round(12.5);
		sop("ceil:"+d);
		sop("floor:"+d1);
		sop("round:"+l);

		//返回2^4。
		double d2 = Math.pow(2,4);
		sop("pow:"+d2);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行结果:

6、Date、DateFormat类
日期对象和毫秒值间的转换:
a 毫秒值-->日期对象 new Date(); setTime();
b 日期对象-->毫秒值 getTime();
c 对日期对象进行格式化:使用DateFormat类中的format方法。
import java.util.*;
import java.text.*;

class DateDemo
{
	public static void main(String[] args)
	{
		Date d = new Date();
		sop(d);

		sop("将日期对象转成毫秒值:"+d.getTime());

		//将模式封装到SimpleDateFormat对象中。
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy年MM月dd日E hh:mm:ss");

		//调用format方法让模式格式化指定Date对象。
		String time = sdf.format(d);

		sop("time="+time);
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行结果:

7、Calendar类

该类是一个抽象类,它为特定瞬间与一组诸如YREA、MONTH、DAY_OF_MONTH、HOUR等日历字段之间的转换
提供了一些方法,并为操作日历字段提供了一些方法。
add(int field,int amount):依据日历规则,为指定日历字段指定添加或减去指定的时间量。
/*
1,获取任意年的二月有多少天。
	思路:根据指定年设置一个时间就是
	c.set(year,3,1)//某一年的3月1日。
	c.add(Calendar.DAY_OF_MONTH,-1);//3月1日前一天就是2月最后一天。
2,获取昨天的现在这个时刻。
	c.add(Calendar.DAY_OF_MONTH,-1);
*/
import java.util.*;
class CalendarDemo
{
	public static void main(String[] args)
	{

		Calendar c = Calendar.getInstance();

		c.set(2012,3,1);

		c.add(Calendar.MONTH,-1);

		c.add(Calendar.DAY_OF_MONTH,-1);

		printlnCalendar(c);
	}
	public static void printlnCalendar(Calendar c)
	{
		String[] mons = {"一月","二月","三月","四月"
				,"五月","六月","七月","八月"
				,"九月","十月","十一月","十二月"};

		String[] weeks = {"","星期日","星期一","星期二","星期三"
					,"星期四","星期五","星期六"};

		int index = c.get(Calendar.MONTH);

		int index1 = c.get(Calendar.DAY_OF_WEEK);


		sop(c.get(Calendar.YEAR)+"年");

		//sop((c.get(Calendar.MONTH)+1)+"月");
		sop(mons[index]);

		sop(c.get(Calendar.DAY_OF_MONTH)+"日");

		//sop("星期"+c.get(Calendar.DAY_OF_WEEK));
		sop(weeks[index1]);		
	}
	public static void sop(Object obj)
	{
		System.out.println(obj);
	}
}
运行结果:

四、JDK1.5

JDK1.5版本出现的新特性。
JDK1.5版本后,Collection继承了Iterable接口。Iterable接口将iterator()方法抽取出来。
优点:提高了集合框架扩展性;提供了新功能:foreach:高级for循环。
1、foreach:高级for循环。凡是支持迭代器的集合都支持foreach。
1.1格式:
for(数据类型 变量名 : 被遍历的集合(Collection)或数组){}
1.2特点:
优点:foreach简化了书写,可对集合进行遍历。
缺点:只能提出集合元素,不能修改。
PS:
迭代器:除了遍历,还可以进行remove集合中元素的动作;
如果是用ListIterator,还可以在遍历过程中对集合进行增删改查的动作。
传统for和高级for区别:
高级for有一个局限性:必须有被遍历的目标。
建议:在遍历数组时,用传统for,因为其可以定义角标。
//JDk1.5之后特性
import java.util.*;
class ForEachDemo
{
	public static void main(String[] args)
	{
		ArrayList<String> al = new ArrayList<String>();

		al.add("abc1");
		al.add("abc2");
		al.add("abc3");		
	
		//高级for循环
		for(String s : al)
		{
			s = "kk";		
		}
		//只能打印集合内容,不能修改
		System.out.println("for循环后集合:"+al);

		int[] arr = {3,5,6};
		for(int i : arr)
		{
			//高级for循环大大简化了书写
			System.out.println("i:"+i);
		}

		HashMap<Integer,String> hm = new HashMap<Integer,String>();

		hm.put(1,"a");
		hm.put(2,"b");
		hm.put(3,"c");
		
		//用高级for循环取出键值对:方式一
		Set<Integer> keySet = hm.keySet();
		for(Integer i : keySet)
		{
			System.out.println(i+"::"+hm.get(i));
		}

		//方式二
		//Set<Map.Entry<Integer,String>> entrySet = hm.entrySet();
		//for(Map.Entry<Integer,String> me : entrySet)
		for(Map.Entry<Integer,String> me : hm.entrySet())
		{
			System.out.println(me.getKey()+":----:"+me.getValue());
		}
	}
}
运行结果:

2、可变数组:简写了数组参数。 不用每次都手动的建立数组对象,只要将要操作的元素作为参数传递即可。
隐式将这些参数封装成类数组。
格式:数据类型... 数组名 
注意:使用时,可变参数一定要定义在参数列表最后面。

//JDK1.5版本出现的新特性:可变参数
class VariableArrayDemo
{
	public static void main(String[] args)
	{
		show("hah",2,1,2,115,3);
	}
	//使用时,可变参数一定要定义在参数列表最后面。
	public static void show(String str,int... ar)	
	{
		System.out.println(ar.length);
	}
}
运行结果:

3、静态导入(StaticImport):导入的是类的所有静态成员。
格式:
import static java.util.Arrays.*;
当类名重名时,需要指定具体的包名。

当方法重名时,指定具备所属的对象或类。

//StaticImport 静态导入
import java.util.*;

//导入的是Arrays这个类中的所有静态成员。
import static java.util.Arrays.*;

//导入了System类中所有静态成员。
import static java.lang.System.*;

class StaticImport
{
	public static void main(String[] args)
	{
		//由于静态导入,可省略类
		out.println("hah ");

		int[] arr = {3,1,4};

		sort(arr);//Arrays.sort(arr);
		int index = binarySearch(arr,4);//int index = Arrays.binarySearch(arr,1);

		//这里的Arrays.不能省,因为Object有同名方法。
		out.println(Arrays.toString(arr));
		System.out.println("Index="+index);
	}
}
运行结果:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值