继承与多态

目录

1.继承

1.1继承的概念

1.2继承的语法

1.3父类成员访问

1.3.1子类中访问父类的成员变量

1.3.2子类中访问父类的成员方法

1.4super关键字

1.5子类构造方法

1.6 super与this

1.7实例代码块与静态代码块 和构造方法的(在继承环境下的运行顺序)

1.7.1回顾之前没有继承环境下的运行顺序

1.7.2继承环境下的运行顺序

1.8protected关键字

1.9final关键字

1.9.1修饰字段或变量,表示常量(即不可以被修改)

1.9.2修饰类(即类就不可以被继承)

1.9.3修饰方法(既不能进行方法的重写)

1.10继承方式

2.多态

2.1多态实现的条件

2.2方法的重写

2.3向上转型与向下转型

2.3.1向上转型

2.3.2向下转型

2.4避免在构造方法中调用方法的重写

3.导入包中的类

3.1java中自带的包

3.2自定义包


1.继承

在现实生活中继承有继承财产,而在java代码中的继承就是继承代码。

现在看一个例子

package 继承;

public class Dog {
    public String name;
    public int age;

    public void eat(){
        System.out.println(this.name+"正在吃饭");
    }

}

package 继承;

public class Cat {
    public String name;
    public int age;

    public void eat(){
        System.out.println(this.name+"正在吃饭");

    }
}

会发现出现了代码重复,虽然在不同类中

而我们如果把相同的代码放进一个单独的类中,在使用继承的方法,就完美的解决了这个问题。

1.1继承的概念

继承(inheritance)机制:是面向对象程序设计使代码可以复用的最重要的手段,它允许程序员在保持原有类特 性 的基础上进行扩展,增加新功能,这样产生新的类,称派生类。继承呈现了面向对象程序设计的层次结构, 体现了 由简单到复杂的认知过程。继承主要解决的问题是:共性的抽取,实现代码复用。

例如:狗和猫都是动物,那么我们就可以将共性的内容进行抽取,然后采用继承的思想来达到共用。

上述图示中,

Dog和Cat都继承了Animal类,其中:Animal类称为父类/基类或超类,Dog和Cat可以称为Animal的 子类/派生类,继承之后,子类可以复用父类中成员,子类在实现时只需关心自己新增加的成员即可。

1.2继承的语法

在Java中如果要表示类之间的继承关系,需要借助extends关键字

父类

package 继承;

public class Animal {
    public String name ;
    public int age;

}

子类

package 继承;

public class Dog extends Animal {
    public void eat(){
        System.out.println(this.name+"正在吃饭");
    }

}
package 继承;

public class Cat extends Animal{
    public void eat(){
        System.out.println(this.name+"正在吃饭");

    }
}

测试类

package 继承;

public class Test {
    public static void main(String[] args) {
        Dog dog =new Dog();
        dog.name="旺财";
        dog.age=11;
        dog.eat();
        Cat cat =new Cat();
        cat.name="咪咪";
        cat.age=12;
        cat.eat();



    }
}

结果

注意:

1. 子类会将父类中的成员变量或者成员方法继承到子类中了

2. 子类继承父类之后,必须要新添加自己特有的成员,体现出与基类的不同,否则就没有必要继承了

1.3父类成员访问

在继承体系中,子类将父类中的方法和字段继承下来了,那在子类中能否直接访问父类中继承下来的成员呢?

1.3.1子类中访问父类的成员变量

1. 子类和父类不存在同名成员变量

public class Base {
int a;
int b;
}
public class Derived extends Base{
int c;
public void method(){
a = 10; // 访问从父类中继承下来的a
b = 20; // 访问从父类中继承下来的b
c = 30; // 访问子类自己的c
}
}

2. 子类和父类成员变量同名

public class Base {
int a;
int b;
int c;
}
/
public class Derived extends Base{
int a; // 与父类中成员a同名,且类型相同
char b; // 与父类中成员b同名,但类型不同
public void method(){
a = 100; // 访问父类继承的a,还是子类自己新增的a?
b = 101; // 访问父类继承的b,还是子类自己新增的b?
c = 102; // 子类没有c,访问的肯定是从父类继承下来的c
// d = 103; // 编译失败,因为父类和子类都没有定义成员变量b
}
}

在子类方法中 或者 通过子类对象访问成员时

1.如果访问的成员变量子类中有,优先访问自己的成员变量。

2.如果访问的成员变量子类中无,则访问父类继承下来的,

3.如果父类也没有定义,则编译报错。 如果访问的成员变量与父类中成员变量同名,则优先访问自己的

成员变量访问遵循就近原则,自己有优先自己的,如果没有则向父类中找。

1.3.2子类中访问父类的成员方法

1.成员方法名字不同

public class Base {
public void methodA(){
System.out.println("Base中的methodA()");
}
}
public class Derived extends Base{
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodB(); // 访问子类自己的methodB()
methodA(); // 访问父类继承的methodA()
// methodD(); // 编译失败,在整个继承体系中没有发现方法methodD()
}
}

2.成员方法名相同的时候

public class Base {
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}
public class Derived extends Base{
public void methodA(int a) {
System.out.println("Derived中的method(int)方法");
}
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
methodA(); // 没有传参,访问父类中的methodA()
methodA(20); // 传递int参数,访问子类中的methodA(int)
methodB(); // 直接访问,则永远访问到的都是子类中的methodB(),基类的无法访问到
}
}

1,通过子类对象访问父类与子类中不同名方法时,优先在子类中找,找到则访问,否则在父类中找,找到 则访问,否则编译报错。

2,通过派生类对象访问父类与子类同名方法时,如果父类和子类同名方法的参数列表不同(重载),根据调用 方法适传递的参数选择合适的方法访问,如果没有则报错

1.4super关键字

super关键字,该关键字主要作用:在子类方法中访问父 类的成员

public class Base {
int a;
int b;
public void methodA(){
System.out.println("Base中的methodA()");
}
public void methodB(){
System.out.println("Base中的methodB()");
}
}
public class Derived extends Base{
int a; // 与父类中成员变量同名且类型相同
char b; // 与父类中成员变量同名但类型不同
// 与父类中methodA()构成重载
public void methodA(int a) {
System.out.println("Derived中的method()方法");
}
// 与基类中methodB()构成重写(即原型一致,重写后序详细介绍)
public void methodB(){
System.out.println("Derived中的methodB()方法");
}
public void methodC(){
// 对于同名的成员变量,直接访问时,访问的都是子类的
a = 100; // 等价于: this.a = 100;
b = 101; // 等价于: this.b = 101;
// 注意:this是当前对象的引用
// 访问父类的成员变量时,需要借助super关键字
// super是获取到子类对象中从基类继承下来的部分
super.a = 200;
super.b = 201;
// 父类和子类中构成重载的方法,直接可以通过参数列表区分清访问父类还是子类方法
methodA(); // 没有传参,访问父类中的methodA()
methodA(20); // 传递int参数,访问子类中的methodA(int)
// 如果在子类中要访问重写的基类方法,则需要借助super关键字
methodB(); // 直接访问,则永远访问到的都是子类中的methodA(),基类的无法访问到
super.methodB(); // 访问基类的methodB()

【注意事项】

1. 只能在非静态方法中使用

2. 在子类方法中,访问父类的成员变量和方法。

1.5子类构造方法

子类对象构造时,需要先调用基类构造方法,然后执行子类的构造方法。

public class Base {
public Base(){
System.out.println("Base()");
}
}
public class Derived extends Base{
public Derived(){
// super(); // 注意子类构造方法中默认会调用基类的无参构造方法:super(),
// 用户没有写时,编译器会自动添加,而且super()必须是子类构造方法中第一条语句,
// 并且只能出现一次
System.out.println("Derived()");
}
}
public class Test {
public static void main(String[] args) {
Derived d = new Derived();
}
}


结果打印:
Base()
Derived()

子类对象中成员是有两部分组成的,基类继承下来的以及子类新增加的部分 。父子父子 肯定是先有父再有子,所以在构造子类对象时候 ,先要调用基类的构造方法,将从基类继承下来的成员构造完整 ,然后再调用子类自己的构造方法,将子类自己新增加的成员初始化完整

注意:

1. 若父类显式定义无参或者默认的构造方法,在子类构造方法第一行默认有隐含的super()调用,即调用基类构 造方法

2. 如果父类构造方法是带有参数的,此时需要用户为子类显式定义构造方法,并在子类构造方法中选择合适的 父类构造方法调用,否则编译失败。

3. 在子类构造方法中,super(...)调用父类构造时,必须是子类构造函数中第一条语句。

4. super(...)只能在子类构造方法中出现一次,并且不能和this同时出现

1.6 super与this

相同点

1. 都是Java中的关键字

2. 只能在类的非静态方法中使用,用来访问非静态成员方法和字段

3. 在构造方法中调用时,必须是构造方法中的第一条语句,并且不能同时存在

不同点

1. this是当前对象的引用,当前对象即调用实例方法的对象,super相当于是子类对象中从父类继承下来部分成 员的引用

2. 在非静态成员方法中,this用来访问本类的方法和属性,super用来访问父类继承下来的方法和属性

3. 在构造方法中:this(...)用于调用本类构造方法,super(...)用于调用父类构造方法,两种调用不能同时在构造 方法中出现

4. 构造方法中一定会存在super(...)的调用,用户没有写编译器也会增加,但是this(...)用户不写则没有

1.7实例代码块与静态代码块 和构造方法的(在继承环境下的运行顺序)

1.7.1回顾之前没有继承环境下的运行顺序

package 继承;

class Person {
   public String name;
   public int age;
   public Person (String name,int age){
       this.name=name;
       this.age=age;
       System.out.println("这个是构造方法的执行");
   }
    {
        System.out.println("这是实例代码块的执行");
    }
    static
    {
        System.out.println("这个是静态代码块的执行");
    }

}

public class Test {
    public static void main(String[] args) {
//        Dog dog =new Dog();
//        dog.name="旺财";
//        dog.age=11;
//        dog.eat();
//        Cat cat =new Cat();
//        cat.name="咪咪";
//        cat.age=12;
//        cat.eat();
        Person person=new Person("wo",55);
        System.out.println("----------------------");
        Person person1=new Person("fskd",5);
    }
}

执行结果

注意;

1. 静态代码块先执行,并且只执行一次,在类加载阶段执行

2. 当有对象创建时,才会执行实例代码块,实例代码块执行完成后,最后构造方法执行

1.7.2继承环境下的运行顺序

父类

package 继承;

public class Animal {
    public String name ;
    public int age;
    public Animal (String name,int age){
        this.name=name;
        this.age=age;
        System.out.println("父类  这个是构造方法的执行");
    }
    {
        System.out.println("父类   这是实例代码块的执行");
    }
    static
    {
        System.out.println("父类    这个是静态代码块的执行");
    }

}

子类

package 继承;

class Person extends Animal {
   public String name;
   public int age;
   public Person (String name,int age){
      super(name,age);
       System.out.println("子类  这个是构造方法的执行");
   }
    {
        System.out.println("子类   这是实例代码块的执行");
    }
    static
    {
        System.out.println("子类   这个是静态代码块的执行");
    }

}

public class Test {
    public static void main(String[] args) {
//        Dog dog =new Dog();
//        dog.name="旺财";
//        dog.age=11;
//        dog.eat();
//        Cat cat =new Cat();
//        cat.name="咪咪";
//        cat.age=12;
//        cat.eat();
        Person person=new Person("wo",55);
        System.out.println("----------------------");
        Person person1=new Person("fskd",5);
    }
}

执行结果

通过分析执行结果,得出以下结论:

1、父类静态代码块优先于子类静态代码块执行,且是最早执行

2、父类实例代码块和父类构造方法紧接着执行

3、子类的实例代码块和子类构造方法紧接着再执行

4、第二次实例化子类对象时,子类和父类的

1.8protected关键字

// 为了掩饰基类中不同访问权限在子类中的可见性,为了简单类B中就不设置成员方法了
// extend01包中
public class B {
private int a;
protected int b;
public int c;
int d;
}
// extend01包中
// 同一个包中的子类
public class D extends B{
public void method(){
// super.a = 10; // 编译报错,父类private成员在相同包子类中不可见
super.b = 20; // 父类中protected成员在相同包子类中可以直接访问
super.c = 30; // 父类中public成员在相同包子类中可以直接访问
super.d = 40; // 父类中默认访问权限修饰的成员在相同包子类中可以直接访问
}
}
// extend02包中
// 不同包中的子类
public class C extends B {
public void method(){
// super.a = 10; // 编译报错,父类中private成员在不同包子类中不可见
super.b = 20; // 父类中protected修饰的成员在不同包子类中可以直接访问



super.c = 30; // 父类中public修饰的成员在不同包子类中可以直接访问
//super.d = 40; // 父类中默认访问权限修饰的成员在不同包子类中不能直接访问
}
}
// extend02包中
// 不同包中的类
public class TestC {
public static void main(String[] args) {
C c = new C();
c.method();
// System.out.println(c.a); // 编译报错,父类中private成员在不同包其他类中不可见
// System.out.println(c.b); // 父类中protected成员在不同包其他类中不能直接访问
System.out.println(c.c); // 父类中public成员在不同包其他类中可以直接访问
// System.out.println(c.d); // 父类中默认访问权限修饰的成员在不同包其他类中不能直接访问
}
}

1.9final关键字

final关键可以用来修饰变量、成员方法以及类。

1.9.1修饰字段或变量,表示常量(即不可以被修改)

1.9.2修饰类(即类就不可以被继承)

我们平时用的字符串就是用Sreing修饰的,所以不能被改变

1.9.3修饰方法(既不能进行方法的重写)

1.10继承方式

1.单继承

2.多层继承

3.不同类继承一个类

4.多继承·(不支持)

2.多态

2.1多态实现的条件

1. 必须在继承体系下

2. 子类必须要对父类中方法进行重写

3. 通过父类的引用调用重写的方法

多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。

父类

package 继承;

public class Animal {
    public String name ;
    public int age;

    public Animal (String name,int age){
        this.name=name;
        this.age=age;
       // System.out.println("父类  这个是构造方法的执行");
    }
//    {
//        System.out.println("父类   这是实例代码块的执行");
//    }
//    static
//    {
//        System.out.println("父类    这个是静态代码块的执行");
//    }

    public void eat(){
        System.out.println(this.name+"正在吃饭");
    }

}

Dog子类

package 继承;

//package 继承;

public class Dog extends Animal {
    public Dog (String name,int age){
        super(name,age);

    }
    public void eat(){
        System.out.println(this.name+"汪汪叫");
    }

}
//    int a;
//    public void eat() {
//        System.out.println(this.name + "正在吃饭");
//        this.a=77;
//        super.a=88;
//    }
//    //被static修饰的方法,是属于静态方法
//    //this 和super一样都是依赖于对象,但是static修饰后属于类
//        public static void add () {
//        //this.a;
//        //super.a;
//
//        }
//
//
//}

Cat子类

package 继承;

public class Cat extends Animal {
    public Cat(String name, int age) {
        super(name, age);
    }

    public void eat() {
        System.out.println(this.name + "喵喵叫");
    }
}

//    public void eat(){
//        System.out.println(this.name+"正在吃饭");
//
//    }
//}

teat测试类

package 继承;

class Person extends Animal {
    public String name;
    public int age;

    public Person(String name, int age) {
        super(name, age);
        // System.out.println("子类  这个是构造方法的执行");
    }
//    {
//        System.out.println("子类   这是实例代码块的执行");
//    }
//    static
//    {
//        System.out.println("子类   这个是静态代码块的执行");
//    }
}

public class Test {
//    public static Animal fun(){
//        Cat cat=new Cat("s",5);
//        return cat;
//    }
//    public static void fun(Animal animal){
//
//    }

    public static void main(String[] args) {
        //先进行向上转型
        Animal animal=new Dog("旺财",5);
        animal.eat();
        Animal animal1=new Cat("喵喵",8);
        animal1.eat();
    }
}

执行结果

2.2方法的重写

重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程 进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定 于自己的行为。 也就是说子类能够根据需要实现父类的方法

方法重写的规则

1.子类在重写父类的方法时一般必须跟父类的方法一样即(方法名 参数列表 返回值类型与父类的方法一样)

2.被重写的方法返回值类型可以不一样,但一定要有父子关系

3.访问权限不能比被重写的父类的方法的访问权限还要低,例如父类中的访问权限为public时

子类中的访问权限就不能是protected

4.父类被static,private,声明和构造方法都不能被重写

5.重写的方法, 可以使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心 将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法 构成重写.

重载于重写的区别

方法重载是一个类的多态性表现,而方法重写是子类与父类的一种多态性表现

2.3向上转型与向下转型

2.3.1向上转型

三种方式

1.直接赋值

        2.方法传参

3.方法返回

向上转型的优点:让代码实现更简单灵活。

向上转型的缺陷:不能调用到子类特有的方法。

2.3.2向下转型

将一个子类对象经过向上转型之后当成父类方法使用,再无法调用子类的方法,但有时候可能需要调用子类特有的 方法,此时:将父类引用再还原为子类对象即可,即向下转换

package 继承;

class Person extends Animal {
    public String name;
    public int age;

    public Person(String name, int age) {
        super(name, age);
        // System.out.println("子类  这个是构造方法的执行");
    }
//    {
//        System.out.println("子类   这是实例代码块的执行");
//    }
//    static
//    {
//        System.out.println("子类   这个是静态代码块的执行");
//    }
}

public class Test {
//    public static Animal fun(){
//        Cat cat=new Cat("s",5);
//        return cat;
//    }
//    public static void fun(Animal animal){
//
//    }

    public static void main(String[] args) {
        //先进行向上转型
        Animal animal=new Dog("旺财",5);
        animal.eat();
        Animal animal1=new Cat("喵喵",8);
        animal1.eat();
        //这是调用子类中特有的方法就会报错
       // animal.brea();

        //这时就可以使用向下转型
      Dog dog=(Dog)animal;
      dog.brea();

      //但是向下转型不能乱转  例如
       //无法正常还原,因为向上转型的时候时由子类Dog;
        // Cat cat=(Cat)animal;
        //向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入
        //了 instanceof ,如果该表达式为true,则可以安全转换。

    }

}

运行结果

向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入 了 instanceof ,如果该表达式为true,则可以安全转换。

package 继承;

class Person extends Animal {
    public String name;
    public int age;

    public Person(String name, int age) {
        super(name, age);
        // System.out.println("子类  这个是构造方法的执行");
    }
//    {
//        System.out.println("子类   这是实例代码块的执行");
//    }
//    static
//    {
//        System.out.println("子类   这个是静态代码块的执行");
//    }
}

public class Test {
//    public static Animal fun(){
//        Cat cat=new Cat("s",5);
//        return cat;
//    }
//    public static void fun(Animal animal){
//
//    }

    public static void main(String[] args) {
        //先进行向上转型
        Animal animal=new Dog("旺财",5);
        animal.eat();
        Animal animal1=new Cat("喵喵",8);
        animal1.eat();
        //这是调用子类中特有的方法就会报错
       // animal.brea();

        //这时就可以使用向下转型
      //Dog dog=(Dog)animal;
      //dog.brea();

      //但是向下转型不能乱转  例如
       //无法正常还原,因为向上转型的时候时由子类Dog;
        // Cat cat=(Cat)animal;
        //向下转型用的比较少,而且不安全,万一转换失败,运行时就会抛异常。Java中为了提高向下转型的安全性,引入
        //了 instanceof ,如果该表达式为true,则可以安全转换。

        if(animal instanceof Dog){
            Dog dog=(Dog)animal;
            dog.brea();
        }
        if(animal instanceof Cat){
            Cat cat=(Cat)animal;
            cat.fun();
        }

    }

}

2.4避免在构造方法中调用方法的重写

一段有坑的代码. 我们创建两个类, B 是父类, D 是子类. D 中重写 func 方法. 并且在 B 的构造方法中调用 func

class B {
public B() {
// do nothing
func();
}
public void func() {
System.out.println("B.func()");
}
}
class D extends B {
private int num = 1;
@Override
public void func() {
System.out.println("D.func() " + num);
}
}
public class Test {
public static void main(String[] args) {
D d = new D();
}
}
// 执行结果
D.func() 0

构造 D 对象的同时, 会调用 B 的构造方法.

B 的构造方法中调用了 func 方法, 此时会触发动态绑定, 会调用到 D 中的 func 此时 D 对象自身还没有构造,

此时 num 处在未初始化的状态, 值为 0. 如果具备多态性,num的值应该是1.

所以在构造函数内,尽量避免使用实例方法,除了final和private方法。

3.导入包中的类

3.1java中自带的包

Java 中已经提供了很多现成的类供我们使用. 例如Date类:

1.可以使用 java.util.Date 导入 java.util 这个包中的 Date 类.

public class Test {
public static void main(String[] args) {
java.util.Date date = new java.util.Date();
// 得到一个毫秒级别的时间戳
System.out.println(date.getTime());
}
}

2.但是这种写法比较麻烦一些, 可以使用 import语句导入包

mport java.util.Date;
public class Test {
public static void main(String[] args) {
       Date date = new Date();
       // 得到一个毫秒级别的时间戳
       System.out.println(date.getTime());
}
}

3.如果需要使用 java.util 中的其他类, 可以使用 import java.util.*

import java.util.*;
public class Test {
public static void main(String[] args) {
      Date date = new Date();
      // 得到一个毫秒级别的时间戳
      System.out.println(date.getTime());
}
}

更建议显式的指定要导入的类名. 否则还是容易出现冲突

import java.util.*;
import java.sql.*;
public class Test {
public static void main(String[] args) {
     // util 和 sql 中都存在一个 Date 这样的类, 此时就会出现歧义, 编译出错
      Date date = new Date();
     System.out.println(date.getTime());
}
}
// 编译出错
Error:(5, 9) java: 对Date的引用不明确
java.sql 中的类 java.sql.Date 和 java.util 中的类 java.util.Date 都匹配

改成如下情况

在这种情况下需要使用完整的类名

import java.util.*;
import java.sql.*;
public class Test {
public static void main(String[] args) {
   java.util.Date date = new java.util.Date();
   System.out.println(date.getTime());
}
}

可以使用import static导入包中静态的方法和字段

import static java.lang.Math.*;
public class Test {
public static void main(String[] args) {
    double x = 30;
     double y = 40;
    // 静态导入的方式写起来更方便一些.
    // double result = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
     double result = sqrt(pow(x, 2) + pow(y, 2));
        System.out.println(result);
}
}

3.2自定义包

Computer类位于com.bit.demo1包中,TestComputer位置com.bit.demo2包中:

package com.bit.demo1;
public class Computer {
   private String cpu; // cpu
    private String memory; // 内存
      public String screen; // 屏幕
         String brand; // 品牌
public Computer(String brand, String cpu, String memory, String screen) {
     this.brand = brand;
   this.cpu = cpu;
     this.memory = memory;
  this.screen = screen;
}
public void Boot(){
    System.out.println("开机~~~");
}
public void PowerOff(){
   System.out.println("关机~~~");
}
public void SurfInternet(){
    System.out.println("上网~~~");
}

///
package com.bite.demo2;
import com.bite.demo1.Computer;
public class TestComputer {
public static void main(String[] args) {
      Computer p = new Computer("HW", "i7", "8G", "13*14");
     System.out.println(p.screen);
  // System.out.println(p.cpu); // 报错:cup是私有的,不允许被其他类访问
  // System.out.println(p.brand); // 报错:brand是default,不允许被其他包中的类访问
}
}
// 注意:如果去掉Computer类之前的public修饰符,代码也会编译失败

注意:导入自定义包中的类是不同的

  • 21
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值