SXT 面向对象

4.1 面向过程和面向对象
面向过程和面向对象都是对软件分析、设计和开发的一种思想,它指导着人们以不同的方式去分析、设计和开发软件。
面向过程思想思考问题时,我们首先思考-怎么按照步骤实现?,并将步骤对应成方法,一步一步,最终完成。这个适合简单任务,不需要过多协作的情况下。比如:如何开车?
面向过程适合简单、不需要协作的事务,但是当我们思考比较复杂的问题,比如"如何造车?",就会发现列出1234这样的步骤,是不可能的。那是因为,造车太复杂,需要很多协作才能完成,此时面向对象思想就应运而生了。
面向对象和面向过程的总结:
(1)都是解决问题的思维方式,都是代码组织的方式
(2)解决简单问题可以使用面向过程
(3)解决复杂问题:宏观上使用面向对象把握,微观处理上仍然是面向过程
4.3 对象和类的概念
可以看做是一个模板,或者图纸,系统根据类的定义来造出对象。
类:我们叫做class,对象:我们叫做Object、instance。我们以后说某个类的对象,某个类的实例,是一样的意思。
总结:
(1)对象是具体的事物,类是对对象的抽象;
(2)类可以看出一类对象的模板,对象可以看成该类的一个具体实例;
(3)类是用于描述同一类型的对象的一个抽象概念,类中定义了这一类对象所应具有的共同的属性、方法;
第一个包含属性和方法的类的定义:

public class SxtStu {

    //属性field s
    int id;
    String name;
    int age;

    //方法
    void study(){
        System.out.println("我在认真学习!!");
    }
    void play(){
        System.out.println("我再玩一会嘛!!");
    }

}

然后在类的基础上创建对象并调用方法:

public class SxtStu {

    //属性field s
    int id;
    String name;
    int age;

    //方法
    void study(){
        System.out.println("我在认真学习!!");
    }
    void play(){
        System.out.println("我再玩一会嘛!!");
    }

    //程序执行的入口,必须要有
    public static void main(String[] args) {

        SxtStu stu = new SxtStu();
        stu.play();

    }
}

深化一下:

public class SxtStu {

    //属性field s
    int id;
    String sname;
    int age;

    Computer comp; //计算机

    //方法
    void study(){
        System.out.println("我在认真学习!!并且用着:"+comp.brand);
    }
    void play(){
        System.out.println("我再玩一会嘛!!");
    }

    //构造方法,用于创建这个类的对象,无参的构造方法可以由系统自动创建,必须与类名完全一致
    SxtStu(){
    }

    //程序执行的入口,必须要有
    public static void main(String[] args) {

        SxtStu stu = new SxtStu();  //创建一个对象
        stu.id = 1001;
        stu.sname = "哈利路亚";
        stu.age = 18;

        Computer c1 = new Computer();
        c1.brand = "联想";

        stu.comp = c1;

        stu.play();
        stu.study();

    }

}

class Computer{

    String brand;

}

4.4 面向对象的内存分析:
Java虚拟机的内存可以分为三个区域:栈stack、堆heap、方法区method area
的特点如下:
1 栈描述的是方法执行的内存模型,每个方法被调用都会创建一个栈帧(存储局部变量、操作数、方法出口等)
2 JVM为每个线程创建一个栈,用于存放该线程执行方法的信息(实际参数、局部变量等)
3 栈属于线程私有,不能实现线程间的共享!
4 栈的存储特性是:先进后出,后进先出
5 栈是由系统自动分配,速度快!栈是一个连续的内存空间!
的特点如下:
1 堆用于存储创建好的对象和数组(数组也是对象)
2 JVM只有一个堆,被所有线程共享
3 堆是一个不连续的内存空间,分配灵活,速度慢!
==方法区(又叫静态区)==特点如下:
1 JVM只有一个方法区,被所有线程共享!
2 方法区实际也是堆,只是用于存储类、常量相关的信息!
3 用来存放程序中永远不变或唯一的内容。(类信息【Class对象】、静态变量、字符串常量等)
在这里插入图片描述
4.5 构造方法
构造器也叫构造方法(constructor),用于对象的初始化。
要点:
1 通过new关键字调用!
2 构造器虽然有返回值,但是不能定义返回值类型(返回值的类型肯定是本类),不能在构造器里使用return返回某个值
3 如果我们没有定义构造器,则编译器会自动定义一个无参的构造函数,如果已定义则编译器不会自动添加!
4 构造器的构造方法名必须和类名一致!
代码:

class Point{
    double x,y;

    //构造方法名称和类名称必须保持一致
    public Point(double _x,double _y){

        x = _x;
        y = _y;

    }

    public double getDistance(Point p)
    {

        return Math.sqrt((x-p.x)*(x-p.x)+(y-p.y)*(y-p.y));

    }
}

public class TestConstructor {

    public static void main(String[] args) {

        Point p = new Point(3.0,4.0);
        Point origin = new Point(0.0,0.0);

        System.out.println(p.getDistance(origin));

    }
}

4.6 构造方法的重载
构造方法也是方法,只不过有特殊的作用而已,与普通方法一样,构造方法也可以重载。
构造方法重载(创建不同用户对象)

public class User {

    int id; //id
    String name; //账户名
    String pwd; //密码

    public User() {
    }

    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    public static void main(String[] args) {
        User u1 = new User();
        User u2 = new User(100,"八五七");
        User u3 = new User(101,"哈拉少","520555");
    }
}

4.7 垃圾回收机制(Garbage Collection)
Java引入了垃圾回收机制,令C++程序员头疼的内存管理问题迎刃而解,Java程序员可以将更多的精力放到业务逻辑上而不是内存管理工作上,大大提高了开发的效率。
垃圾回收算法一般要做两件基本事情:
1 发现无用的对象
2 回收无用对象占用的内存空间
垃圾回收相关算法:
1 引用计数法
堆中每个对象都有一个引用计数,被引用一次,计数加1,被引用变量值变为null,则计数减1,直到计数为0,则表示变成无用对象,优点是算法简单,缺点是"循环引用的无用对象"无法被识别。
2 引用可达法(根搜索算法)
程序把所有的引用关系看作一张图,从一个节点GC ROOT开始,寻找对应的引用节点,找到这个节点以后,继续寻找这个节点的引用节点,当所有的引用节点寻找完毕之后,剩余的节点则被认为是没有被引用到的节点,即无用的节点。
通用的分代垃圾回收机制:
不同生命周期的对象可以采取不同的回收算法,以便提高回收效率。我们将对象分为三种状态:年轻代、年老代、持久代。JVM将堆内存划分为 Eden、Survivor 和 Tenured/Old 空间。
1 年轻代
所有新生成的对象首先都是放在Eden区。 年轻代的目标就是尽可能快速的收集掉那些生命周期短的对象,对应的是Minor GC,每次 Minor GC 会清理年轻代的内存,算法采用效率较高的复制算法,频繁的操作,但是会浪费内存空间。当“年轻代”区域存放满对象后,就将对象存放到年老代区域。
2 年老代
在年轻代中经历了N(默认15)次垃圾回收后仍然存活的对象,就会被放到年老代中。因此,可以认为年老代中存放的都是一些生命周期较长的对象。年老代对象越来越多,我们就需要启动Major GC和Full GC(全量回收),来一次大扫除,全面清理年轻代区域和年老代区域。
3 持久代
用于存放静态文件,如Java类、方法等。持久代对垃圾回收没有显著影响。
在这里插入图片描述
Minor GC:
用于清理年轻代区域。Eden区满了就会触发一次Minor GC。清理无用对象,将有用对象复制到“Survivor1”、“Survivor2”区中(这两个区,大小空间也相同,同一时刻Survivor1和Survivor2只有一个在用,一个为空)
Major GC:
用于清理老年代区域。
Full GC:
用于清理年轻代、年老代区域。 成本较高,会对系统性能产生影响
垃圾回收过程:
1 新创建的对象,绝大多数都会存储在Eden中
2 当Eden满了(达到一定比例)不能创建新对象,则触发垃圾回收(GC),将无用对象清理掉,然后剩余对象复制到某个Survivor中,如S1,同时清空Eden区
3 当Eden区再次满了,会将S1中的不能清空的对象存到另外一个Survivor中,如S2,同时将Eden区中的不能清空的对象,也复制到S1中,保证Eden和S1,均被清空
4 重复多次(默认15次)Survivor中没有被清理的对象,则会复制到老年代Old(Tenured)区中,
5 当Old区满了,则会触发一个一次完整地垃圾回收(FullGC),之前新生代的垃圾回收称为(minorGC)
创建大量无用对象:
比如我们在需要大量拼接字符串时,使用了String而不是StringBuilder。

String str = "";
for(int i = 0; i < 10000 ; i++;)
{
	str + = i;  //相当产生了10000个String对象
}

4.8 this关键字
创建一个对象分为如下四步:
1 分配对象空间,并将对象成员变量初始化为0或空
2 执行属性值的显式初始化
3 执行构造方法
4 返回对象的地址给相关的变量
this的本质就是创建好的对象的地址,由于在构造方法调用前,对象已经创建,因此,在构造方法中也可以使用this代表-当前对象。
this最常用的用法:
1 在程序中产生二义性之处,应使用this来指明当前对象;普通方法中,this总是指向调用该方法的对象,构造方法中,this总是指向正要初始化的对象。
2 使用this关键字调用重载的构造方法,避免相同的初始化代码,但只能在构造方法中用,并且必须位于构造方法的第一句。
3 this不能用于static方法中。

public class TestThis {
    
    int a,b,c;

    public TestThis(int a, int b) {
        this.a = a;
        this.b = b;
    }

    public TestThis(int a, int b, int c) {
        this(a,b);
        this.c = c;
    }
    
    void sing(){
        
    }
    
    void eat(){
        this.sing(); //调用本类中的sing()
        System.out.println("你妈妈喊你回家吃饭!");
    }

    public static void main(String[] args) {
        TestThis hi = new TestThis(2,3);
        hi.eat();
    }
}

4.9 static关键字
在类中,用static声明的成员变量为静态成员变量,也称为类变量,类变量的生命周期和类相同,在整个应用程序执行期间都有效。
static修饰的成员变量和方法,从属于类,普通变量和方法从属于对象的。
在这里插入图片描述

public class User2 {

    int id; //id
    String name; //账户
    String pwd; //密码

    static String company = "北京尚学堂"; //公司名称

    public User2(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public void login(){
        System.out.println("登录:"+name);
    }

    public static void printCompany(){
        //login();//调用非静态成员,编译就会报错
        System.out.println(company);
    }

    public static void main(String[] args) {
        User2 u = new User2(101,"哈拉少");
        User2.printCompany();
        User2.company = "北京阿里爷爷";
        User2.printCompany();
    }
}

4.10 静态初始化块
构造方法用于对象的初始化;静态初始化块,用于类的初始化操作;在静态初始化块中不能直接访问非static成员。

public class User3 {

    int id; //id
    String name; //账户名
    String pwd; //密码
    static String company; //公司名称

    static {

        System.out.println("执行类的初始化工作");
        company = "北京尚学堂";
        printcompany();

    }

    public static void printcompany(){
        System.out.println(company);
    }

    public static void main(String[] args) {
        User3 u3 = null;
    }
}

4.11 参数传值机制
Java中,方法中所有参数都是"值传递",也就是"传递的是值的副本",也就是说,我们得到的是"原参数的复印件,而不是原件",因此,复印件改变不会影响原件。

Java中常用的包说明
java.lang包含一些Java语言的核心类,如String、Math、Integer、System和Thread,提供常用功能
java.awt包含了构成抽象窗口工具集(abstract window toolkits)的多个类,这些类被用来构建和管理应用程序的图形用户界面(GUI)
java.net包含执行与网络相关的操作的类
java.io包含能提供多种输入/输出功能的类
java.util包含一些实用工具类,如定义系统特性、使用与日期日历相关的函数

5 面向对象进阶
5.1 继承的实现
我们来对比一下下面的的两个代码:

/**
 * 测试继承
 */
public class TestExtends {

}

class Person{
    String name;
    int height;

    public void test(){
        System.out.println("休息一会儿!");
    }
}

class Student{
    String name;
    int height;
    String major;

    public void study(){
        System.out.println("学习两小时!");
    }

    public void rest(){
        System.out.println("休息一会儿!");
    }
}
public class TestExtends {

    public static void main(String[] args) {
        Student stu = new Student();
        stu.name = "哈拉少";
        stu.height = 172;
        stu.test();
        
        Student stu2 = new Student("西西",6,"挖掘机");
    }

}

class Person{

    String name;
    int height;

    public void test(){

        System.out.println("休息一会儿!");

    }

}

class Student extends Person{

    String major;

    public void study(){
        System.out.println("学习两小时!");
    }

    public Student(String name,int height,String major) {
        this.name = name;
        this.height = height;
        this.major = major;
    }

    public Student() {
    }
}

继承使用要点:
1 父类也称作超类、基类、派生类等。
2 Java中只有单继承,没有像C++那样的多继承,多继承会引起混乱,使得继承过于复杂,系统难以维护;
3 Java中类没有多继承,接口有多继承;
4 子类继承父类,可以得到父类的全部属性和方法(除了父类的构造方法),但不见得可以直接访问(比如,父类私有的属性和方法);
5 如果定义一个类时,没有调用extends,则它的父类是:java.lang.Object

instanceof是二元运算符,左边是对象,右边是类;当对象是右面类或子类所创建对象时,返回true;否则,返回false

方法的重写override:
子类通过重写父类的方法,可以用自身的行为替换父类的行为,方法的重写是实现多态的必要条件;

方法重写要点:
1 “==”:方法名、形参列表相同
2 “<=”:返回值类型和声明异常类型,子类小于等于父类
3 “>=”:访问权限,子类大于等于父类

public class TestOverride {

    public static void main(String[] args) {
        Horse h = new Horse();
        h.run();
    }

}

class Vehicle{
    public void run(){
        System.out.println("跑....");
    }
    public void stop(){
        System.out.println("停止!");
    }
    
    public Person WhoIsPsg(){
        return new Person();
    }
    
}

class Horse extends Vehicle{
    public void run(){
        System.out.println("四蹄翻飞。嘚嘚的....");
    }
    
    public Student WhoIsPsg(){  //返回值类型小于等于父类的类型
        return new Student();
    }
    
//    public Object WhoIsPsg(){  //返回值类型大了
//        
//    }
}

5.2 Object类
Object类是所有Java类的根基类,也就是意味着所有Java对象都拥有Object类的属性和方法。
在这里插入图片描述
重写toString方法:

public class TestObject {

    public static void main(String[] args) {

        TestObject to = new TestObject();
        System.out.println(to.toString());

        Person2 p2 = new Person2("哈拉少",6);
        System.out.println(p2.toString());

    }

    public String toString(){

        return "测试Object对象";

    }

}

class Person2{

    String name;
    int age;

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

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

==和equals方法:

public class TestEquals {

    public static void main(String[] args) {

        User u1 = new User(1000,"哈拉少","123456");
        User u2 = new User(1000,"老八","520111");

        System.out.println(u1 == u2);     //false,不是同一个对象
        System.out.println(u1.equals(u2));  //true,id相等

        String str1 = new String("sxt");
        String str2 = new String("sxt");

        System.out.println(str1 == str2);     //fasle,不是同一个对象
        System.out.println(str1.equals(str2)); //true,相等

    }

}

class User{

    int id;
    String name;
    String pwd;

    public User(int id, String name, String pwd) {
        this.id = id;
        this.name = name;
        this.pwd = pwd;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        User user = (User) o;
        return id == user.id;
    }

    @Override
    public int hashCode() {
        return Objects.hash(id);
    }
}

5.3 super关键字
super是直接父类对象的引用,可以通过super来访问父类中被子类覆盖的方法或属性。

public class TestSuper01 {

    public static void main(String[] args) {
        new ChildClass().f();
    }

}

class FatherClass{

    public int value;

    public void f(){
        value = 100;
        System.out.println("FatherClass.value="+value);
    }

}

class ChildClass extends FatherClass{

    public int value;

    public void f(){
        super.f();  //调用父类对象的普通方法
        value = 200;
        System.out.println("ChildClass.value="+value);
        System.out.println(value);
        System.out.println(super.value); //调用父类对象的成员变量
    }

}

输出结果为:

FatherClass.value=100
ChildClass.value=200
200
100

5.3.1 继承树追溯
构造方法第一句总是:super(…)来调用父类对应的构造方法。所以,流程就是:先向上追溯到Object,然后再依次向下执行类的初始化块和构造方法,直到当前子类为止;
注:静态初始化块调用顺序,与构造方法调用顺序一样,不再重复;

public class TestSuper02 {

    public static void main(String[] args) {
        new ChildClass2();
    }

}

class FatherClass2{

    public FatherClass2(){
        System.out.println("创建FatherClass");
    }

}

class ChildClass2 extends FatherClass2{

    public ChildClass2(){
        //super();  无论写不写都会默认调用父类构造器
        System.out.println("创建ChildClass");
    }

}

输出结果为:
创建FatherClass
创建ChildClass

5.4.1 封装的作用与含义
高内聚就是类的内部数据操作细节自己完成,不允许外部干涉;低耦合是仅暴露少量的方法给外部使用,尽量方便外部调用。
访问控制符:

修饰符同一个类同一个包中子类所有类
private*
default**
protected***
public****

(1)private 表示私有,只有自己类能访问

(2)default表示没有修饰符修饰,只有同一个包的类能访问

(3)protected表示可以被同一个包的类以及其他包中的子类访问

(4)public表示可以被该项目的所有包中的所有类访问

在这里插入图片描述
5.4.3 封装的使用细节
类的属性的处理:
(1)一般使用private访问权限。
(2)提供相应的get/set方法来访问相关属性,这些方法通常是public修饰的,以提供对属性的赋值与读取操作(注意:boolean变量的get方法是is开头!)。
(3)一些只用于本类的辅助性方法可以用private修饰,希望其他类调用的方法用public修饰。
如何用get/set方法来访问private修饰的属性:
在这里插入图片描述
5.5 多态
多态指的是同一个方法调用,由于对象不同可能会有不同的行为,现实生活中,同一个方法,具体实现会完全不同。
多态的要点:
(1)多态是方法的多态,不是属性的多态(多态与属性无关)
(2)多态的存在要有3个必要条件:继承,方法重写,父类引用指向子类对象
(3)父类引用指向子类对象后,用该父类引用调用子类重写的方法,此时多态就出现了
在这里插入图片描述
5.6 对象的转型
父类引用指向子类对象,我们称这个过程为向上转型,属于自动类型转换
向上转型后的父类引用变量只能调用它编译类型的方法,不能调用它运行时类型的方法。这时,我们就需要进行类型的强制转换,我们称之为向下转型!

5.7 final关键字
final关键字的作用:
(1)修饰变量:被他修饰的变量不可改变,一旦赋了初值,就不能被重新赋值

final int Max SPEED = 120;

(2)修饰方法:该方法不可被子类重写,但是可以被重载

final void study(){}

(3)修饰类:修饰的类不嫩被继承,比如Math、String等

final class A{}

在这里插入图片描述
在这里插入图片描述
5.8 抽象方法和抽象类
抽象方法:
使有abstract修饰的方法,没有方法体,只有声明,定义的是一种规范,就是告诉子类必须要给抽象方法提供具体的实现。
抽象类:
包含抽象方法的类就是抽象类,通过abstract方法定义规范,然后要求子类必须定义具体实现,通过抽象类,我们就可以做到严格限制子类的设计,使子类之间更加通用。
抽象类的使用要点:
(1)有抽象方法的类只能定义成抽象类
(2)抽象类不能实例化,即不能用new来实例化抽象类
(3)抽象类可以包含属性、方法、构造方法,但是构造方法不能用了new实例,只能用来被子类调用
(4)抽象类只能用来继承
(5)抽象方法必须被子类实现

public abstract class Animal {

    //第一:没有实现 第二:子类必须实现
    abstract public void shout();

    public void run(){
        System.out.println("跑啊跑!");
    }

}

class Dog extends Animal{

    @Override
    public void shout() {
        System.out.println("汪汪汪!");
    }
}

5.9.1 接口的作用
接口就是比"抽象类"还"抽象"的"抽象类",可以更加规范的对子类进行约束,全面地专业的实现了:规范和具体实现的分离
详细说明:
(1)访问修饰符:只能是public或默认
(2)接口名:和类名采用相同的命名机制
(3)extends:接口可以多继承
(4)常量:接口中的属性只能是常量,总是:public static final修饰,不写也是
(5)方法:接口中的方法只能是:public abstract,省略的话,也是public abstract
要点:
(1)子类通过implements来实现接口中的规范。
(2)接口不能创建实例,但是可用于声明引用变量类型。
(3) 一个类实现了接口,必须实现接口中所有的方法,并且这些方法只能是public的。
(4)JDK1.7之前,接口中只能包含静态常量、抽象方法,不能有普通属性、构造方法、普通方法。
(5)JDK1.8后,接口中包含普通的静态方法

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

        Volant v = new Angel();
        v.fly();

        Honest h = new GoodMan();
        h.helpOther();

    }
}

/**
 * 飞行接口
 */
interface Volant{
    int FLY_HEIGHT = 1000;
    void fly();
}

//善良接口
interface Honest{
    void helpOther();
}


class Angel implements Volant,Honest{  //实现类可以实现多个父接口
    @Override
    public void fly() {
        System.out.println("天使飞了起来");
    }

    @Override
    public void helpOther() {
        System.out.println("天使帮助弱者");
    }
}

class GoodMan implements Honest{
    @Override
    public void helpOther() {
        System.out.println("好男人帮助弱者");
    }
}

class BirdMan implements Volant{
    @Override
    public void fly() {
        System.out.println("鸟人飞飞飞");
    }
}
public class TestInterface2 {



}

interface A{
    void testa();
}

interface  B{
    void testb();
}

/**接口可以多继承:接口C继承接口A和B*/
interface C extends A,B{
    void testc();
}

class Mysubclass implements C{
    
    @Override
    public void testa() {

    }

    @Override
    public void testb() {

    }

    @Override
    public void testc() {

    }
}

java里面有多继承吗?
1 java的类没有多继承,只有单继承
2 java的接口有多继承

5.10 内部类
一般情况,我们把类定义成独立的单元。有些情况下,我们把一个类放在另一个类的内部定义,称为内部类。
非静态内部类:
(1)非静态内部类必须寄存在一个外部类对象里。因此,如果有一个非静态内部类对象那么一定存在对应的外部类对象。非静态内部类对象单独属于外部类的某个对象。
(2)非静态内部类可以直接访问外部类的成员,但是外部类不能直接访问非静态内部类成员。
(3) 非静态内部类不能有静态方法、静态属性和静态初始化块。
(4)外部类的静态方法、静态代码块不能访问非静态内部类,包括不能使用非静态内部类定义变量、创建实例。
成员变量访问要点:
(1)内部类里方法的局部变量:变量名。
(2)内部类属性:this.变量名。
(3)外部类属性:外部类名.this.变量名

public class TestInnerClass {
    public static void main(String[] args) {
        //创建内部类对象
        Outer.Inner inner = new Outer().new Inner();
        inner.show();
    }
}

class Outer{
    private int age = 10;
    public void testOuter(){}
    class Inner{
        int age = 20;
        public void show(){
            int age = 30;
            System.out.println("外部类的成员变量age:"+ Outer.this.age);
            System.out.println("内部类的成员变量age:"+this.age);
            System.out.println("局部变量age:"+age);
        }
    }
}

静态内部类:
(1)当一个静态内部类对象存在,并不一定存在对应的外部类对象。 因此,静态内部类的实例方法不能直接访问外部类的实例方法。
(2)静态内部类看做外部类的一个静态成员。 因此,外部类的方法中可以通过:“静态内部类.名字”的方式访问静态内部类的静态成员,通过 new 静态内部类()访问静态内部类的实例。

public class TestStaticInnerClass {
    public static void main(String[] args) {
        Outer2.Inner2 inner = new Outer2.Inner2();        
    }
}

class Outer2{
    static class Inner2{
    }
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值