day17、集合

一、集合的概念

1.概念:

对象的容器,定义了对多个对象进行操作的常用方法。可实现数组的功能。

集合中是可以存放任意对象的,只要把对象存储集合后,那么这时他们都会被提升成Object类型。当我们在取出每一个对象,并且进行相应的操作,这时必须采用类型转换。

2.与数组区别:
  • 数组长度固定,集合长度不固定
  • 数组可以存储基本类型和引用类型,集合只能存储引用类型
3.位置

java.util.xxxx;需要导包

二、泛型Generics

概念:声明要存储的类型是什么。
作用:一般在创建对象时,将未知的类型确定具体的类型。当没有指定泛型时,默认类型为Object类型。泛型没有继承概念
目的:保护容器中的数据的类型的安全。

语法:
	容器<数据类型> 容器对象 = new 容器<数据类型>();
注意点:因为集合仅限于存储引用类型,所以声明泛型不能直接写基本数类型,需要写对应的包装类。
1、定义和使用含有泛型的类

语法

修饰符 class 类名<代表泛型的类型> {}

使用格式:在创建对象的时候确定泛型

class MyGenericClass<T> {
	//没有T类型,在这里代表 未知的一种数据类型 未来传递什么就是什么类型
	private T t;    
    
    public void setT(T t) {
        this.t = t;
    }     
    public T getT() {
        return t;
    }
}

public class GenericClassDemo {
  	public static void main(String[] args) {		 
         // 创建一个泛型为String的类
         MyGenericClass<String> my = new MyGenericClass<String>();    	
         // 调用setT
         my.setT("AAA");
         // 调用getT
         String t = my.getT();
         System.out.println(t);
         //创建一个泛型为Integer的类
         MyGenericClass<Integer> my2 = new MyGenericClass<Integer>(); 
         my2.setT(123);   	  
         Integer t2 = my2.getT();
         System.out.println(t2);
    }
}
2、含有泛型的方法

语法

修饰符 <代表泛型的类型> 返回值类型 方法名(参数){}

使用格式:调用方法时,确定泛型的类型

class MyGeneric {	  
    public <E> void show(E e) {
    	System.out.println(e.getClass());
    }
    
    public <E> E show2(E e) {	
    	return e;
    }
}
public class GenericDemo {
    public static void main(String[] args) {
        // 创建对象
        MyGeneric mm = new MyGeneric();
        // 调用方法
        mm.show("aaa");//class java.lang.String
        mm.show(123);//class java.lang.Integer
        mm.show(12.45);//class java.lang.Double
    }
}
3、含有泛型的接口

语法

修饰符 interface接口名<代表泛型的类型> {}

使用格式:

//接口类型
public interface MyGenericInterface<E>{
	public abstract void add(E e);
	
	public abstract E getE();  
}

1、定义类时确定泛型的类型

此时,泛型E的值就是String类型。
public class MyImp1 implements MyGenericInterface<String> {
	@Override
    public void add(String e) {
      
    }

	@Override
	public String getE() {
		return null;
	}
}

2、始终不确定泛型的类型,直到创建对象时,确定泛型的类型

public class MyImp2<E> implements MyGenericInterface<E> {
	@Override
	public void add(E e) {
       	 
	}

	@Override
	public E getE() {
		return null;
	}
}

//确定泛型
public class GenericInterface {
    public static void main(String[] args) {
        MyImp2<String>  my = new MyImp2<String>();  
        my.add("aa");
    }
}

三、Collection接口

1、Collection集合体系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BiJ3D1dy-1597380545267)(D:\java\复习\java基础\图片\Collection集合框架.PNG)]

2、特点

代表一组任意类型的对象,集合框架的最大的父接口

3、方法:
add(元素);//向容器中添加元素
remove(元素);//从容器中移出某个元素
contains(元素);//是否包含指定的元素
clear();//清除集合,删除集合中所有的元素。
iterator();//迭代器
size();//集合的中元素个数
addAll(容器);//向当前容器中,添加所有了另外一个容器中的所有的元素
removeAll(容器);//从当前容器中,删除所有另一个容器的元素
isEmpty();//判断容器是否为空
retainAll();//取2个集合相同元素
4、Iterator迭代器

集合的遍历方式

  1. Iterator迭代器
  2. for增强
  3. 普通for(),只适合有下标的集合

使用迭代器Iterator来获取集合中的数据。

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
public class Demo3 {
	public static void main(String[] args) {
		//最常用方式
		List l = new ArrayList();
		//添加值
		l.add("张三");//下标0
		l.add("李四");//下标1
		l.add("王五");//下标2
		l.add("赵六");//下标3
		l.add("牛一");
		l.add(2, "田七");//添加到下标为2的位置
		
		//遍历
		//方式1 Iterator迭代器
        //step1:先在要遍历的集合上,获取迭代器对象
		Iterator it = l.iterator();
		//step2:判断迭代器对象之后是否有元素
		while (it.hasNext()) {
			//step3:获取该元素:
			Object o = it.next();
			System.out.println(o);			
		}		
		System.out.println("==========");
		//方式2 for增强
		for (Object object : l) {
			System.out.println(object);			
		}
		System.out.println("==========");
		//方式3 普通for()
		for (int i = 0; i < l.size(); i++) {
			System.out.println(l.get(i));
		}
	}
}
注意点:
	1、每次迭代获取元素(调用next())前,应该先判断是否有这个元素(hasNext()),如果有再获取,如果没有就不要获取,如果强行获取,就报错:java.util.NoSuchElementException
	2、迭代器在工作期间,集合本身不要去更改集合的结构。但是迭代器对象自己可以删除。

1、List子接口

1.1.特点

继承自Collection接口

有序,有下标,元素可重复

1.2.方法
add(int index,Objict o);//在index位置插入对象o
set(int index,Objict o);-->指定位置替换元素
remove(index)-->根据位置进行删除
addAll(int index,Collection c);//将一个集合中所以元素添加到c集合的index位置
get(int index);//获取指定下标的元素
subList(int fromIndex,int toIndex);//截取fromIndex(包含)到toIndex(不包含)间元素,返回新集合
indexOf()-->int,搜索指定的元素,返回下标,如果没有就返回-1
1.3.遍历集合
  • for-each,增强for循环
  • Iterator,迭代器
  • 普通的for循环,结合get()方法。
1.4.练习
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class Demo3 {

	public static void main(String[] args) {
		//最常用方式
		List l = new ArrayList();
		//添加值
		l.add("张三");//下标0
		l.add("李四");//下标1
		l.add("王五");//下标2
		l.add("赵六");//下标3
		l.add("牛一");//下标4
        //使用下标添加元素,下标数值不能大于已有集合长度
		l.add(2, "田七");//添加到下标为2的位置
		
		//遍历
		//方式1 Iterator迭代器
		Iterator it = l.iterator();
		//迭代器之后是否有元素
		while (it.hasNext()) {
			//获取迭代器之后元素
			Object o = it.next();
			System.out.println(o);
		}
		
		System.out.println("==========");
		
		//方式2 for增强
		for (Object object : l) {
			System.out.println(object);
		}
		
		System.out.println("==========");
		
		//方式3 普通for()
		for (int i = 0; i < l.size(); i++) {
			System.out.println(l.get(i));
		}
		
		//indexOf()搜索指定的元素,返回下标,如果没有就返回-1
		System.out.println(l.indexOf("牛一"));
		//lastIndexOf()从后往前搜索指定的元素,返回下标,如果没有就返回-1
		System.out.println(l.lastIndexOf("牛一"));
		
		//切割集合,从前面下标开始(包含),到后面下标结束(不包含)
		List l2 = l.subList(1, 3);
		System.out.println(l2);
	}
}

2、List实现类

2.1. ArrayList 实现类
  • 数组结构实现,查询快,增删慢;
  • JDK1.2版本,运行效率快,线程不安全
2.2. Vector 实现类
  • 数组结构实现,查询快,增删慢;
  • JDK1.0版本,运行效率慢,线程安全
2.3. LinkedList 实现类
  • 链表结构实现,增删快,查询慢
2.3.1LinkedList方法
public void addFirst(E e):将指定元素插入此列表的开头。
public void addLast(E e):将指定元素添加到此列表的结尾。
public E getFirst():返回此列表的第一个元素。
public E getLast():返回此列表的最后一个元素。
public E removeFirst():移除并返回此列表的第一个元素。
public E removeLast():移除并返回此列表的最后一个元素。
public E pop():从此列表所表示的堆栈处弹出一个元素。
public void push(E e):将元素推入此列表所表示的堆栈。
public boolean isEmpty():如果列表不包含元素,则返回true
2.4练习
import java.util.ArrayList;
import java.util.List;

public class Test {
	public static void main(String[] args) {
		//step1:创建容器对象:特点,可以存储重复的元素,有序存储(有下标,index)
		List<String> l1 = new ArrayList<>();
		System.out.println(l1);//[]
		l1.add("aaa");//下标:0
		l1.add("bbb");//1
		l1.add("ccc");//2
		System.out.println(l1);//[aaa, bbb, ccc]
		
		//step2:操作list这个容器
		
		//1.add(index,元素),指定位置添加元素
		l1.add(1,"XXX");//在指定的位置,添加元素
		System.out.println(l1);//[aaa, XXX, bbb, ccc]
		
		
		//2.get(index)-->元素,根据下标位置获取对应的元素
		for(int i=0;i<l1.size();i++){
			System.out.println("-->"+l1.get(i));
		}
		
		//3.indexOf()->int,在集合中搜索指定的内容,返回下标,如果不存在就-1
		//4.lastIndexOf()-->int,在集合中从后往前搜索指定的内容,返回下标,如果不存在就-1
		System.out.println(l1.indexOf("bbb"));//2
		l1.add("ccc");
		System.out.println(l1.lastIndexOf("ccc"));//4
		System.out.println(l1);//[aaa, XXX, bbb, ccc, ccc]
		
		//5.remove(index),根据下标删除指定元素
		l1.remove(3);
		System.out.println(l1);//[aaa, XXX, bbb, ccc]
		
		/*
		 * 6.set(index, 元素);在指定的位置,更新元素。
		 * 第一个参数:index,被替换的元素的位置
		 * 第二个参数:E,新元素
		 * 
		 * 返回值:被替换下来的元素。。
		 */
		String s1 = l1.set(2, "王二狗");
		System.out.println(l1);//[aaa, XXX, 王二狗, ccc]
		System.out.println(s1); //bbb
		/*
		 * 7.subList(int fromIndex, int toIndex)->List,
		 * 截取从fromIndex开始(包含)到toIndex(不包含)的集合,并返回到调用处
		 */
		List<String> subList = l1.subList(1, 3);
		System.out.println(subList);//[XXX, 王二狗]
	}
}

3、Set接口

继承自Collection接口

特点:无序、无下标、元素不可重复

方法:全部继承自Collection中方法

遍历方法:for-each(for增强);增强for。

3.1 HashSet集合
3.1.1 Set接口的实现类

java.util.HashSet底层的实现其实是一个java.util.HashMap支持

是根据对象的哈希值来确定元素在集合中的存储位置,因此具有良好的存取和查找性能。

3.1.2HashSet集合去重的流程
step1:先获取对象的hashCode,对象的哈希值不同,直接存储到HashSet容器中。
step2:如果哈希值相同,调用equals()比较。
	true:认为是相同的元素,不存储
	false:不同的元素,存储
    
    我们的set底层是使用map,所以他的对比方式就和map一致
数据结构为数组加链表

set的判断是否为同一对象基准
1.会先找到值在数组上的位置(使用哈希算法计算)hashCode
2.如果hash值相同,他就会找到对象的equals方法在进行比对是否为同一对象

原则:set的判断是否为同一对象基准

重写hashCode()的规则:先找到值在数组上的位置(使用哈希算法计算)hashCode
	对象相同:属性值相同。那么哈希码必须相同。
	对象不同:属性值不同。哈希码尽量不同。
			哈希码可能相同,也可能不同,但是我们希望不同。

重写equals()的原则:如果hash值相同,再找到对象的equals方法在进行比对是否为同一对象
	如果两个对象的属性值相同,认为是相同的对象,返回true。
	如果两个对象的属性值有不同,就不是相同的对象,返回false。
3.1.3练习
public class Student {
	private String name;//姓名
	private int no;//学号
	/**
	 * @Description:重写hashCode
	 */
	@Override
	public int hashCode() {
		int i1 = this.name.hashCode();
		int i2 = this.no;
		return (i1+i2)*31;
	}
	/**
	 * @Description:重写equals
	 */
	@Override
	public boolean equals(Object obj) {
		//判断对象不为空
		if (obj!=null) {
			//是否为本对象
			if (this == obj) {
				return true;
			}
			//比对对象的各个属性
			if (obj instanceof Student) {
				Student s = (Student)obj;
				if (s.getName().equals(this.name)&&s.getNo()==this.no) {
					//System.out.println("他们是同一个人");
					return true;
				}
			}
		}
		return false;
	}
	/**
	 * @Description:Student的构造方法,set/get方法,toString方法
	 */
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public int getNo() {
		return no;
	}
	public void setNo(int no) {
		this.no = no;
	}
	@Override
	public String toString() {
		return "Student [name=" + name + ", no=" + no + "]";
	}
	public Student(String name, int no) {
		super();
		this.name = name;
		this.no = no;
	}
	public Student() {
		super();
	}
}

public class Test {

	public static void main(String[] args) {
        //创建集合对象,该集合中存储 Student类型对象
		Set<Student> stuSet = new HashSet<Student>();
        Student stu = new Student("张三", 101);
		stuSet.add(stu);
		stuSet.add(new Student("李四", 102));
		stuSet.add(new Student("张三", 101));
		stuSet.add(new Student("李四", 102));

		// 遍历
		Iterator<Student> it = stuSet.iterator();
		for (Student student : stuSet) {
			System.out.println(student);
		}
	}
}
执行结果:
Student [name=李四, no=102]
Student [name=张三, no=101]
3.2 LinkedHashSet
3.2.1 Set接口的实现类

存储去重原理同HashSet相同,但是外层套了一个链表结构。用于记录存储的顺序。它是链表和哈希表组合的一个数据存储结构。

3.2.2 练习
public class LinkedHashSetDemo {
	public static void main(String[] args) {
		Set<String> set = new LinkedHashSet<String>();
		set.add("bbb");
		set.add("aaa");
		set.add("abc");
		set.add("bbc");
        Iterator<String> it = set.iterator();
		while (it.hasNext()) {
			System.out.println(it.next());
		}
	}
}
结果:
  bbb
  aaa
  abc
  bbc
3.3 TreeSet集合
3.3.1 Set接口的实现类

TreeSet作为Set的一个实现类,也要去除重复的元素。可以给存储的元素进行整理排序。

排序:就要有排序的规则。

默认的规则:Comparable接口,定义排序的规则

3.3.2 TreeSet集合去重的流程

要想把元素存入到TreeSet集合中。就要求元素所属的类,必须实现Comparable接口。

interface Comparable{
	int compareTo(T obj);//排序的规则
}
java.lang.Comparable接口的用途:强行对实现类的对象进行排序。

compareTo()-->此方法用于排序,比较其两个数的顺序,返回值int类型类型

o1.compareTo(o2)-->int
按照升序排序
- 返回正数:o1 > o2,将o1排在o2的后面。
- 返回负数:o1 < o2,将o1排在o2的前面。
- 返回零:认为o1和o2相同,不存储了。

按照降序排序
- 返回正数:o1 < o2,将o1排在o2的后面。
- 返回负数:o1 > o2,将o1排在o2的前面。
- 返回零:认为o1和o2相同,不存储了。
3.4 练习
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;

class Student {
	private String name;
	private int age;
	public Student() {
	}
	public Student(String name, int age) {
		this.name = name;
		this.age = 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 "Student{" + "name='" + name + '\'' + ", age=" + age + '}';
	}
}

public class Demo {

    public static void main(String[] args) {
        // 创建四个学生对象 存储到集合中
        ArrayList<Student> list = new ArrayList<Student>();

        list.add(new Student("rose",18));
        list.add(new Student("jack",16));
        list.add(new Student("abc",16));
        list.add(new Student("ace",17));
        list.add(new Student("mark",16));

        /*
         * 让学生先按照年龄排序 升序;年龄相同按照姓名的首字母 升序
         */
//        Collections.sort(list);//要求 该list中元素类型  必须实现比较器Comparable接口
        Collections.sort(list, new Comparator<Student>() {
        	@Override
            public int compare(Student o1, Student o2) {
                // 年龄降序
                int result = o2.getAge()-o1.getAge();//年龄降序

                if(result==0){//第一个规则判断完了 下一个规则 姓名的首字母 升序
                    result = o1.getName().charAt(0)-o2.getName().charAt(0);
                }
                return result;
            }
        });

        for (Student student : list) {
            System.out.println(student);
        }
    }
}

//效果如下:
Student{name='rose', age=18}
Student{name='ace', age=17}
Student{name='abc', age=16}
Student{name='jack', age=16}
Student{name='mark', age=16}

四、比较器

1、Comparable接口

java.lang.Comparable接口:给对象强行排序的。默认的比较器。

int compareTo(T o) 
将此对象与指定的对象进行比较以进行排序。 
    比较的两个对象:this对象和参数o对象比较

升序排序的规则

  • 正数:this对象>o对象,this对象排后面。
  • 负数:this对象<o对象,this对象排前面
  • 零:this对象和o对象相同,不存储。——>去重
2、Comparator接口

java.util.Comparator接口:给对象强行排序的。自定义的比较器。

int compare(T o1, T o2) 
比较其两个参数的顺序。
    比较的两个对象:o1和o2

升序排序的规则

  • 正数:o1对象>o2对象,this对象排后面。
  • 负数:o1对象<o2对象,this对象排前面
  • 零:o1对象和o2对象相同,不存储。——>去重

五、Colletions工具类

Collections是集合工具类,用来对集合进行操作。

除了存取以外的集合常用方法

reverse()//反转集合
sort()//升序排序要求该集合中元素类型必须实现比较器Comparable接口
shuffle()//打乱集合顺序

练习

ublic class CollectionsDemo3 {
	public static void main(String[] args) {
		ArrayList<String> list = new ArrayList<String>();
		list.add("cba");
		list.add("aba");
		list.add("sba");
		list.add("nba");
		// 排序方法 按照第一个单词的降序
		Collections.sort(list, new Comparator<String>() {
			@Override
			public int compare(String o1, String o2) {
				return o2.charAt(0) - o1.charAt(0);
			}
		});
		System.out.println(list);
	}
}

六、Map接口

1.Map集合体系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-M0qVY3cN-1597380545273)(D:\java\复习\java基础\图片\Map框架.PNG)]

2.特点

map每次操作的元素是成对的。两个:key(键),value(值)。

map中存储的元素,键值对。其中键不能重复。值可以重复。键和值,必须是一一对应的。

3.遍历
3.1 键找值方式

即通过元素中的键,获取键所对应的值

  1. 获取Map中所有的键,由于键是唯一的,所以返回一个Set集合存储所有的键。方法提示:keyset()
  2. 遍历键的Set集合,得到每一个键。
  3. 根据键,获取键所对应的值。方法提示:get(K key)
3.2 Entry键值对对象

Map中存为key(键)与value(值),它们在在Map中是一一对应关系,这一对对象又称做Map中的一个Entry(项)

即通过集合中每个键值对(Entry)对象,获取键值对(Entry)对象中的键与值。

  1. 获取Map集合中,所有的键值对(Entry)对象,以Set集合形式返回。方法提示:entrySet()

  2. 遍历包含键值对(Entry)对象的Set集合,得到每一个键值对(Entry)对象。

  3. 通过键值对(Entry)对象,获取Entry对象中的键与值。 方法提示:getkey() getValue()

4.方法
添加/修改元素:
put(key,value);向map中添加键值对,键不能重复。如果键重复了,那么value会被覆盖的并返回原value。添加key与value相同元素,会返回key所对应的value
    
删除元素:
remove(key)-->value,删除指定key,并返回key对应的value;没有就返回null
clear()-->清空集合
    
查询元素:
containsKey(key)-->boolean是否包含指定key
containsValue(value)-->boolean是否包含指定value
get(key)-->通过key获取value,没有就返回null
size()-->键值对的个数

keySet()-->Set<key>,获取Map集合中所有的键,存储到Set集合中。
values()-->Collection<value>,获取Map集合中所有的value,存储到Collection集合中。
entrySet()-->Set<Entry>,获取Map集合中所有的键值对,存储到Set集合中。

HashMap key值可以为null,value值也可以为null

如果key值相同,value值会被覆盖

1、HashMap实现类
key不重复,无序,键值对对应
HashMap去重原理同HashSet相同。
HashSet的底层就是HashMap,只不过只要key,不要value值。

去重规则:

tep1:对象的hashCode()-->哈希值
	如果哈希值不同,就直接存储。
	如果哈希值相同,就进入第二步

step2:对象的equals()-->boolean
	如果true:相同的元素,key是相同的了。value值,会覆盖map中相同的key的之前的value。
	如果false:不同的元素,key,value都可以进行存储。
2、TreeMap实现类
TreeMap要给key去重,而且还要排序:从小到大。
TreeMap去重原理同TreeSet相同。
TreeSet的底层就是TreeMap,只不过只要key,不要value值。

默认的排序去重规则:Comparable接口;自定义Comparator接口作为比较器。

compareTo(o)-->this和o;从小到大排序
- 正数:this > o,this排后面
- 负数:this < o,this排前面
- 零:相同的对象,这个key对应的value要替换掉原来的value。

compare(o1,o2)-->int;从小到大排序
- 正数:o1 > o2,排后面
- 负数:o1< o2,排前面
- 零:相同的对象,这个key对应的value要替换掉原来的value。
3、LinkedHashMap实现类

继承HashMap集合

记录了存储的顺序。去重的原理和HashMap相同。

public class Test {
	public static void main(String[] args) {
		/*
		 * LinkedHashMap集合
		 * 记录了存储的顺序。
		 */		
		LinkedHashMap<String, String> map2 = new LinkedHashMap<>();
		map2.put("D", "ddd");
		map2.put("A", "aaa");
		map2.put("C", "ccc");
		map2.put("B", "bbb");
        //按照存储顺序输出
		System.out.println(map2);
	}
}
//效果如下:
{D=ddd, A=aaa, C=ccc, B=bbb}
4、集合去重原理
  • TreeSet与TreeMap是靠二叉树实现去重,需要实现comparable接口或compareTo接口
  • HashSet与HashMap是靠哈希值实现去重,需要重写HashCode方法与equals方法
5、练习
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

public class Demo {

	public static void main(String[] args) {
		Map<String,String> maps = new HashMap<String,String>();
		//添加
		maps.put("cn", "中国");
		maps.put("jp", "日本");
		maps.put("usa", "美国");
		maps.put("uk", "英国");
		//取值
		String word = maps.get("cn");
		System.out.println(word);
		
		System.out.println("====遍历1 keySet====");
		//遍历1 keySet 将key值存入Set集合
		Set<String> keys = maps.keySet();
		for (String string : keys) {
			System.out.println("keys:"+string+"value:"+maps.get(string));
		}
		System.out.println("==========");
		
		//map集合remove()成功会返回key所对应的value
		String a = maps.remove("usa");
		System.out.println(a);
		//map集合remove()不成功会返回null
		String a1 = maps.remove("ua");
		System.out.println(a1);
		System.out.println("==========");
		
		//添加key与value相同元素,会返回key所对应的value
		String s = maps.put("uk", "英国");
		System.out.println(s);
		//添加key值相同value不同的元素,以前存储的value会被覆盖,且返回被覆盖的value
		String s1 = maps.put("uk", "日不落帝国");
		System.out.println(s1);
		System.out.println("==========");
		
		System.out.println("====遍历2 keySet====");
		//遍历2 entry 将key值与value封装到Entry,存入Set集合
		Set<Entry<String, String>> entry = maps.entrySet();
		for (Entry<String, String> entry2 : entry) {
			System.out.println(entry2.getKey()+"="+entry2.getValue());
		}
		System.out.println("==========");
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值