Java-泛型

泛型的引出

测试代码

package com.pero.generic;

import java.util.ArrayList;

/**
 * 在ArrayList中添加3个Dog对象
 * Dog对象含有name和age,并输出name和age
 *
 * @author Pero
 * @version 1.0
 */
@SuppressWarnings({"all"})

public class Test {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add(new Dog("小灰", 2));
        arrayList.add(new Dog("小白", 3));
        arrayList.add(new Dog("小黑", 5));
        arrayList.add(new Cat("小花",4));

        for (Object object : arrayList) {
            Dog dog = (Dog) object;  //遇到Cat类的小花时,报错ClassCastException
            System.out.println(dog);
        }

    }
}

class Dog {
    private String name;
    private int age;

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

    public Cat(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 "Dog{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

问题分析

1)不能对加入集合的数据类型进行约束,不安全!

2)便利的时候需要对类型转换,如果集合中的数据量比较大,会影响效率;

使用泛型的好处

1)编译时,检查添加元素的类型提高安全性;

2)减少了类型转换提高效率;

不使用泛型时:Dog  -加入->  Object  -取出->  Dog;添加进ArrayList中会先转成Object,取出时需要转成Dog,才能调用Dog的方法;

使用泛型时:Dog  -加入->  Dog  -取出->  Dog;存放和取出都是Dog,不需要在转型。

3)不再提示编译警告;

添加泛型之后代码

package com.pero.improve;

import java.util.ArrayList;

/**
 * @author Pero
 * @version 1.0
 */
public class Generic_ {
    public static void main(String[] args) {

        //ArrayList<Dog>表示存放到ArrayList集合集合中的元素时Dog类型
        //编译器如果发现存放的类型不满足条件就会报错
        //在遍历时,直接取出Dog类型,而不是Object类型
        ArrayList<Dog> arrayList = new ArrayList<Dog>();
        arrayList.add(new Dog("小灰", 2));
        arrayList.add(new Dog("小白", 3));
        arrayList.add(new Dog("小黑", 5));
        //arrayList.add(new Cat("小花",4));  //编译器发现存放的类型不满足条件,报错
        for (Dog dog :arrayList) {
            System.out.println(dog.getName()+dog.getAge());
        }

    }
}

基本介绍

1)泛型又称为参数化类型,是jdk5.0出现的新特性,解决数据类型的安全问题;

2)在类声明或实例化时指定需要的具体类型;

3)Java泛型可以保证如果程序在编译时没有发出警告,则运行时就不会产生;

4)泛型的作用是:可以在类声明时通过一个标识表示类中某个属性的类型,或者是某个方法的返回值的类型,或者是参数类型。

package com.pero.generic;

import java.util.Objects;

/**
 * @author Pero
 * @version 1.0
 */
@SuppressWarnings({"all"})

public class Generic01 {
    public static void main(String[] args) {
        Person<String, Integer> person = new Person<String, Integer>("jack",28);
        //new Person<String,Integer>(100,30);   //此时就会报错,在编译时就已经明确了参数的类型规定
        person.show();  //class java.lang.String
    }

}

//在类声明时定义泛型,通过一个标识符表示类中某个属性的类型,
// 创建Person对象时确定泛型类型(比如Person<String,Integer>,
// String类型替换了Person类的E,Integer类型替换了Person类的T),
// 在编译期间就确定E的类型!
class Person<E,T>{
    E name;      //规范name的类型,在创建对象时明确类型
    T age;      //规范age的类型,在创建对象时明确类型

    public Person(E name, T age) {
        this.name = name;
        this.age = age;
    }

    public void show(){
        System.out.println(name.getClass());
    }

    public E getName() {
        return name;
    }

    public void setName(E name) {
        this.name = name;
    }

    public T getAge() {
        return age;
    }

    public void setAge(T age) {
        this.age = age;
    }

    public E e(){
        return name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Person<?, ?> person = (Person<?, ?>) o;
        return Objects.equals(name, person.name) && Objects.equals(age, person.age);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
        return "Person{" +
                "name=" + name +
                ", age=" + age +
                '}';
    }
}

泛型的声明

interface 接口<T>{}和class 类<K,V>{}
例如:List,ArrayList
说明:
1)其中K,T,V并不代表值,而是表示类型;
2)任意字母都可以作为泛型的表示,通常用T(Type)。
3)要在类名后面指定类型参数的值(类型):
①List<String> strList = new ArrayList<String>();
②Iterator<Customer> iterator = customer.iterator();

package com.pero.generic;

import java.util.*;

/**
 * 创建三个学生对象
 * 放到HashMap中,要求Key是String name,Value就是学生对象
 * 使用两种方式遍历
 *
 * @author Pero
 * @version 1.0
 */


public class GenericExercise {
    public static void main(String[] args) {

        //3个学生对象
        Student<String> jack = new Student<String>("jack");
        Student<String> tom = new Student<String>("tom");
        Student<String> lucy = new Student<String>("lucy");

        //HashMap
        HashMap<String, Student> hashMap = new HashMap<String, Student>();

        hashMap.put("jack", jack);
        hashMap.put("tom", tom);
        hashMap.put("lucy", lucy);

        //先取出EntrySet
        /*
        public Set<Map.Entry<K(替换成String),V(替换成Person)>> entrySet() {
            Set<Map.Entry<K,V>> es;
            return (es = entrySet) == null ? (entrySet = new EntrySet()) : es;
        }
        */
        Set<Map.Entry<String, Student>> entries = hashMap.entrySet();
        //迭代器遍历
        /*  //EntrySet类是HashMap的内部类
        final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
            //entries.iterator()会调用该方法,<K(替换成String),V(替换成Person)>
            public final Iterator<Map.Entry<K,V>> iterator() {
                return new EntryIterator();
            }
        }
        */
        Iterator<Map.Entry<String, Student>> iterator_ = entries.iterator();
        while (iterator_.hasNext()) {
            Map.Entry<String, Student> entry = iterator_.next();
            System.out.println(entry.getKey() + "-" + entry.getValue());
        }

        //遍历增强for遍历
        for (Object object : entries) {
            Map.Entry entry = (Map.Entry) object;
            System.out.println(entry.getKey() + "-" + entry.getValue());
        }

        //HashSet
        HashSet<Student> students = new HashSet<Student>();
        students.add(jack);
        students.add(tom);
        students.add(lucy);
        //迭代器遍历
        Iterator<Student> iterator = students.iterator();
        while (iterator.hasNext()) {
            Student student = iterator.next();
            System.out.println(student);
        }
        //增强for遍历
        for (Student student : students) {
            System.out.println(student);
        }


    }
}

class Student<T> {
    private T name;

    public Student(T name) {
        this.name = name;
    }

    public T getName() {
        return name;
    }

    public void setName(T name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Student:" + name;
    }
}

泛型使用细节

1)interface List <T>{},public class HashSet<E>{}...等

      T,E只能是引用类型,不能是基本数据类型

2)在指定泛型具体类型后,可以传入该类型或者其子类类型

3)泛型使用形式:

      ①List<Integer> list1 = new ArrayList<Integer>();

      ②List<Integer> list2 = new ArrayList<>();

4)List list3 = new ArrayList();默认泛型<E>是Object;

package com.pero.generic;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Pero
 * @version 1.0
 */
public class GenericDetail {
    public static void main(String[] args) {

        //给泛型指定数据类型时,要求是引用类型不能是基本数据类型
        List<Integer> list = new ArrayList<Integer>();
        //List<int> list1 = new ArrayList<int>();  //编译报错

        //在指定泛型具体类型后,可以传入该类型或者其子类类型
        List<Animal> animals = new ArrayList<Animal>();
        animals.add(new Animal());  //可以添加泛型规定的类型
        animals.add(new Tiger());   //可以添加泛型规定类型的子类型
        //animals.add(new Persons());   //不能添加

        //泛型使用形式
        List<Integer> list1 = new ArrayList<Integer>();
        ArrayList<Integer> integers = new ArrayList<Integer>();
        //简写(日常使用,编译器会进行类型推断)
        ArrayList<Integer> integers1 = new ArrayList<>();
        List<Integer> list2 = new ArrayList<>();

        //默认泛型是Object
        ArrayList arrayList = new ArrayList();
        //等价于ArrayList<Object> arrayList = new ArrayList<Object>();
        Persons persons = new Persons();
        /*  上面的对象创建,相当于其类如下:
        class Persons{
            Object name;
            public Persons(){};
            public Persons(Object name){
                this.name = name;
            }
        }
        */

    }
}
class Animal {}
class Tiger extends Animal{}

class Persons<E>{
    E name;
    public Persons(){};
    
    public Persons(E name){
        this.name = name;
    }
}

练习代码

package com.pero.generic;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;

/**
 * 定义Employee类
 * 1)该类包含:private成员变量name、salary、birthday,其中birthday为MyData类的对象;
 * 2)为每一个属性定义getter和setter方法;
 * 3)重写toString方法,输出name、salary、birthday;
 * 4)MyDate类包含:private成员变量month,day,year;并为每一个属性定义getter和setter方法;
 * 5)创建该类的3个对象,并把这些对象放入ArrayList集合中(ArrayList需要用泛型定义),
 * 对集合中的元素进行排序,并遍历输出(排序方法:调用ArrayList的sort()方法,传入Comparator对象【使用泛型】),
 * 先按照name排序,如果name相同,则按照生日日期排序。
 *
 * @author Pero
 * @version 1.0
 */
@SuppressWarnings({"all"})

public class GenericHomework {
    public static void main(String[] args) {

        Employee jack = new Employee("jack", 2300, new MyDate(1995, 12, 1));
        Employee tom = new Employee("tom", 3300, new MyDate(1996, 1, 20));
        Employee lucy = new Employee("lucy", 4300, new MyDate(1997, 1, 28));

        ArrayList<Employee> employees = new ArrayList<Employee>();
        employees.add(jack);
        employees.add(tom);
        employees.add(lucy);
        employees.add(new Employee("smith",3600,new MyDate(2002,3,2)));
        employees.add(new Employee("smith",5900,new MyDate(2002,3,1)));
        employees.add(new Employee("jack",8800,new MyDate(1996,1,20)));


        employees.sort(new Comparator<Employee>() {
            @Override
            public int compare(Employee o1, Employee o2) {
                if (!(o1 instanceof Employee && o2 instanceof Employee)) {
                    System.out.println("类型不匹配");
                    return 0;
                }
                int i = o1.getName().compareTo(o2.getName());   //名字排序
                if (i != 0) {
                    return i;
                } else {
                    return o1.getMyDate().minDate(o2.getMyDate());  //调用年龄比较方法,早出生的放在前面
                }

            }
        });

        Iterator<Employee> iterator = employees.iterator();
        while (iterator.hasNext()) {
            Employee employee = iterator.next();
            System.out.println(employee);
        }

    }
}

class Employee {
    private String name;
    private double salary;
    private MyDate myDate;

    public Employee(String name, double salary, MyDate myDate) {
        this.name = name;
        this.salary = salary;
        this.myDate = myDate;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public MyDate getMyDate() {
        return myDate;
    }

    public void setMyDate(MyDate myDate) {
        this.myDate = myDate;
    }

    @Override
    public String toString() {
        return "name='" + name + ", salary=" + salary + ", myDate=" + myDate;
    }
}

class MyDate {
    private int year;
    private int month;
    private int day;

    public MyDate(int year, int month, int day) {
        this.year = year;
        this.month = month;
        this.day = day;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonth() {
        return month;
    }

    public void setMonth(int month) {
        this.month = month;
    }

    public int getDay() {
        return day;
    }

    public void setDay(int day) {
        this.day = day;
    }

    @Override
    public String toString() {
        return year + "-" + month + "-" + day;
    }

    public int minDate(MyDate myDate) {
        int yearMinus = this.getYear() - myDate.getYear();
        int monthMinus = this.getMonth() - myDate.getMonth();
        int dayMinus = this.getDay() - myDate.getDay();

        if (yearMinus != 0) {
            return yearMinus;
        }
        if (monthMinus != 0) {
            return monthMinus;
        }
        return dayMinus;
    }
}

自定义泛型类

基本语法

class  类名  <T,R,...>{

        成员

}

注意细节

1)普通成员可以使用泛型(属性、方法);

2)使用泛型的数组,不能初始化;

3)静态方法中不能使用类的泛型;

4)泛型类的类型,是在创建对象时确定的(因为创建对象时,需要指定确定类型);

5)如果在创建对象时,没有指定类型,默认为Object;

package com.pero.customgeneric;

/**
 * 自定义泛型类
 *
 * @author Pero
 * @version 1.0
 */


public class CustomGeneric {
    public static void main(String[] args) {

    }
}
//Tiger后面有泛型,Tiger称为自定义泛型类
//一般是单个的大写字母作为泛型的标识符,例如:R,S,T...
//泛型的标识符可以有多个
class Tiger<R,S,T>{
    String name;
    R r;
    S s;
    T t;

    //数组在new时不能确定T的类型,无法在内存中分配空间
    T[] ts;
    //T[] ts = new T[8];  //可以声明,不能初始化

    //静态属性和方法中不能使用类的泛型,静态方法是和类相关的,在类加载时对象还没有创建,
    // 如果静态方法和静态属性中使用泛型,泛型不能确定,JVM就无法完成初始化;
//    private static T t1;
//    public static void s(S s){
//
//    }

    public Tiger(String name, R r, S s, T t) {
        this.name = name;
        this.r = r;
        this.s = s;
        this.t = t;
    }

    //方法使用泛型,返回类型可以是泛型
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public R getR() {
        return r;
    }

    public void setR(R r) {
        this.r = r;
    }

    public S getS() {
        return s;
    }

    public void setS(S s) {
        this.s = s;
    }

    public T getT() {
        return t;
    }

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

}

练习代码

package com.pero.customgeneric;

/**
 * @author Pero
 * @version 1.0
 */
public class Test_ {
    public static void main(String[] args) {
        MyGeneric<Double, String, Integer> john = new MyGeneric<>("john");
        john.setR(10.9);
        //john.setR("jack"); setR(R r)方法内的参数必须是R泛型类型的,这里是Double类型
        System.out.println("john:"+john);

        //这里相当于MyGeneric<Object,Object,Object> myGeneric = new MyGeneric<>();
        MyGeneric myGeneric = new MyGeneric("john~~");
        //setR(R r)方法类泛型的类型现在是Object类,"yy"是String类,
        // String类是Object的子类,所以可以传进去
        myGeneric.setT("yy");
        System.out.println("myGeneric:"+myGeneric);
    }
}
class MyGeneric<R,S,T>{
    R r;
    S s;
    T t;

    public MyGeneric(S s){
        this.s = s;
    }

    public MyGeneric(R r, S s, T t) {
        this.r = r;
        this.s = s;
        this.t = t;
    }

    public R getR() {
        return r;
    }

    public void setR(R r) {
        this.r = r;
    }

    public S getS() {
        return s;
    }

    public void setS(S s) {
        this.s = s;
    }

    public T getT() {
        return t;
    }

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

自定义泛型接口

基本语法

interface 接口名<R,S,T...>{

}

注意细节

1)接口中,静态成员不能使用泛型;

2)泛型接口的类型,在继承接口或者实现接口时确定;

3)没有指定类型,默认为Object。

package com.pero.customgeneric;

/**
 * @author Pero
 * @version 1.0
 */


public class CustomInterfaceGeneric {
    public static void main(String[] args) {

    }
}

//在继承接口时指定泛型接口的类型
interface IA extends IUsb<String,Double>{

}

//在类实现接口时,接口所指定的泛型类型,在类中会直接进行替换
class AA implements IA{
    @Override
    public Double get(String s) {
        return null;
    }

    @Override
    public void hi(Double aDouble) {

    }

    @Override
    public void run(Double r1, Double r2, String u1, String u2) {

    }  //必须实现接口的所有抽象方法,否则编译器报错

}

//在实现接口时,直接指定泛型接口的类型
//类中实现接口方法时,泛型会直接进行替换
class BB implements IUsb<Integer,Float>{

    @Override
    public Float get(Integer integer) {
        return null;
    }

    @Override
    public void hi(Float aFloat) {

    }

    @Override
    public void run(Float r1, Float r2, Integer u1, Integer u2) {

    }
}

//自定义泛型接口
interface IUsb<U,R>{
    int n = 10;
    //U u;      //接口中的成员都是静态属性的,不能使用泛型声明成员

    //普通方法中,可以使用接口泛型
    R get(U u);

    void hi(R r);

    void run(R r1,R r2,U u1,U u2);

    //在jdk8中,可以在接口中,使用默认方法,也是可以使用泛型
    //default是在java8中引入的关键字,在接口内部包含了一些默认的方法实现,
    //从而使得接口在进行扩展的时候,不会破坏与接口相关的实现类代码。
    default R method(U u){
        return null;
    }
}

//如果没有指定泛型类型,默认用Object替换泛型
//如果不明确泛型定义什么都不写,则会提醒警告
class CC implements IUsb<Object,Object>{  

    @Override
    public Object get(Object o) {
        return null;
    }

    @Override
    public void hi(Object o) {

    }

    @Override
    public void run(Object r1, Object r2, Object u1, Object u2) {

    }
}

自定义泛型方法

基本语法

修饰符 <R,S,T...>返回类型 方法名(参数列表){

}

注意细节

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

)当泛型方法被调用时,类型会确定;

3)public void eat(E e){},修饰符后没有<R,S,T...>,方法不是泛型方法,而是使用了泛型;

package com.pero.customgeneric;

/**
 * @author Pero
 * @version 1.0
 */
public class CustomMethodGeneric {
    public static void main(String[] args) {
        Car car = new Car();
        car.fly("宝马",2330); //当调用方法时,传入参数,编译器就会确定类型
        System.out.println("=================================");
        car.fly(25330,2210);

        Fish<String, Integer> stringIntegerFish = new Fish<>();
        stringIntegerFish.eat("jack",126.6,'s');
    }
}

//泛型方法,可以定义在普通类中,也可以定义在泛型类中
//普通类
class Car {
    public void run() {  //普通方法

    }
    //<T,V>就是泛型,提供给fly()方法使用
    public <T, V> void fly(T t, V v) {   //泛型方法
        System.out.println(t.getClass());
        System.out.println(v.getClass());
    }

//使用泛型的普通方法,普通类中不能这样使用,编译报错(S s)
//    public void swimming(S s){        //没有声明S泛型,无法找到
//
//    }
}

//泛型类
class  Fish<T,V>{
    public void run(){  //普通方法

    }
    //泛型方法,可以使用类声明的泛型,也可以使用方法自己定义的泛型
    public <R,S> void eat(T t,R r,S s){
        System.out.println(t.getClass());
        System.out.println(r.getClass());
        System.out.println(s.getClass());

    }
    //使用泛型的普通方法,不是泛型方法
    //使用类定义声明的泛型T
    public void swimming(T t){

    }
}

练习代码

package com.pero.customgeneric;

/**
 * @author Pero
 * @version 1.0
 */

public class CustomMethodGenericExercise {
    public static void main(String[] args) {
        Apple<String, Integer, Double> apple = new Apple<>();
        apple.fly(10);
        apple.fly(new Dog());
    }
}
class Apple<T,R,M>{ //泛型类
    public <E> void fly(E e){   //泛型方法
        System.out.println(e.getClass().getSimpleName());
    }
    //public void eat(U u){}    //查找不到泛型U,没有声明报错
    public void run(M m){}
}
class Dog{}

泛型的继承和通配符

1)泛型不具备继承性;//List<Object> list = new ArrayList<String>();这样写错误

2)<?>:支持任意泛型类型;

3)<? entends A>支持A类以及A的子类,规定了泛型类型的范围上限

4)<? super A>支持A类以及A的父类,不限于直接父类,规定了泛型的下限;

package com.pero.customgeneric;

import java.util.ArrayList;
import java.util.List;

/**
 * @author Pero
 * @version 1.0
 */

public class GenericExtends {
    public static void main(String[] args) {

        Object object = new String("pero");

        //泛型没有继承性
        //List<Object> list = new ArrayList();

        List<Object> list1 = new ArrayList<>();
        List<String> list2 = new ArrayList<>();
        List<Animal> list3 = new ArrayList<>();
        List<Monkey> list4 = new ArrayList<>();
        List<Person> list5 = new ArrayList<>();
        
        //printCollection1(可以接受任意类型)
        printCollection1(list1);
        printCollection1(list2);
        printCollection1(list3);
        printCollection1(list4);
        printCollection1(list5);

        //printCollection2(只能接收Animal类型和Animal的子类类型)
        //printCollection2(list1);  //报错,Object类是Animal的父类
        //printCollection2(list2);  //报错,String类与Animal类不相关
        printCollection2(list3);
        printCollection2(list4);
        printCollection2(list5);
        
        //只能接收Animal类型和Animal的父类
        printCollection3(list1);
        //printCollection3(list2);  //报错,String类与Animal类不相关
        printCollection3(list3);
        //printCollection3(list4);  //报错,Monkey类是Animal类的子类
        //printCollection3(list5);  //报错,person类是Animal类的子类
        
    }
    //List<?>表示任意泛型类型都可以接收
    public static void printCollection1(List<?> c) { //<?>通配符
        for (Object o : c) {
            System.out.println(o);
        }
    }
    //? extends Animal 表示泛型可以接收Animal和Animal的子类类型,确定范围上限
    public static void printCollection2(List<? extends Animal> c) {
        for (Object o : c) {
            System.out.println(o);
        }
    }
    //? super Animal 表示泛型可以接收Animal和Animal 的父类,确定范围下限
    public static void printCollection3(List<? super Animal> c) {
        for (Object o : c) {
            System.out.println(o);
        }
    }
}

class Animal {}

class Monkey extends Animal {}

class Person extends Monkey {}

JUnit单元测试类

为什么使用JUnit

1)一个类有很多功能代码需要测试,为了测试,就需要写到main方法中;

2)如果有多个功能代码测试,就需要来回注销,切换很麻烦;

3)如果可以直接运行一个方法,就方便很多,并且可以给出相关信息。

基本介绍

1)JUnit是一个Java语言的单元测试框架;

2)多数Java的开发环境都已经集成了Junit作为单元测试的工具

使用步骤:

1)在测试方法上一行添加@Test;

2)然后点击Alt+Enter,然后选择Add 'JUnit5.8.1' to classpath;

3)跟随引导添加即可。

package com.pero.junit_;

import org.junit.jupiter.api.Test;

/**
 * @author Pero
 * @version 1.0
 */
public class JUnit_ {
    public static void main(String[] args) {

        //传统方式
        //new JUnit_().m1();
        //new JUnit_().m2();
    }
    
    //JUnit单元测试,可以对方法进行单独测试
    @Test
    public void m1(){
        System.out.println("m1()被调用");
    }
    @Test
    public void m2(){
        System.out.println("m2()被调用");
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值