JAVASE

目录

一、集合

二、Collection接口

1、Iterator迭代器

2、for each

3、for(编译类型需要时List,因为List支持索引)

三、List子接口

1、ArrayList

2、Vector

3、LinkedList

四、Set子接口

1、HashSet   

2、LinkedHashSet 

3、TreeSet 

五、Map接口

1、HashMap

2、Hashtable

3、TreeMap:

六、Collections工具类

七、泛型

1、自定义泛型类

2、自定义泛型接口

3、自定义泛型方法

八、反射

1、反射机制

2、反射相关类

3、Class类

4、类加载

5、反射获取类的结构信息

6、通过反射机制创建对象


一、集合

Collection接口:

                           List子接口:ArrayList实现类  Vector实现类  LinkedList实现类 

                           Set子接口: HashSet实现类:LinkedHashSet子类

                                                TreeSet实现类  

Map接口:

                                                HashMap实现类:LinkedHashMap子类

                                                Hashtable实现类:Properties子类

                                                TreeMap实现类 

Collections工具类:

二、Collection接口

public interface Collection<E> extends Iterable<E> 

        Collection l = new ArrayList();
        //添加元素,返回布尔值,对象名.add();
        l.add(0);
        l.add("a");
        l.add(true);
        //获取集合的元素个数,对象名.size();
        l.size();
        //删除某个元素,返回布尔值,对象名.remove(元素);如有多个目标值,删除前面的哪一个
        l.remove("a");
        //判断集合是否包含某个元素,返回布尔值,对象名.contains(元素);
        l.contains("a");
        //判断集合是否为空,返回布尔值,对象名.isEmpty();
        l.isEmpty();

        Collection list = new ArrayList();
        //添加一个集合到另一个集合,返回布尔值,对象名.addAll(集合);
        list.addAll(l);
        //判断一个集合是否包含另一个集合的所有元素,返回布尔值,对象名.containsAll(集合);
        l.containsAll(list);
        //在一个集合中删除另一个集合中所包含的元素,返回布尔值,对象名.removeAll(集合);
        l.removeAll(list);

        //清空集合,对象名.clear();
        l.clear();

1、Iterator迭代器

(1)主要用于遍历Collection集合中的元素

(2)所有实现了Collection接口的都有一个iterator()方法,用于返回一个实现了Iterator接口的对象,即可以返回一个迭代器

        Collection l = new ArrayList();
        l.add(0);
        l.add("a");
        l.add(true);

        Iterator i = l.iterator();     //此时i指向地址

        while (i.hasNext()) {          //hasNext():判断是否有下一个元素,返回布尔值
            Object o = i.next();       //next():指针下移,返回下移以后位置上的元素
            System.out.println(o);
        }
        i = l.iterator();              //重置迭代器

2、for each

for(元素类型 元素名:集合名或数组名){  }                  底层仍然是迭代器

        Collection l = new ArrayList();
        l.add(0);
        l.add("a");
        l.add(true);

        for (Object o :l) {
            System.out.println(o);
        }

3、for(编译类型需要时List,因为List支持索引)

        List l = new ArrayList();
        l.add(0);
        l.add("a");
        l.add(true);

        for (int i = 0; i < l.size(); i++) {
            System.out.println(l.get(i));
        }

三、List子接口

(1)List集合中的元素有序,添加顺序和取出顺序一致

(2)List集合中的元素可重复

(3)List集合中的每个元素都有其对应的顺序索引,即支持索引,从0开始

        List l = new ArrayList();
        l.add("a");
        l.add("b");
        l.add("b");
        //获取指定位置元素,对象名.get(索引);
        l.get(0);
        //添加指定位置元素,对象名.add(索引,元素);
        l.add(2,"c");
        //修改某个位置的元素,返回修改前的元素,对象名.set(索引,元素);
        l.set(3, "d");
        //删除指定位置的元素,返回被删除的元素,对象名.remove(索引);
        l.remove(3);
        //获取元素在集合中首次出现的位置,对象名.indexOf(元素);
        l.indexOf("b");
        //获取元素在集合中最后一次出现的位置,对象名.lastIndexOf(元素);
        l.lastIndexOf("b");
        //返回一个子集合,对象名.subList(a,b);    [a,b)
        l.subList(0,1);

        List list = new ArrayList();
        //在指定位置添加另一个集合中的所有元素,返回布尔值,对象名.addAll(索引,集合);
        list.addAll(0, l);

1、ArrayList

(1)ArrayList线程不安全,执行效率高

(2)ArrayList中维护了一个Object类型的数组elementDate

        transient Object[] elementDate;

(3)创建ArrayList对象时,如果使用的是无参构造器,则初始elementDate的容量为0,第一次添加,则扩容elementDate为10,再次扩容,则扩容为elementDate的1.5倍

(4)创建ArrayList对象时,如果使用的是有参构造器,则初始elementDate的容量为指定大小,再次扩容,则扩容为elementDate的1.5倍

2、Vector

(1)Vector线程安全,执行效率不高

(2)Vector中维护了一个Object类型的数组elementDate

        protected Object[] elementDate;

(3)创建Vector对象时,如果使用的是无参构造器,则初始elementDate的容量为0,第一次添加,则扩容elementDate为10,再次扩容,则扩容为elementDate的2倍

(4)创建Vector对象时,如果使用的是有参构造器,则初始elementDate的容量为指定大小,再次扩容,则扩容为elementDate的2倍

3、LinkedList

(1)线程不安全

(2)底层实现了双向链表,LinkedList维护了first和last分别指向头节点和尾节点,每个节点又维护了prev,next,item三个属性

        LinkedList l = new LinkedList();

四、Set子接口

(1)Set集合中的元素无序,添加顺序和取出顺序不一致,但取出的顺序是固定的

(2)Set集合中的元素不可重复,添加重复元素编译器不会报错,只是添加失败

(3)Set集合中的每个元素没有索引

1、HashSet   

(1)HashSet底层是HashMap,HashMap底层是数组+链表,红黑树

(2)添加一个元素时,先得到这个元素的hash值(hashCode方法),hash值会转成索引值,找到存储数据表table,看这个索引位置是否已经存放元素,如果没有,直接加入,如果有,调用equals方法依次比较,如果相同,就放弃添加,如果不相同,则添加到最后,

(3)如果一条链表元素个数达到一个默认值,并且table大小达到一个默认值,就会进行红黑树化

2、LinkedHashSet 

(1)LinkedHashSet底层是LinkedHashMap,LinkedHashMap底层是数组+双向链表

(2)同样根据元素的hash值决定元素的存储位置,同时使用双向链表维护元素的次序,使得元素看起来是以添加顺序保存的

3、TreeSet 

用无参构造器,创建TreeSet时,输出仍然是无序的

可通过有参构造器,可以传入一个比较器(匿名内部类),然后指定输出的排序规则

        TreeSet t = new TreeSet(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String) o2).compareTo((String) o1);
            }
        });
        t.add("d");
        t.add("b");
        t.add("a");
        t.add("c");

五、Map接口

(1)用于保存具有映射关系的数据:Key-Value(双列元素)

(2)Key和Value可以是任何引用类型的数据

(3)常用String类作为Map的key

(4)Key和Value都可以为null,但key只能有一个null,value可以都多个null

(5)Key不允许重复,Value可以重复,如果Key重复,新的Key的Value会对先前Key的Value进行覆盖

(6)Key和Value之间存在单向一对一关系,即通过指定的key总能找到对应的value

(7)一对k-v是封装在一个HashMap$Node对象中的,因为Node实现了Entry接口

        Map m = new HashMap();
        //添加元素,返回布尔值,对象名.put(Key,Value);
        m.put("1","a");
        m.put("2","b");
        m.put("3","b");
        m.put("3","c");
        //删除某个元素,返回布尔值,对象名.remove(Key);
        m.remove("3");
        //获取某个元素,对象名.get(Key);
        m.get("3");
        //获取集合的元素个数,对象名.size();
        m.size();
        //判断集合是否为空,返回布尔值,对象名.isEmpty();
        m.isEmpty();
        //判断一个key是否存在,返回布尔值,对象名.containsKey(key);
        m.containsKey("3");
        //获取所有key,返回Set类型,对象名.keySet();
        m.keySet();
        //获取所有Value,返回Collection类型,对象名.values();
        m.values();
        //获取所有k-v,返回Set类型,对象名.entrySet();
        m.entrySet();
        //清空集合,对象名.clear();
        m.clear();

 (8)Map遍历

        Map m = new HashMap();
        m.put("1", "a");
        m.put("2", "b");
        m.put("3", "c");

        //通过得到存放Key值的Set对象
        Set s = m.keySet();

        Iterator i = s.iterator();
        while (i.hasNext()) {
            Object key = i.next();
            System.out.println(key);
            System.out.println(m.get(key));
        }

        for (Object key : s) {
            System.out.println(key);
            System.out.println(m.get(key));
        }
        Map m = new HashMap();
        m.put("1", "a");
        m.put("2", "b");
        m.put("3", "c");

        //通过得到存放Value值的Collection对象
        Collection c = m.values();

        Iterator i = c.iterator();
        while (i.hasNext()) {
            Object o = i.next();
            System.out.println(o);
        }

        for (Object o :c) {
            System.out.println(o);
        }
        Map m = new HashMap();
        m.put("1", "a");
        m.put("2", "b");
        m.put("3", "c");

        //通过得到存放K-V的Set对象
        Set s = m.entrySet();

        Iterator i = s.iterator();
        while (i.hasNext()) {
            Object o = i.next();
            Map.Entry e = (Map.Entry) o;
            System.out.println(e.getKey());
            System.out.println(e.getValue());

        }

        for (Object o :s) {
            Map.Entry e = (Map.Entry) o;
            System.out.println(e.getKey());
            System.out.println(e.getValue());
        }

1、HashMap

(1)HashMap底层是数组+链表,红黑树

(2)线程不安全

(3)HashMap底层维护了Node类型的数组table,默认为null

(4)当创建对象时,将加载因子(loadfactor)初始化为0.75

(5)当添加key-val时,通过key的哈希值得到在table的索引。然后判断该索引处是否有元素,如果没有元素直接添加。如果该索引处有元素,继续判断该元素的key和准备加入的key是否相等,如果相等,则直接替换val,如果不相等需要判断是树结构还是链表结构,做出相应处理。如果添加时发现容量不够,则需要扩容

(6)第1次添加,则需要扩容table容量为16,临界值(threshold)为12(16*0.75)

(7)以后再扩容,则需要扩容table容量为原来的2倍(32),临界值为原来的2倍,即24,依次类推

(8)如果一条链表的元素个数超过TREEIFT_THRESHOLD(默认是8),并且table的大小>=MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树)

2、Hashtable

(1)线程安全

(2)Hashtable的key和value都不能为null,否则会抛出空指针异常

3、TreeMap:

用无参构造器,创建TreeMap时,输出仍然是无序的

可通过有参构造器,可以传入一个比较器(匿名内部类),然后指定输出的排序规则

        TreeMap t = new TreeMap(new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o2).compareTo((String)o1);
            }
        });
        t.put("d",2);
        t.put("b",4);
        t.put("a",6);
        t.put("c",7);

六、Collections工具类

Collections是一个操作List、Set、Map等集合的工具类,提供一系列静态方法对集合元素进行操作

        List l = new ArrayList();
        l.add("a");
        l.add("b");
        l.add("c");
        //反转list元素的顺序:reverse
        Collections.reverse(l);
        //对list元素进行随机排序:shuffle
        Collections.shuffle(l);
        //对list元素进行升序排序:sort
        Collections.sort(l);
        //对list元素按字符串长度大小排序:sort
        Collections.sort(l, new Comparator() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length()-((String)o2).length();
            }
        });
        //指定集合中i处和j处的元素交换:swap
        Collections.swap(l,0,2);
        //根据元素的自然排序,返回给定集合中的最大/最小元素:max min
        Collections.max(l);
        //返回给定集合中长度最大/最小的元素:max min
        Collections.max(l, new Comparator<Object>() {
            @Override
            public int compare(Object o1, Object o2) {
                return ((String)o1).length()-((String)o2).length();
            }
        });
        //返回给定集合中某个元素出现的次数:frequency
        Collections.frequency(l,"a");
        //将一个集合复制到另一个集合中:copy
        List t = new ArrayList();
        for (int i = 0; i < l.size(); i++) {
            t.add("");           //为了完成完整拷贝,需要给t赋值,大小和l一样
        }
        Collections.copy(t,l);
        //使用新元素替换旧元素:replaceALL
        Collections.replaceAll(l,"c","d");

七、泛型

(1)约束集合只存放某种引用类型,后面的 <引用类型> 可以不写

        ArrayList<String> a = new ArrayList<String>();
        ArrayList<String> a = new ArrayList<>();
        ArrayList<String> a = new ArrayList();

 (2)泛型没有继承性

        ArrayList<Object> a = new ArrayList<String>();    //报错

 (3)? extends super

public class Test {
    public static void main(String[] args) {
        List<Object> l1 = new ArrayList<>();
        List<A> l2 = new ArrayList<>();
        List<B> l3 = new ArrayList<>();
        List<C> l4 = new ArrayList<>();
        n1(l1);
        n1(l2);
        n1(l3);
        n1(l4);
        n2(l1);    //报错
        n2(l2);
        n2(l3);
        n2(l4);
        n3(l1);
        n3(l2);
        n3(l3);    //报错
        n3(l4);    //报错
    }
    //<?>接收任意类
    public static void n1(List<?> l){
    }
    //<? extends A>接收A及A的子类
    public static void n2(List<? extends A> l){
    }
    //<? super A>接收A及A的父类
    public static void n3(List<? super A> l){
    }
}

class A {
}
class B extends A {
}
class C extends B {
}

1、自定义泛型类

(1)在类声明时通过标识表示类中某个成员的引用类型,成员变量/成员方法可以使用泛型

(2)使用泛型的数组不能初始化,不确定类型,内存不知道分配多少的空间

(3)静态成员不能使用泛型

(4)创建对象时指定类型,没有指定类型,默认为Object

public class Test {
    public static void main(String[] args) {
        A<String,Integer> a = new A<>();
        a.t = "String";
        a.r = 1;
        a.n("123");
    }
}

class A<T,R> {
    T t;
    R r;

    //非泛型方法,使用了类的泛型
    public T n(T t,R r) {
        return t;
    }

    //非泛型方法,使用了类的泛型
    public A<T,R> m(T t,R r){
        A<T,R> a = new A<>();
        return a;
    }

    //无参构造器
    public A() {
    }

    //有参构造器
    public A(T t, R r) {
        this.t = t;
        this.r = r;
    }
}

(5)给泛型指定具体类型后,可以传入该类型其子类类型 

public class Test {
    public static void main(String[] args) {
        A<B> a1 = new A<B>(new B());
        A<B> a2 = new A<B>(new C());
    }
}

class A<E> {
    public A(E e) {
        this.e = e;
    }
}

class B {
}

class C extends B {
}

2、自定义泛型接口

(1)在接口声明时通过标识表示类中某个成员的引用类型,成员方法/默认方法可以使用泛型

(2)静态成员不能使用泛型

(3)继承或实现接口时指定类型,没有指定类型,默认为Object

interface A<T, R> {
    T n1(R r);

    default T n2(R r) {
        return null;
    }
}

interface B extends A<String, Integer> {
}

class C implements B {
    @Override
    public String n1(Integer integer) {
        return null;
    }
}

class D implements A<String, Integer> {
    @Override
    public String n1(Integer integer) {
        return null;
    }
}

3、自定义泛型方法

(1)泛型方法可以定义在普通类中,也可以定义在泛型类中

(2)泛型方法被调用时确定类型

(3)泛型方法既可以使用自己声明的泛型,也可以使用类声明的泛型

public class Test {
    public static void main(String[] args) {
        new Test().run("String");
    }

    public <T> void run1(T t){
        System.out.println(t);
    }
    public static <T> void run2(T t){
        System.out.println(t);
    }
}
class A<T> {
    private T t;

    //泛型类中的泛型方法的泛型T与类中的泛型T没有任何关系,可以是不同的类型
    public <T> void a(T t) {
    }

    //泛型类中的静态泛型方法的泛型R与类中的泛型T没有任何关系,可以是不同的类型
    public static <R> void b(R r) {
    }

    //泛型类中的静态方法如果想使用类中的泛型,需要将这个方法定义成泛型方法
    public static <T> T c(T t) {
    }

    public T getT() {
        return t;
    }
    public void setT(T t) {
        this.t = t;
    }
    public A() {
    }
    public A(T t) {
        this.t = t;
    }
}

八、反射

1、反射机制

 允许程序在执行期间借助于Reflection API取得任何类的内部信息并能操作对象的属性和方法

(1)可以判断任意一个对象所属的类

(2)可以构造任意一个类的对象

(3)可以得到任意一个类所具有的成员变量和方法

(4)可以调用任意一个对象的成员变量/方法

(5)生成动态代理

2、反射相关类

(1)java.lang.Class:代表一个类,Class对象表示某个类加载后在堆中的对象

(2)java.lang.reflect.Method:代表类的方法,Method对象表示某个类的方法

(3)java.lang.reflect.Field:代表类的成员变量,Field对象表示某个类的成员变量

(4)java.lang.reflect.Constructor:代表类的构造方法,Constructor对象表示某个类的构造器

(5)反射调用性能优化:Method,Field,Constructor对象都有setAccesssible()方法,作用是启动和禁用访问安全检查的开关,参数值为true时,反射的对象在使用时取消访问检查,提高反射的效率,反之

        Properties p  = new Properties();
        p.load(new FileInputStream("D:\\code\\studyjava\\src\\set.properties"));
        String classPath = p.getProperty("classPath");
        String methodName = p.getProperty("methodName");
        String fieldName = p.getProperty("fieldName");

        //通过Class类的方法forName加载类,返回Class类的对象(一个类只有一个Class对象)
        Class c = Class.forName(classPath);
        //返回加载类的对象
        Object o = c.newInstance();
        //返回Method类的对象,通过Method类的对象调用
        Method m = c.getMethod(methodName);
        m.invoke(o);
        //返回Field类的对象,通过Field类的对象调用(不能得到私有的属性)
        Field f = c.getField(fieldName);
        f.get(o);
        //返回无参/有参构造器
        Constructor c1 = c.getConstructor();
        Constructor c2 = c.getConstructor(String.class);
        //取消访问检查
        m.setAccessible(true);
        f.setAccessible(true);
        c1.setAccessible(true);
        c2.setAccessible(true);

3、Class类

(1)Class类对象不是new出来的,而是系统创建的

        //用于配置文件:forName方法
        Class c1 = Class.forName("com.javastudy.Cat");
        //用于参数传递:类名.class
        Class c2 = Cat.class;
        //用于已有对象实例
        Cat cat = new Cat();
        Class c3 = cat.getClass();
        //通过类加载器
        ClassLoader classLoader = cat.getClass().getClassLoader();
        Class c4 = classLoader.loadClass("com.javastudy.Cat");
        //基本数据类型.class
        Class c5 = int.class;
        //基本数据类型对应的包装类.TYPE
        Class c6 = Integer.TYPE;
        System.out.println(c5==c6);

(2)对于某个类的Class类对象,因为类只加载一次,在内存中只有一份,存放在堆中

(3)每个类的实例都会记得自己由哪个Class的实例所生成

(4)通过Class可以完整地得到一个类的完整结构

        //获取Cat类对应的Class对象
        Class c = Class.forName("com.javastudy.Cat");
        //输出c是哪个类的Class对象
        System.out.println(c);
        //输出c的运行类型
        System.out.println(c.getClass());
        //得到包名
        c.getPackage().getName();
        //得到全类名
        c.getName();
        //通过c创建对象实例
        Object object = c.newInstance();
        Cat cat = (Cat) c.newInstance();
        //通过c获取成员变量
        Field[] fields = c.getFields();
        Field f = c.getField("name");
        //通过c修改成员变量,cat对象的f属性设置成jack
        f.set(cat,"Jack");

(5)外部类,内部类,接口,数组,二维数组,注解,枚举,基本数据类型,void,都有对应的class对象

4、类加载

(1)静态加载:编译时加载相关的类,

(2)动态加载:运行时加载相关的类

5、反射获取类的结构信息

        Class c = Cat.class;
        //获取全类名
        c.getName();
        //获取简单类名
        c.getSimpleName();
        //获取所有public修饰的属性,包含本类以及父类的
        c.getFields();
        //获取本类中所有属性
        c.getDeclaredFields();
        //获取所有public修饰的方法,包含本类以及父类的
        c.getMethods();
        //获取本类中所有方法
        c.getDeclaredMethods();
        //获取所有public修饰的构造器,包含本类不包含父类的
        c.getConstructors();
        //获取本类中所有构造器 
        c.getDeclaredConstructors();
        //以Package形式返回包信息
        c.getPackage();
        //以Class形式返回父类信息
        c.getSuperclass();
        //以Class[]形式返回接口信息
        c.getInterfaces();
        //以Annotation[]形式返回注解信息
        c.getAnnotations();
        Class c = Cat.class;
        Field f = c.getField("name");
        //以int形式返回属性的修饰符,默认:0,public:1,private:2,protected:4
        //static:8,final:16,多个修饰数值相加
        System.out.println(f.getModifiers());
        //以Class形式返回属性的类型
        System.out.println(f.getType());
        //返回属性名
        System.out.println(f.getName());
        Class c = Cat.class;
        Method m = c.getMethod("run");
        //以int形式返回方法的修饰符,默认:0,public:1,private:2,protected:4
        //static:8,final:16,多个修饰数值相加
        System.out.println(m.getModifiers());
        //以Class形式返回方法的返回类型
        System.out.println(m.getReturnType());
        //返回方法名
        System.out.println(m.getName());
        //以Class[]返回方法的参数类型数组
        m.getParameterTypes();
        Class c = Cat.class;
        Constructor cs = c.getConstructor();
        //以int形式返回构造器的修饰符,默认:0,public:1,private:2,protected:4
        //static:8,final:16,多个修饰数值相加
        System.out.println(cs.getModifiers());
        //返回构造器名
        System.out.println(cs.getName());
        //以Class[]返回构造器的参数类型数组
        cs.getParameterTypes();

6、通过反射机制创建对象

public class TestA {
    public static void main(String[] args) throws Exception {
        Class c = Cat.class;
        //通过public的无参构造器
        Object o1 = c.newInstance();
        //通过public的有参构造器
        Constructor cs1 = c.getConstructor(String.class);
        Object o2 = cs1.newInstance("Jack");
        //通过非public的有参构造器
        Constructor cs2 = c.getDeclaredConstructor(String.class,int.class);
        cs2.setAccessible(true);    //暴破:使用反射可以访问private构造器
        Object o3 = cs2.newInstance("Bob",20);
    }
}

class Cat {
    private String name = "Tom";
    private int age = 10;

    public void run() {
        System.out.println(1);
    }

    public Cat() {
    }

    public Cat(String name) {
        this.name = name;
    }

    private Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class TestA {
    public static void main(String[] args) throws Exception {
        Class c = Cat.class;
        Object o = c.newInstance();
        //通过反射得到age属性对象
        Field f1 = c.getField("age");
        f1.get(o);
        //通过反射操作属性
        f1.set(o,20);

        //操作私有的属性,暴破
        Field f2 = c.getDeclaredField("name");
        f2.setAccessible(true);
        f2.get(o);
        f2.set(o,"Jack");
        f2.set(null,"Bob");    //因为name是static属性,因此o也可以写成null
    }
}

class Cat {
    private static String name = "Tom";
    public int age = 10;

    public void run() {
        System.out.println(1);
    }

    public Cat() {
    }

    public Cat(String name) {
        this.name = name;
    }

    private Cat(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class TestA {
    public static void main(String[] args) throws Exception {
        Class c = Cat.class;
        Object o = c.newInstance();
        //通过反射得到方法run
        Method m1 = c.getMethod("run");
        //如果方法有返回值,统一返回Object
        Object returenValue = m1.invoke(o);
        System.out.println(returenValue);

        //操作私有的方法,暴破
        Method m2 = c.getDeclaredMethod("walk", int.class);
        m2.setAccessible(true);
        m2.invoke(null,2);
    }
}

class Cat {
    public int run() {
        System.out.println(1);
        return 1;
    }

    private static void walk(int n) {
        System.out.println(n);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值