Java SE 复习

目录

目录

一、基础

二、数组

三、面向对象

1、杂项

2、封装

3、构造器(构造方法)

4、继承

5、多态

6、包装类

7、设计模式

1、单例设计模式

8、代码块

 9、抽象方法与抽象类

10、接口

11、内部类 

四、异常类

五、多线程

1、多线程的创建

2、线程的生命周期

3、线程的同步

4、线程的通信问题

六、常用类

1、String 

2、StringBuilder和StringBuffer

3、时间api

4、java比较器

5、Math类

 七、枚举类

八、注解

九、集合

1、List家族

Arraylist

Vector

2、Set

HashSet

LinkHashSet

TreeSet

3、Map

HashMap

LinkedHashMap

TreeMap

Hashtable


2021-12-18更


一、基础

1、命名规范

包名       全部小写xxxyyyzzz
类,接口名大驼峰XxxYyyZzz
变量方法名小驼峰xxxYyyZzz
常量名全部大写XXX_YYY_ZZZ

 2、基本数据类型的长度

byte1字节float4字节
short2字节double8字节
int4字节char2字节
long8字节boolean1字节

3、逻辑运算符注意事项

4、三元运算符 

(我爱你)?娶你:分手;

####如果我真的爱你,那么我就娶你,如果是假的就分手把!

5、循环之switch          //case必须是常量

二、数组

1、foreach循环遍历数组

public static void main(String[] args) {
      double[] arr01 = {1.9, 2.9, 3.4, 3.5};
 
      // 打印所有数组元素
      for (double element: arr01) {
         System.out.println(element);
      }
   }


//直接打印的方法
System.out.println(Arrays.toString(arr01));

2.暂时还没有想到。。。。。。

三、面向对象

1、杂项

1、匿名对象

直接new Object().方法,就是不起名字,直接调用。用于一次性使用或者作为参数。

2、成员变量也就是属性,存在于堆空间,有默认值。

      局部变量存在于栈空间,没有默认值。

3、方法的重载

        在同一个类中,允许存在一个以上的同名方法,只要它们的参数个数或者参数
类型不同即可。

4、可变形参

public class test3 {
    public static void main(String[] args) {
        test("a","b","c");
    }
    public static void test(String...str){
        System.out.println(str[1]);             //b
        System.out.println(str.length);         //3
    }
}

5、方法的值传递机制

对于基本数据类型,传入的是实际的数值

对于引用数据类型,传入的是地址值

下面是经典的题,可以试试。

public class test3 {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        method(a,b);    //编写方法使得调换a和b的数值。
    }
}

6、将对象作为参数传递给方法,一个比较神奇的设定,你可以把一个🐖的实例塞进去。

7、递归,主要就是递归公式和结束条件两方面。下面写一下n的阶乘~

public class test4 {
    public static void main(String[] args) {
        System.out.println(jiechen(6));
    }
    public static int jiechen(int n) {
        int flag = 0;
        if (n == 1) {
            return 1;
        } else {
            return n * jiechen(n - 1);
        }
    }
}

8、属性的赋值顺序

①默认初始化 ②显式初始化  ③构造器赋值  ④通过方法调用赋值

9、JavaBean

符合①类是公共的②有一个无参的公共构造器③提供get和set方法

10、面试题:==和equals的爱恨情仇

  • == 既可以比较基本类型也可以比较引用类型。对于基本类型就是比较值,对于引用类型
    就是比较内存地址
  • equals的话,它是属于java.lang.Object类里面的方法,如果该方法没有被重写过默认也
    是==;我们可以看到String等类的equals方法是被重写过的,而且String类在日常开发中
    用的比较多,久而久之,形成了equals是比较值的错误观点。
  • 具体要看自定义类里有没有重写Object的equals方法来判断。

11、static关键字

用来修饰属性、方法、代码块、内部类,被static修饰后,随着类的加载而加载,被所有对象共享

2、封装

下面才是真正的走进java面向对象的大门----封装

封装顾名思义就是把一个东西封存起来,至于是哪些东西呢,肯定是见不得人的东西,把一些复杂的结构封装起来,只对外暴露简单的接口,提高了系统的可扩展性和可维护性。

下面的表懒得手打,就直接拉过来了😀


                                                         2021-12-18AM更


3、构造器(构造方法)

1、构造器就是用来new对象的,并且可以给对象初始化(比如让她天生丽质🤭),每个类都会提供一个空参构造器,当然你如果不满意可以重载若干个构造器,当你重载后,默认提供的就会偷偷的跑掉。根据习惯,重载时再补上一个空参构造器。需要注意的是,继承时构造器不会被子类继承。

2、如果一个类中声明了n个构造器,则最多有n - 1个构造器中使用了"this(形参列表)"

     在类的一个构造器中,最多只能声明一个"this(形参列表)"

4、继承

        子承父业,发扬光大,说的就是继承后,子类比父类的功能更加强大丰富,减少了代码的冗余,毕竟爸爸打下的天下,我为何还要自己打一遍,那不是造反呢。继承的出现为后面的多态埋下了伏笔。当然需要注意的是,不要为了实现父类一点点的功能而去继承,不值得。

1、继承后获得了父类的属性方法,当然不包括private的属性方法

2、使用extends关键字,不能多继承。

3、方法的重写(与上面的方法重载放一起是面试重点)

  • 方法名与参数列表保持一致
  • 返回值类型不能大于父类
  • 权限修饰符不能小于父类
  • 抛出的异常不能大于父类
  • 用时声明为为static的

4、关于继承后构造器的问题

  • 子类中所有的构造器默认都会访问父类中空参构造器
  • 当父类中没有空参数的构造器时,子类的构造器必须通过this(参数列表)或者super(参数列表)语句指定调用本类或者父类中相应的构造器。同时,只能”二选一”,且必须放在构造器的首行
  • 如果子类构造器中既未显式调用父类或本类的构造器,且父类中又没有无参的构造器,则编译出错

5、多态

1、定义:父类的引用指向子类的对象

Person person = new Son();

2、前提条件:①需要存在继承或者实现关系   ②有方法的重写

3、成员变量不具备多态。

4、instanceof方法,判断前者是否是后者的实例或者子类的实例

jiayiing instanceof Person   //true

5、向上转型,向下转型。

6、包装类

1、java设计之初就是一个面向对象的编程语言,然而基本数据类型的出现,就让它变得不那么面向对象,包装类的出现就是为了解决这个问题。

2、接下来就是涉及到基本数据类型,包装类以及String之间相互的转换

①基本数据类型<===>包装类

这里有自动装箱与自动拆箱

②基本数据类型<===>String

public static void main(String[] args) {
        int a = 5;
        String str01 = 5+"";

        String str02 = "6";
        int i = parseInt(str02);
    }

7、设计模式

1、单例设计模式

 单例设计模式就是只会产生一个对象实例,根据生成的时间又分为饿汉式和懒汉式

8、代码块

 9、抽象方法与抽象类

1、含有抽象方法的类一定是抽象类,用abstract修饰。抽象类是被用来继承,抽象类不能被实例化,继承后需要重写抽象方法。

10、接口

1、接口(interface)是抽象方法和常量值定义的集合。

2、 接口中的所有成员变量都默认是由public static final修饰的。
      接口中的所有抽象方法都默认是由public abstract修饰的。

11、内部类 

目前几乎用不到,对于我来说,顾不进行介绍 

四、异常类

1、常见的异常类型

  • 角标越界
  • 空指针
  • 类型转换异常

2、异常的处理方式一

try{

    //有可能出错的代码段
    }catch(错误类型 变量){

        处理的代码段}finally{
                    }

3、异常的处理方式二

throws Exception    //直接扔出去

4、手动抛出异常    throw

5、自定义异常类

五、多线程

1、多线程的创建

方式一:继承Thread类

public class ThreadTest extends Thread {
    /*
1)  定义子类继承Thread类。
2)  子类中重写Thread类中的run方法。
3)  创建Thread子类对象,即创建了线程对象。
4)  调用线程对象start方法:启动线程,调用run方法。
 */

    @Override
    public void run() {
        for(int i=0;i<50;i++){
            System.out.println(Thread.currentThread().getName()+" "+i);
        }
    }
}
class test_thread{
    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        ThreadTest threadTest2 = new ThreadTest();
        ThreadTest threadTest3 = new ThreadTest();
        
        threadTest.start();
        threadTest2.start();
        threadTest3.start();
    }
}

方式二:实现runnable接口


//①实现Runnable接口
class number2 implements Runnable {
    //②实现run()方法
    @Override
    public void run() {
        for (int i = 0; i < 100; i++) {
            if (i % 2 == 0) {
                System.out.println(Thread.currentThread().getName() + i);
            }
        }
    }
}
 
public class Runnable_Test {
    public static void main(String[] args) {
        //③实例化number2的对象
        number2 num = new number2();
        //④把对象作为参数传递给Thread的构造器
        Thread b1 = new Thread(num);
        Thread b2 = new Thread(num);
        Thread b3 = new Thread(num);
        
        b1.setName("线程一:");
        b2.setName("线程二:");
        b3.setName("线程三:");
        //⑤调用start方法
        b1.start();
        b2.start();
        b3.start();
    }
}

方式三和四目前不研究,对于我来说入门即可,后续如果用再做补充

通过实现Callable接口和线程池

2、线程的生命周期

1、线程的状态

新建=》就绪=》运行=》阻塞=》死亡

3、线程的同步

1、多线程会出现安全问题,因为多个线程同时处理一个数据时,当多条语句在操作同一个线程共享数据时,一个线程对多条语句只执行了一部分,还没有执行完,另一个线程参与进来执行。导致共享数据的错误。,最经典的就是银行存取钱的问题。

2、解决办法

4、线程的通信问题

这个东东可以让两个线程交替打印消息

六、常用类

1、String 

public class StringTest {
    public static void main(String[] args) {
        String s1 = "a";
        String s2 = "a";
        String s3 = new String("a");
        String s4 = "b";
        String s5 = "ab";

        System.out.println(s1==s2);
        System.out.println(s1==s3);
        System.out.println(s1+s4==s5);
        System.out.println(s1+"b"==s5);
    }
}

String的具体方法,点击链接

2、StringBuilder和StringBuffer

StringBuffer(JDK1.0):可变字符序列、效率低、线程安全
StringBuilder(JDK 5.0):可变字符序列、效率高、线程不安全

3、时间api

此方面涉及的比较多,而且一般我用的比较少,后续可能会补上

public class DateTest {
    public static void main(String[] args) {
        Date date = new Date();
        //获取当前时间的时间戳  13位的毫秒数
        System.out.println(date.getTime()); 
        //获取当前时间的时间戳13位的毫秒数
        System.out.println(System.currentTimeMillis());
        //Thu Dec 30 14:24:44 CST 2021
        System.out.println(date.toString());  
    }
}

时间戳转为标准时间

public static String stampToDate(long s){
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date date = new Date(s);
        return simpleDateFormat.format(date);
    }

4、java比较器

java比较器是用来比较两个对象的。比如比一下身高体重啥的啦!😎

  1. 自然排序:java.lang.Comparable
  2. 定制排序:java.util.Comparator

1、首先将自然排序,要实现Comparable 的类并且实现compareTo(Object obj) 方法,两个对象即
通过compareTo(Object obj) 方法的返回值来比较大小。如果当前对象this大于形参对象obj,则返回正整数,如果当前对象this小于形参对象obj,则返回负整数,如果当前对象this等于形参对象obj,则返回零。

public class PersonSort {
    public static void main(String[] args) {
        Person [] list1 = new Person[4];
        Person p1 = new Person("gaoruixia", 38);
        Person p2 = new Person("jiayixing", 18);
        Person p3 = new Person("gaogao", 8);
        Person p4 = new Person("jiajia", 48);
        list1[0] = p1;
        list1[1] = p2;
        list1[2] = p3;
        list1[3] = p4;
        Arrays.sort(list1);
        System.out.println(Arrays.toString(list1));
    }
}

class Person implements Comparable<Person>{
    String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

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

    public int compareTo(Person o) {
        if(this.age>o.age){
            return 1;
        }else if(this.age<o.age){
            return -1;
        }
        return 0;
    }
}

2、当第一种方法不方便实现Comparable方法时,采用第二种,Comparator()

Goods[] all = new Goods[4];
all[0] = new Goods("War and Peace", 100);
all[1] = new Goods("Childhood", 80);
all[2] = new Goods("Scarlet and Black", 140);
all[3] = new Goods("Notre Dame de Paris", 120);
Arrays.sort(all, new Comparator() {
@Override
public int compare(Object o1, Object o2) {
Goods g1 = (Goods) o1;
Goods g2 = (Goods) o2;
return g1.getName().compareTo(g2.getName());
}
});
System.out.println(Arrays.toString(all));

5、Math类

 七、枚举类

1、枚举类的对象个数是确定的,如星期,季节等,目前用的少,后续研究

public enum SeasonEnum {
    SPRING("春天","春风又绿江南岸"),
    SUMMER("夏天","映日荷花别样红"),
    AUTUMN("秋天","秋水共长天一色"),
    WINTER("冬天","窗含西岭千秋雪");
    private final String seasonName;
    private final String seasonDesc;
    private SeasonEnum(String seasonName, String seasonDesc) {
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }
    public String getSeasonName() {
        return seasonName;
    }
    public String getSeasonDesc() {
        return seasonDesc;
    }
}

八、注解

1、注解(Annotation)不是注释,用@使用

 注解一般在框架中大量使用,配合反射,后边用到进行补充。。。。。。。。

九、集合

这是面试的重中之重重重重。。。。。。。

首先介绍一下集合家族成员

 如果你看过源码就会发现Collection实现了Iterable<E>,然后就会获得iterator() 方法,这就是迭代器,迭代器也是一种设计模式,用来遍历集合

public class Itraeasd {
    public static void main(String[] args) {
        ArrayList<Integer> l = new ArrayList<Integer>();
        l.add(5);
        l.add(53);
        l.add(55);
        l.add(52);
        l.add(56);
        Iterator<Integer> iterator = l.iterator();
        while (iterator.hasNext()){     //判断是否存在下一个数据
            Integer next = iterator.next();  //返回并指针下移
            if(next.equals(5)){
                iterator.remove();    //删除元素
            }
        }
        System.out.println(l);
    }
}

这里还要提到之前的foreach,不仅可以用来遍历数组,对于集合同样也是适用的,他的底层也是使用迭代器

1、List家族

List主要有三个成员,他们是Arraylist,Linklist,Vector

List里面的数据是有序且可重复的

Arraylist

arraylist底层是一个“变长”的数组,初始长度不指定的话默认是10,在jdk8.0以前,采用的饿汉式创建,在之后采用的是懒汉式。

这里提到一个方法

Arrays.asList()    这里的返回值是一个长度不可变的List

linklist底层采用双向链表实现的,定义了一个头部一个尾部,用来记录前后的地址值,好处就是便于频繁的插入或者删除

Vector

这是一个古老的集合,线程安全,但是代价就是慢慢慢慢慢的,不介意使用

2、Set

Set 集合不允许包含相同的元素,如果试把两个相同的元素加入同一个Set 集合中,则添加操作失败。Set 判断两个对象是否相同不是使用== 运算符,而是根据equals() 方法。

HashSet

1、特点:不能保证排列顺序  线程不安全   可以是null

2、如何判断两个元素是否相等,首先判断hashcode(),然后判断equals(),都相等才是相等

3、对于放在set数组中的对象,一定要重写这两个方法,以实现对象相等原则,即相等的对象必须有相等的散列码。

 如果不知道hash算法,理解起来有一丢丢困难,这里推荐一本不错的书

https://item.jd.com/13293434.htmlhttps://item.jd.com/13293434.html4、hashset的底层是数组,初始容量是16,当使用频率超过0.75,自动扩容两倍。

LinkHashSet

 这是在HashSet的基础上增加了双向列表,可以在存入数据的时候,看似有序,插入性能略低于HashSet,但是在迭代时访问有很好的性能。

TreeSet

底层采用了红黑树,保证了集合元素始终处于排序状态。红黑树在后面的HashMap会再次和大家相遇。

3、Map

下面来到了大名鼎鼎的map家族,他的存储方式很特别,使用的是键值对,键的底层存储使用的是set集合来保证唯一性,这就类似于函数,一个键能找到唯一一个与之对应的值。再来回顾一下继承结构,使用最最最最频繁的就是HashMap

 

HashMap

1、允许键和值使用NULL值,不保证映射顺序,所有的Key都是使用Set集合来存放,所在类要重写equals()方法和hashCode()方法;所有的Value都是Collection,所在类要重写equals()方法。

2、一个Key-Value构成一个entry,所有的entry构成的集合是Set无序的,不可重复的。

3、JDK 7及以前版本:HashMap是数组+链表结构(即为链地址法)
      JDK 8版本发布以后:HashMap是数组+链表+红黑树实现,当链表长度大于8时,会自动转换为红黑树,因为红黑树的效率比较高。 

 4、hashmap添加元素的过程,看起来比较繁琐,打个比喻就是根据你的hash值去寻找你的坑位,如果坑位没有人,那就把你放进去,如果有,这个时候就得调用equals方法来判断是否相同,如果不同,通过链表把你放进去,如果相同,用你的value去替换他的value。

5、hashmap扩容,当存入的数据越来越多,哈希碰撞的几率就会越来越大,效率就会下降,所以需要进行扩容,扩大为原来的一倍空间, 当数据达到容量的0.75时进行扩容,扩容之后,所有数据的hash值都要重新计算,放入新的位置,这是一个很浪费资源的过程,所以我们如果提前预知要放入数据的多少,提前选择创建的大小,尽可能的避免扩容。

6、当HashMap中的其中一个链的对象个数如果达到了8个,此时如果capacity没有达到64,那么HashMap会先扩容解决,如果已经达到了64,那么这个链会变成树,结点类型由Node变成TreeNode类型。当然,如果当映射关系被移除后,下次resize方法时判断树的结点个数低于6个,也会把树再转为链表。

LinkedHashMap

  • LinkedHashMap 是HashMap 的子类
  • 在HashMap存储结构的基础上,使用了一对双向链表来记录添加元素的顺序
  • 与LinkedHashSet类似,LinkedHashMap 可以维护Map 的迭代顺序:迭代顺序与Key-Value 对的插入顺序一致

TreeMap

Hashtable

一个古老的键值对集合,线程安全,不能存放NULL。 

学了这么多先来一个小结

ArrayListLinkListVector
HashSetLinkHashSetTreeset
HashMapLinkedHashMapTreeMap

首先,在2020-01-01恭喜大家元旦快乐


十、泛型

在以前,一个List的集合,里面可以放各种各样的数据类型,这样不便于管理,于是给List贴上一个标签,规定了里面可以放些什么东西。<泛型类型>

1、在集合中使用泛型

ArrayList<Integer> list = new ArrayList<>();//类型推断
list.add(78);
list.add(88);
list.add(77);
list.add(66);

for(Integer i : list){
不需要强转
System.out.println(i);
}

 2、自定义泛型结构

泛型类

public class Testt9<E> {
    public E ttt(E aa){
        System.out.println(aa);
        return aa;
    }
}

class Test77{
    public static void main(String[] args) {
        Testt9<String> stringTestt9 = new Testt9<String>();
        stringTestt9.ttt("dddd");
    }
}

泛型方法

public class Test5 {
    public static void main(String[] args) {
        tt(43);
    }
    public static <E> E tt(E a){
        System.out.println(a);
        return a;
    }
}

 

十一、IO流

1、File类的使用

1、先来认识一下file类的构造器,第一个是最常用的。

 常用方法一大堆,粘贴过来的,想看就看看


 File类的获取功能 public String getAbsolutePath():获取绝对路径
 public String getPath() :获取路径
 public String getName() :获取名称
 public String getParent():获取上层文件目录路径。若无,返回null
 public long length() :获取文件长度(即:字节数)。不能获取目录的长度。
 public long lastModified() :获取最后一次的修改时间,毫秒值
 public String[] list() :获取指定目录下的所有文件或者文件目录的名称数组
 public File[] listFiles() :获取指定目录下的所有文件或者文件目录的File数组
 File类的重命名功能 public boolean renameTo(File dest):把文件重命名为指定的文件路径 
 public boolean isDirectory():判断是否是文件目录
 public boolean isFile() :判断是否是文件
 public boolean exists() :判断是否存在
 public boolean canRead() :判断是否可读
 public boolean canWrite() :判断是否可写
 public boolean isHidden() :判断是否隐藏
 File类的创建功能 public boolean createNewFile() :创建文件。若存在,则不创建,返回false
 public boolean mkdir() :创建文件目录。如果存在,就不创建。如果此文件目录的上层目录不存在,也不创建。
 public boolean mkdirs() :创建文件目录。如果上层文件目录不存在,一并创建
注意事项:如果你创建文件或者文件目录没有写盘符路径,那么,默认在项目
路径下。
 File类的删除功能 public boolean delete():删除文件或者文件夹
删除注意事项:
Java中的删除不走回收站。要删除一个文件目录,请注意该文件目录内不能包含文件或者文件目录


2、IO流原理及流的分类

前面引入File,现在正式的进入了IO流,I:input,O:output,流:Stream

 3、节点流

还有fileinputstream和fileoutputstream,使用这个可以给图片加密

public class FIPSt {
    public static void main(String[] args) throws IOException {
        File file = new File("E:\\pic.jpg");
        FileInputStream fis = new FileInputStream(file);
        FileOutputStream fos = new FileOutputStream(new File("E:\\picss.jpg"));
        byte[] bytes = new byte[102400];
        fis.read(bytes);
        System.out.println(bytes[0]);
        bytes[0]=4;
        fos.write(bytes);
        
        fis.close();
        fos.close();
    }
}

4、缓冲流

为了提高数据读写的速度,Java API提供了带缓冲功能的流类,在使用这些流类时,会创建一个内部缓冲区数组,缺省使用8192个字节(8Kb)的缓冲区。 

使用缓冲流是要在节点流上套壳

flush()可以强制将缓冲区的内容全部写入输出流

下面的代码自行体会

BufferedReader br = null;
    BufferedWriter bw = null;
try {
// 创建缓冲流对象:它是处理流,是对节点流的包装
        br = new BufferedReader(new FileReader("d:\\IOTest\\source.txt"));
        bw = new BufferedWriter(new FileWriter("d:\\IOTest\\dest.txt"));
        String str;
        while ((str = br.readLine()) != null) { // 一次读取字符文本文件的一行字符
            bw.write(str); // 一次写入一行字符串
            bw.newLine(); // 写入行分隔符
        }
        bw.flush(); // 刷新缓冲区
    } catch (IOException e) {
        e.printStackTrace();
    } finally {
// 关闭IO流对象
        try {
            if (bw != null) {
                bw.close(); // 关闭过滤流时,会自动关闭它所包装的底层节点流
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        try {
            if (br != null) {
                br.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

 5、转换流

当字节流转为字符流时,就得考虑编码方式

6、标准输入输出流,打印流、数据流

略 

7、对象流

ObjectInputStream和OjbectOutputSteam

对应的就是反序列化和序列化,序列化是☞把一个对象实例转化为字节流进行网络传输。

对象所在类要实现Serializable接口才可以进行序列化。

序列化 

ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(“data.txt"));
Person p = new Person("韩梅梅", 18, "中华大街", new Pet());
oos.writeObject(p);
oos.flush();
oos.close();

 反序列化

ObjectInputStream ois = new ObjectInputStream(new FileInputStream(“data.txt"));
Person p1 = (Person)ois.readObject();
System.out.println(p1.toString());
ois.close();

8、随机存储文件流

 

 9、Java NIO

到此IO告一段落了。

十二、网络编程

1、回顾计算机网络

1、这张图可以说是计算机网络祖师爷级别的存在


 

 2、Socket套接字

网络上具有唯一标识的IP地址和端口号组合在一起才能构成唯一能识别的标识符套接字。

 2、TCP网络编程

客户端

服务端

 

 

 tcp的先到这里告一段落

3、UDP编程

 

 十三、反射,java8、9、10、11新特性

暂时不更,几乎用不到


 完结于2022-01-01 21:22:00

全文共计15550


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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值