java第四弹 多态 final static 代码块 抽象类 匿名类 接口 Java8新特性:接口增强

1.多态

  1. 多态的理解
    (1)同一个动作作用于不同的对象产生的不同的行为,比如不同子类对父类的不同的重写。
    (2)多态就是一个对象的多种形态。
  2. 多态的体现
    (1)基于继承的实现,不同子类重写了父类方法之后体现不同的形式。
    (2)接口的实现。
  3. 形成多态的条件
    (1)继承:子类去继承父类。
    (2)重写:子类重写父类的方法。
    (3)重载:同一个方法名,形参列表不同,实现的功能也不同。
    (4)子类对象的多态性:父类的引用指向子类的实例。
  4. 程序分为两种状态,一种是编译时状态,一种是运行时状态。
    举例:Pet p1 = new Dog(“泰迪”, “小泰”);
    对于多态来说,编译时看左边,会把p1看作是宠物类对象,运行时看右边,堆中实际存放的类型是Dog类型。
  5. 向上转型和向下转型
    (1)向上转型(小转大):将子类赋值给父类的引用,可以自动类型转换,例如Pet p1 = new Dog(“泰迪”, “小泰”);
    (2)向下转型(大转小):将父类转换为子类,需要强制类型转换,例如Dog dog1 = (Dog) p1;
  6. 多态的类型
    (1)编译时(看左边)多态:方法重载(在编译期间,调用相同的方法名,根据不同的参数列表来确定调用的是哪个方法)。
    (2)运行时(看右边)多态:方法的重写(只有在运行期间才确定使用的对象类型,才能确定变量的引用指向哪哪种对象的实例)。
  7. 补充instanceof运算符
    该运算符用来判断一个对象是否属于一个类或者实现了一个接口,返回true挥着false。在强制类型转换之前,通过此运算符检查对象的真实类型,可以避免类型转换异常,从而提高代码健壮性。

这么说太抽象,用代码来说明一下👇

Pet父类

public class Pet {

    private String name;
    protected int health = 100;//健康值

    public Pet() {
    }

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

    public Pet(int health) {
        this.health = health;
    }

    public Pet(String name, int health) {
        this.name = name;
        this.health = health;
    }

    public String getName() {
        return name;
    }

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

    public int getHealth() {
        return health;
    }

    public void setHealth(int health) {
        this.health = health;
    }

    //宠物吃食
    public void eat() {
        System.out.println("宠物吃食");
    }

    //描述宠物信息
    public void info() {
        System.out.println("我的昵称是" + this.name + ",我的健康值是" + this.health);
    }
}

Dog子类

public class Dog extends Pet {
    //狗勾的有的属性
    public String stain;//品种
    
    //无参构造方法
    public Dog() {
    }

    //两个参数的构造方法,其中name继承自父类
    public Dog(String stain, String name) {
        super(name);
        this.stain = stain;
    }

    public String getStain() {
        return stain;
    }

    public void setStain(String stain) {
        this.stain = stain;
    }

    //重写宠物吃食的方法
    public void eat() {
        super.health = super.health + 3;
        System.out.println("狗勾吃饱了,健康值加3");
    }

    //重写宠物info的方法
    public void info() {
        super.info();
        System.out.println("我的品种是" + this.stain);
    }
    
    //Dog类独有的方法
    public void sleep() {
        System.out.println("狗勾在呼呼呼的大睡");
    }

}

Penguin子类

public class Penguin extends Pet {
    //企鹅独有的属性
    private int age;

    //无参构造方法
    public Penguin() {
    }

    //两个参数的构造方法,其中name继承自父类
    public Penguin(int age, String name,) {
        super(name);
        this.age = age;
    }

    public int getAge() {
        return age;
    }

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

    //重写宠物吃食的方法
    public void eat() {
        super.health = super.health + 5;
        System.out.println("企鹅🐧吃饱了,健康值加5");
    }

    重写宠物info的方法
    public void info() {
        super.info();
        System.out.println("我的年龄是" + this.age);
    }

    //Penguin类独有的方法
    public void swimming(){
        System.out.println("企鹅🐧在游泳");
    }
}

Master主人类

public class Master {

    private String hostName;//主人姓名

    public String getHostName() {
        return hostName;
    }

    public void setHostName(String hostName) {
        this.hostName = hostName;
    }

    public Master() {
    }

    public Master(String hostName) {
        this.hostName = hostName;
    }

    //给狗🐕喂食
    public void feed(Dog dog) {
        dog.eat();
    }

    //给企鹅🐧喂食
    public void feed(Penguin penguin) {
        penguin.eat();
    }
}

TestMaster测试类

public class TestMaster {
    public static void main(String[] args) {
        //创建一个宠物类
        Pet p = new Pet("开心");
        p.eat();
        p.info();

        Dog dog = new Dog("金毛", "小金");
        dog.info();
        Penguin pg = new Penguin(12, "小鹅");
        pg.info();//不同子类对父类的不同的重写

        Master m = new Master();
        m.feed(dog);
        m.feed(pg);
        
        System.out.println("==========================子类对象的多态性");
        //子类对象的多态性:父类的引用指向子类的实例
        //这时候p1只能调用重写的方法(父类的方法)
        Pet p1 = new Dog("泰迪", "小泰");
        p1.info();//调用Dog重写的info()方法
        
        //p1可不可以调用狗类独有的方法? 不可以。
        //编译期间,程序会把p1看成是Pet对象,而Pet类里没有sleep()方法
         //现在就想用p1调用sleep方法怎么做?进行向下转型强制类型转换
        Dog dog1 = (Dog) p1;//向下转型(大转小)
        dog1.sleep();
        
        //Penguin pg1 = (Penguin) p1;//p1已经转成了Dog类型,不能再转成Penguin
        
        //使用instanceof检查p1类型,然后做相应的强制类型转换
        if (p1 instanceof Dog) {
            Dog dog2 = (Dog) p1;
            dog2.sleep();
        } else if (p1 instanceof Penguin) {
            Penguin pg1 = (Penguin) p1;
            pg1.swimming();
        }
    }

Pet p1 = new Dog(“泰迪”, “小泰”);其实是一种向下转型,这时候子类p1只能调用父类的方法,如果子类重写了,那么就调用子类重写后的方法,不能调用子类独有的方法。

那问题来了,怎么才能让p1调用独有的方法呢,这就得就得通过向下转型,Dog dog1 = (Dog) p1;将p1强制类型转换为Dog类型,然后就可以调用Dog独有的方法,但是不能调用父类的方法。

2.final

final可以用来修饰类、方法、成员变量和局部变量。

  1. final修饰类,表示这个类是最终类,不能被继承。
    父类
 public final class Person {
  }

子类在继承Person类的时候会报错👇

  1. 修饰方法,表示这个方法不能被重写。
    父类
    public class Person {
    public final void sleep() {
    System.out.println(“人在睡觉”);
    }
    }

    重写sleep方法时会报错👇

  2. 修饰成员变量。
    修饰成员变量后,成员不再有默认值,所以必须要赋值,并且赋值之后不能再修改,所以该成员变量没有setter方法,只有getter方法。
    public class Person {
    //private final String name;//没有赋值,所以报错。
    private final String name = “talent”;
    }

  3. 修饰局部变量(一般用大写字母)。
    修饰局部变量后,该变量就成了常量,一旦修改,不可改变。
    public static void main(String[] args) {
    final int A = 10;
    //A = 20;//报错
    final int B;
    B = 20;
    }

3.static

Person person = new Person();当我们通过new关键字创建对象的时候,这时候系统才会分配内存空间给每个对象,其方法才可以供外部调用。

但是,我们有时候希望无论是否产生了对象或者无论产生了多少对象,某些特定的数据在内存中只有一份。

例如所有的中国人都有个国家名称nation,每个中国人都共享这个国家名称,那么每个中国人都可以共享这个属性。

  1. static:静态的。
  2. static可以修饰变量、方法和代码块。
  3. static修饰变量后,变量变成静态变量。
    (1)按照是否使用static进行修饰,可以分为:实例变量(创建了实例之后才能使用)和静态变量。
    • 实例变量:创建了多个对象,每个对象都独立有一套类中的非静态变量(实例变量)。每个对象的非静态变量互不影响。
    • 静态变量:创建了多个对象,多个对象共享一个静态变量,当其中一个对象修改了静态变量,会导致其他对象的静态变量改变。
      (2)static修饰变量
    • 属性不再属于对象,而是属于类,只要是这个类创建的对象,都可以共享该静态变量;静态变量属于对象。
    • 静态变量随着类的加载而加载;实例变量随着对象的创建而加载。
    • 静态变量的加载时间早于对象的创建。
    • 由于类只会加载一次,静态变量在内存中只有一份。
  4. static修饰方法
    (1)static修饰方法后,这个方法就不再属于对象,而是属于类。
    (2)静态方法是随着类的加载而加载,‘类名.方法名’。
    (3)静态方法只能调用静态变量和静态方法,非静态方法能调用非静态变量和非静态方法,也能调用静态变量和静态方法。因为静态变量是在类加载的时候加载静态方法,而实例变量是在对象创建之后才加载实例变量,当静态方法调用实例变量的时候,实例变量还没有被加载,所以不能在静态方法里调用实例变量。
  5. 在静态方法里面可以使用this和super吗?
    不可以,因为这两个关键字是有了对象以后才存在,而静态方法早于对象的创建。
  6. 开发中,如何确定一个属性使用static进行修饰呢?
    如果一个属性需要被多个对象共享,使用static进行修饰。
  7. 开发中,如何确定一个方法使用static进行修饰呢?
    工具类会使用static进行修饰方法。如jdbc工具类和connection连接对象,操作静态变量的方法一般都用static修饰。

请看代码👇

public class Chinese {

    String name;
    int age;
    static String nation;

    public void eat(){
        System.out.println("在吃饭");
        //调用静态变量和实例变量
        nation = "china";
        age = 12;
        //调用静态方法
        sleep();
    }
    public static void sleep(){
        System.out.println("在睡觉");
        //静态方法只能调用静态变量
        nation = "china";
        //age = 12;//静态方不能调用实例变量
        //eat();静态方不能调用实例方法
    }
}


public class TestChinese {
    public static void main(String[] args) {
        Chinese.nation = "中国";
        Chinese.sleep();
        
        Chinese c = new Chinese();
        c.name = "张三";
        c.age = 20;
        //c.nation = "中国";

        Chinese c2 = new Chinese();
        c2.name = "李四";
        c2.age = 40;
        //c2的年龄不会影响c1的age,每个对象都独一份
        c2.nation = "china";
        //c2的nation会影响c1的nation

        System.out.println(c.nation);//china
        System.out.println(c2.nation);//china
    }
}

4.代码块

代码块也叫做初始化块。

  • 代码块的作用就是初始化类和对象。
  • 代码块只能通过static修饰,修饰之后成为静态代码块。
  • 可以看成匿名方法。

4.1.静态代码块

  1. 随着类的加载而加载,它是属于类的。
  2. 可以写输出语句。
  3. 静态代码块的执行要优先于非静态代码块的执行。
  4. 静态代码块里只能调用静态变量和静态方法。
  5. 比如jdbc对数据库连接池进行初始化时会用到静态代码块。

4.2.非静态代码块

  1. 随着对象的创建而加载,它是属于对象的。
  2. 可以写输出语句。
  3. 创建了几个对象,非静态代码块就加载几次。
  4. 作用:可以在创建对象的同时,给对象的属性进行初始化。

请看代码👇

package com.hpe.java2;

public class Animal {

    String name;
    int age;
    static String desc = "我是一只动物";

    //非静态代码块
    {
        name = "小白";
        age = 20;
        //调用静态变量
        desc = "我是一只小动物";
        //调用静态方法
        show();
        System.out.println("我是非静态代码块");
    }

    //静态代码块
    static{
        System.out.println("我是静态代码块");
        //调用非静态变量和非静态方法
        //age = 20;//报错
        //eat();//报错

        //调用静态变量和静态方法
        desc = "hehe";
        show();
    }

    public Animal() {
    }

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

    public void eat(){
        System.out.println("吃饭");
    }

    public static void show(){
        System.out.println("我是一只可爱的动物");
    }
}


package com.hpe.java2;

public class TestAnimal {
    public static void main(String[] args) {
        Animal animal = new Animal();
        Animal animal1 = new Animal();
    }
}package com.hpe.java2;

public class TestAnimal {
    public static void main(String[] args) {
        Animal animal = new Animal();
        Animal animal1 = new Animal();
    }
}

5.抽象类

随着继承层次中一个个新子类的定义,类变得越来越具体,而父类则更通用。

类的设计应该保证父类和子类能够共享特征。有时将一个父类设计的非常的抽象,以至于他没有具体的实例,这样的类叫做抽象类。

用abstract修饰一个类时,这个类叫做抽象类;用abstract修饰一个方法时,这个方法叫做抽象方法。

抽象方法:public abstract void eat();但这个方法只有方法的定义,没有方法的实现。

抽象类:在class前加abstract

特点:

  1. 抽象方法所在的类必须是抽象类。
  2. 抽象类不能实例化。
  3. 如果要实现抽象类,必须创建一个非抽象子类去继承抽象类。
  4. 子类继承抽象类,必须重写抽象类中所有的抽象方法(子类若是抽象类,则不用重写)。
  5. 抽象类里可以定义普通方法。
  6. 抽象类里可以定义构造方法。

注意:

不能用abstract修饰属性、构造器、私有方法、静态方法、final的方法。

举例说明

Animal是抽象类。

Dog是抽象类,继承Animal。

Cat是普通类,并继承Animal。

Dog2Ha是普通类,继承Dog。

请看代码👇

package com.hpe.java;

public abstract class Animal {

    //动物吃饭,就是一个抽象的,因为我们不知道具体是什么动物。
    //比如狗吃骨头,猫吃鱼🐟
    public abstract void eat();

    public abstract void sleep();

    //抽象类中可以定义普通方法
    public void show() {
        System.out.println("描述");
    }

    //可以定义构造方法吗? 可以!
    //所有类最终继承Object类
    //如果不能定义构造方法,也就代表不能使用Object里定义的方法和属性了
    public Animal() {
        super();
    }
}


package com.hpe.java;

//重写父类方法快捷键crtl+i/o

//Dog也是抽象类,对于Animal中的所有抽象方法,可以重写,可以不重写,也可以不全重写
//但是没有重写的抽象方法,交给下一代重写
public abstract class Dog extends Animal{

    //抽象类Dog类重写了Animal的eat(),sleep()交给Dog2Ha重写
    @Override
    public void eat() {
        System.out.println("汪星人喜欢吃骨头");
    }
}


package com.hpe.java;

public class Cat extends Animal{
    @Override
    public void eat() {
        System.out.println("喵星人喜欢吃鱼");
    }

    @Override
    public void sleep() {
        System.out.println("喵星人在睡觉");
    }
}


package com.hpe.java;

public class Dog2Ha extends Dog{
    @Override
    public void sleep() {
        System.out.println("我是二哈,我智商低");
    }
}


package com.hpe.java;

public class TestAnimal {

    public static void main(String[] args) {
        //抽象类不能被实例化,因为动物是一个抽象的概念
        //Animal animal = new Animal();//报错

        //Dog也是一个抽象类,不能被实例化
        //Animal dog = new Dog();

        //多态:父类的引用指向子类的实例
        Animal dog = new Dog2Ha();
        dog.eat();
        dog.show();

        Animal cat = new Cat();
        cat.eat();
    }
}

一般类和抽象类的区别:

  1. 一般类有足够的信息描述事务;抽象类描述事物的信息可能不足。
  2. 一般类中不能定义抽象方法,只能定义非抽象方法;抽象类中可定义抽象方法,也可定义非抽象方法。
  3. 一般类可以被实例化,抽象类不可以被实例化。

6.匿名xx

匿名类有两种:

  1. 与子类有关的匿名类
  2. 与接口有关的匿名类

下面用代码说明与子类有关的匿名类👇

package com.hpe.java1;

public abstract class Person {

    public abstract void eat();

    public abstract void sleep();
}

package com.hpe.java1;

public class Student extends Person{

    @Override
    public void eat() {
        System.out.println("学生在吃饭");
    }

    @Override
    public void sleep() {
        System.out.println("学生在睡觉");
    }
}

package com.hpe.java1;

public class TestPerson {

    public static void main(String[] args) {

        Person person = new Student();
        method(person);//person是非匿名对象  Student是非匿名类

        method(new Student());//匿名对象,只能用一次
        //这里之所以说只能用一次,是因为再创建一个匿名对象的话,虽然不会报错,但两个匿名对象不是同一个对象。

        //其实是new了一个子类,注意这里是子类,相当于Student类,只是这个子类没有名字
        //创建了一个匿名子类的对象person1
        //匿名子类	非匿名对象
        Person person1 = new Person() {
            @Override
            public void eat() {
            	System.out.println("这里是匿名子类的eat方法");
            }

            @Override
            public void sleep() {
		   	    System.out.println("这里是匿名子类的sleep方法");
            }
        };

        person1.eat();
        //匿名子类的最简单的写法,可以用,但是不建议用。
        //匿名子类	匿名对象
        method(new Person() {
            @Override
            public void eat() {
            }

            @Override
            public void sleep() {
            }
        });
    }

    public static void method(Person person) {
        System.out.println("学生");
    }
}

与接口有关的匿名类和上面那种几乎一样,只需把抽象类Person类变成接口即可。

7.接口

我们对电脑已经非常熟悉了,众所周知,电脑具有拍照和播放光碟的功能。现在有一个TakingPhoto类,它提供拍照的功能;还有一个PlayVCD类,它提供了播放光碟的功能。电脑同时具有这两个类的提供的功能。因此我们希望定义一个Computer类,继承TakingPhoto和PlayVCD类。但此时问题就出现了 java中是不允许多重继承的!!!

为了解决这个问题,Java提出了接口的方式,作为“替代版”的多重继承。

1.接口是什么?

(1)多个类之间的公共规范。

(2)接口的出现为了解决java不能多继承的问题。

(3)接口里的方法都是抽象方法,它相当于一个特殊的抽象类。

2.怎么定义一个接口?

public interface Traffic{
}

3.接口的特点

(1)接口里的成员变量都是常量,默认会加上public static final。

(2)接口里的方法都是抽象方法(默认方法除外–jdk1.8新特性),默认会加上public abstract。

(3)接口不能实例化,抽象类通过继承实现,接口通过创建一个类去实现接口。

(4)接口里面不能定义普通方法,可以定义默认方法。

(5)接口不能定义构造方法。

(6)一个接口可以继承一个接口,并且可以继承多个接口。

4.实现类

(1)实现接口的类叫做实现类,写法例如:public class Car implements Traffic。

(2)实现类要重写接口里面所有的抽象方法(实现类是抽象类除外)。

(3)一个是实现类可以实现多个接口。

(4)如果一个类再继承一个类的同时实现一个接口,必须先继承后实现。

5.面试题:接口和抽象类的相同点和不同点。

相同点:

(1)接口和抽象类都不能被实例化。只能被其他类实现和继承。

(2)接口和抽象类都可以包含抽象方法,实现接口和抽象类的类都必须实现这些抽象方法(实现类是抽象类除外)。

(3)接口和抽象类都可以有静态方法,通过接口名和类名调用。

不同点:

(1)接口里只能包含抽象方法,能包含默认方法,能包含静态方法,不能包含普通方法;抽象类则完全可以包含普通的方法。

(2)接口里只能定义静态常量属性,不能定义普通属性;抽象类里既可以定义普通属性,也可以定义静态常量。

(3)接口不包含构造函数;抽象类可以包含构造函数,抽象类里的构造函数并不是用于创建对象,而是让其子类调用这些构造函数来完成属于抽象类的初始化操作。

(4)接口不包含初始化块,但抽象类可以包含初始化块。

(5)一个类最多只能有一个直接父类,包括抽象类;但一个类可以直接实现多个接口,通过实现多个接口可以弥补Java的单继承不足。

用一张图来彻底说明接口和抽象类在开发中分别的作用👇。
在这里插入图片描述

通过代码来解释简单说明一下👇。

Traffic接口定义了车的一系列方法。

package com.hpe.java3;

public interface Traffic {

    int a = 10;//这是常量
    public static final int b = 10;//两种方式相同,都表示常量

    //车启动
    public abstract void start();//这是一个抽象方法

    //车加速
    abstract void add();//这也是一个抽象方法

    //车行驶
    public void run();//这也是一个抽象方法

    //车停止
    void stop();

    //jdk1.8新特性-----默认方法
    public default void m1() {
    }

    //接口里不能有构造方法
    //public Traffic(){
    //}
}

Car类实现了Traffic。

package com.hpe.java3;

//汽车类
public class Car implements Traffic, Oil {
    //重写Traffic的方法
    @Override
    public void start() {
        System.out.println("汽车启动了...");
    }

    @Override
    public void add() {
        System.out.println("汽车加速了...");
    }

    @Override
    public void run() {
        System.out.println("汽车行驶了...");
    }

    @Override
    public void stop() {
        System.out.println("汽车停止了...");
    }

    //重写Oil的方法
    @Override
    public void addOil() {
        System.out.println("汽车在加油...");
    }

}

EVs类实现了Traffic。

package com.hpe.java3;

//电动车
public class EVs implements Traffic {
    @Override
    public void start() {
        System.out.println("电动车启动了...");
    }

    @Override
    public void add() {
        System.out.println("电动车加速了...");
    }

    @Override
    public void run() {
        System.out.println("电动车行驶了...");
    }

    @Override
    public void stop() {
        System.out.println("电动车停止了...");
    }
}

测试一下。

package com.hpe.java3;

public class Test {

    public static void main(String[] args) {
        //Traffic traffic = new Traffic();//抽象类不能实例化

        //创建汽车对象
        Car car = new Car();
        car.start();
        car.run();
        car.add();
        car.stop();

        //多态
        //一般使用下面这种方式
        //接口引用指向实现类实例
        Traffic evs = new EVs();
        evs.start();
        evs.run();
        evs.add();
        evs.stop();
    }
}

8.Java8新特性:接口增强

Java 8 对接口做了进一步的增强。

  1. 接口中可以添加使用 default 关键字修饰的非抽象方法,即默认方法(或扩展方法)。
  2. 接口里可以声明静态方法,并且可以实现。

下面先说一下默认方法。

  1. 接口冲突。 当一个类实现两个接口,并且这两个接口里有同名(包括参数相同)的默认方法,那么这个实现类必须要重写这个默认方法,否者无法通过编译。

    package com.hpe.java6;

    public interface MyFun1 {
    default String getName() {
    return “interface MyFun1”;
    }
    }

    package com.hpe.java6;

    public interface MyFun2 {
    default String getName() {
    return “interface MyFun2”;
    }
    }

    package com.hpe.java6;

    public class SubClass implements MyFun2, MyFun1{
    @Override
    public String getName() {
    return “class SubClass Override”;
    }
    }

    package com.hpe.java6;

    public class Test {
    public static void main(String[] args) {
    SubClass sub = new SubClass();
    System.out.println(sub.getName("hello : "));//hello : class SubClass Override
    }
    }

注意:如果要想调用接口的默认方法,只需要修改SubClass类即可👇。

package com.hpe.java6;

public class SubClass implements  MyFun1,MyFun2{
    @Override
    public String getName(String str) {
        //注意这里super的写法
        return MyFun1.super.getName(str);
    }
}

package com.hpe.java6;

public class Test {
    public static void main(String[] args) {
        SubClass sub = new SubClass();
        System.out.println(sub.getName("hello : "));//hello : interface MyFun1
    }
}
  1. 超类优先。当继承的父类和实现的接口中有相同签名的方法时,不用重写接口的方法,优先使用父类的方法。
    package com.hpe.java6;

    public interface MyFun1 {
    default String getName(String str) {
    return str + “interface MyFun1”;
    }
    }
    package com.hpe.java6;

    public class MyClass {
    public String getName(String str) {
    return str + “class MyClass”;
    }
    }
    package com.hpe.java6;

    public class SubClass extends MyClass implements MyFun1{

    }
    package com.hpe.java6;

    public class Test {
    public static void main(String[] args) {
    SubClass sub = new SubClass();
    System.out.println(sub.getName("hello : "));//hello : class MyClass
    }
    }

再来说一下接口里的静态方法。

比较简单直接上代码👇。

public interface MyInterface {
	
	public static void show(){
		System.out.println("接口中的静态方法");
	}
 
}

public class Test {
    public static void main(String[] args) {
    	MyInterface.show();//接口中的静态方法
    }
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值