Java面向对象学习笔记(五)

本文详细介绍了Java中的接口、内部类和枚举。接口作为规范定义了一组方法,实现类必须覆盖这些方法。接口支持多继承,类只能单继承。内部类分为实例、静态、局部和匿名内部类,它们提供了更好的封装和代码组织。枚举是固定的类集合,常用于表示固定数量的类型。枚举类中的常量可以直接使用,支持switch语句。枚举在单例模式中也有独特应用。
摘要由CSDN通过智能技术生成

二、面对对象---5.

(一)接口

176、什么是接口和为什么需要接口

177、接口的定义和接口成员

多个抽象类的抽象就是接口。Java中最小的程序单元就是类,接口其实就是一个特殊的类。Java中的接口表示规范,用于定义一组方法,表示某一类事务必须要具备的功能,要求实现类必须来实现该接口并提供方法实现。

定义类语法: [public] class 类名{}

定义接口语法:[public] interface 接口名{},在这里还没有考虑接口的父接口等等

接口起名问题:表示具有某些能力,有些人习惯以able结尾。Walkable,表示可以行走的;有的公司或个人习惯以I打头,表示接口如:IWalkable.java

成功编译之后和类一样,具有一份字节码。反编译工具2:jd_gui

接口存在的成员:

1):接口中没有构造器,接口不能new(创建对象),接口中不能定义普通方法

2):接口中定义的成员变量实质是全局静态常量(默认使用public static final修饰)。如:public static final String NAME = "龙17"。(有人喜欢用接口来封装多个常量信息称之为常量接口,其目的和常量类相同,不推荐)

(标志接口:接口中没有任何成员,就仅仅是一个接口的定义,就是一个标志。其他类的实现该接口,就属于该家族,我们可以通过第三方代码赋予该接口实现类特殊的功能,不推荐)

3):接口中定义的方法都是公共的抽象方法,默认使用public abstract 来修饰,如:public abstract void walk();  一般地,我们在接口中定义方法,不喜欢用修饰符

4):接口中定义的内部类都是公共的静态内部类,默认使用public static来修饰内部类,如:public static interface ABC{}

//定义一个接口
interface IWalkable
{
	String NAME = "龙17"; //等价于 public static final String NAME = "龙17"
	void walk(); //等价于public abstract void walk();
	interface ABC{}  //等价于 public static interface ABC{}
	//IWalkable(){} //错误: 需要<标识符> ,接口中不能定义构造器
	void walk(){}; //错误: 已在接口 IWalkable中定义了方法 walk()  ,接口中不能定义普通方法
}
//演示接口
public class InterfaceDemo 
{
	public static void main(String[] args) 
	{
		System.out.println("Hello World!");
	}
}

178、接口的特点和接口的继承

接口的特点:

  1. 没有构造方法,也不能显示定义构造器,不能实例化。
  2. 接口只能继承接口,不能继承类,且接口支持多继承(类是单继承关系)。 语法:[修饰符] interface 接口名 extends 接口1,接口2
  3. 接口里的方法全是抽象的,默认修饰符是public abstract。
  4. 接口里的字段全是全局静态常量,默认修饰符是public static final。
  5. 接口里的内部类全是静态的,默认修饰符是public static。

实现类和接口之间只有实现关系,没有继承关系,使用implements来表示;

接口和接口之间只能是继承关系,使用extends来表示;

类和类之间也可以有继承关系,使用extends来表示。

//定义一个接口
//爬行动物规范
interface IWalkable
{
	void walk();
}
//水生动物规范
interface ISwimable
{
	void swim();
}
//两栖动物
interface Amphibiousable extends IWalkable,ISwimable
{
	
}

179、接口的实现关系

接口的实现者:实现类

接口仅仅只是定义了某一类事物应该具有某些功能,但是没有提供任何实现。

此时,我们得提供类,再让该类去实现接口,并覆盖接口中的方法,从而实现了接口中定义的功能。

类实现接口的方法:[修饰符] class 类名 extends 父类 implements 接口1,接口2{}

一个类可以实现多个接口,从而也弥补了类的单继承问题。

接口和实现类之间的关系,严格上称之为“实现关系”,使用implements来表示,但是在开发,有时候为了方便也把这个实现关系称之为特殊继承关系。所以可以这样理解:接口是实现类的父类。

面向接口编程:

        接口 变量 = 创建实现类对象;  //体现了多态思想

        接口和实现类的多态关系才是我们见得最多的。

因为接口中的方法是抽象的,公共的,所以实现类必须覆盖接口中的方法,并且方法必须使用public修饰。

//定义一个接口
//爬行动物规范
interface IWalkable
{
	void walk();
}
//水生动物规范
interface ISwimable
{
	void swim();
}
//两栖动物
interface Amphibiousable extends IWalkable,ISwimable
{
	
}
class Animal
{
}
//猫
class Cat extends Animal implements IWalkable
{
	public void walk()
	{
		System.out.println("走猫步");
	}
}
class Demo1 
{
	public static void main(String[] args) 
	{
		//创建猫对象,并调用方法
		Cat c = new Cat(); //唾弃,鄙视
		IWalkable w = new Cat(); //面向接口编程,存在多态
		w.walk(); //体现多态特征:执行Cat类中的walk方法
	}
}

180、类和类以及类和接口的关系图

//定义一个接口
//爬行动物规范
interface IWalkable
{
	void walk();
}
//水生动物规范
interface ISwimable
{
	void swim();
}
//两栖动物
interface Amphibiousable extends IWalkable,ISwimable
{
	
}
class Animal
{
}
//猫
class Cat extends Animal implements IWalkable
{
	public void walk()
	{
		System.out.println("走猫步");
	}
}
//鱼
class Fish extends Animal implements ISwimable
{
	public void swim()
	{
		System.out.println("游啊游");
	}
}
//青蛙,一个类实现多个接口
class Frog extends Animal implements IWalkable,ISwimable
{
	public void walk()
	{
		System.out.println("跳跃");
	}
	public void swim()
	{
		System.out.println("蛙泳");
	}
}
class Demo1 
{
	public static void main(String[] args) 
	{
		//创建猫对象,并调用方法2
		Cat c = new Cat(); //唾弃,鄙视
		IWalkable w = new Cat(); //面向接口编程,存在多态
		w.walk(); //体现多态特征:执行Cat类中的walk方法

		ISwimable f = new Fish();
		f.swim();

		Frog frog = new Frog();
		frog.swim();
		frog.walk();
	}
}

181、接口和抽象类的区别

接口和抽象类的区别:

相同点:

  1. 都位于继承的顶端,用于被其他类实现或继承
  2. 都不能实例化
  3. 都可以定义抽象方法,其子类/实现类都必须覆写这些抽象方法

区别:

  1. 接口没有构造方法,抽象类有构造方法
  2. 抽象类可包含普通方法和抽象方法,接口只能包含抽象方法(java8之前)
  3. 一个类只能继承一个直接父类(可能是抽象类),接口是多继承的并且只支持一个类实现多个接口(接口弥补了java的单继承)
  4. 成员变量:接口里默认是public static final,抽象类是默认包权限
  5. 方法:接口里默认是public abstract,抽象类默认是默认包访问权限
  6. 内部类:接口里默认是public static,抽象类默认是默认包访问权限

-------------------------

如果接口和实现类可以完成相同的功能,尽量使用接口,面向接口编程

设计模式:接口和抽象类结合使用的(适配器模式)

182、面向接口编程思想

面向接口编程:多态的好处:把实现类对象赋给接口类型变量,屏蔽了不同实现类之间的实现差异,从而可以做到通用编程

案例:使用USB设备来工作

//指定USB规范
interface IUSB
{
	public void swapData();
}
//USB鼠标
class Mouse implements IUSB 
{
	public void swapData()
	{
		System.out.println("鼠标在移动");
	}
}
//USB打印机
class Print  implements IUSB
{
	public void swapData()
	{
		System.out.println("打印");
	}
}
//主板
class MotherBoard
{
	private static IUSB[] usbs = new IUSB[6];
	private static int index = 0;
	//把设备插入到主板中的功能,接收IUSB类型的对象
	public static void pluginIn(IUSB usb)
	{
		if (index == usbs.length)
		{
			System.out.println("USB插槽已经插满了");
			return;
		}
		usbs[index] = usb;
		index++;
	}
	//取出主板中的每一个USB设备,并工作
	public static void doWork()
	{
		for (IUSB usb : usbs )
		{
			if (usb != null)
			{
				usb.swapData();
			}
		}
	}
}
//面向接口编程    案例:使用USB设备来工作
class USBDemo 
{
	public static void main(String[] args) 
	{
		//创建鼠标对象
		MotherBoard.pluginIn(new Mouse());
		//安装打印机
		MotherBoard.pluginIn(new Print());
		//调用主板的工作方法
		MotherBoard.doWork();
	}
}

(二)内部类

183、内部类概述

内部类:定义在类结构中的另一个类

类中定义的成员:字段、方法、内部类

为什么使用内部类:

  1. 增强封装,把内部类隐藏在外部类之内,不许其他类访问该类
  2. 内部类能提高代码的可读性和可维护性,把小型类嵌入到外部类中结构上代码更靠近
  3. 内部类可以直接访问外部类的成员

内部类根据使用不同的修饰符或定义的位置不同,分成四种:

  1. 实例内部类:内部类没有使用static修饰
  2. 静态内部类:内部类使用了static修饰
  3. 局部内部类:在方法中定义的内部类
  4. 匿名内部类适合于仅使用一次使用的类,属于局部内部类的特殊情况

内部类看做是外部类的一个成员,好比字段,那么内部类可以使用public/缺省/protected/private修饰,还可以使用static修饰

外部类的访问修饰符,使用public,或者缺省

实例内部类:没有使用static修饰的内部类,属于外部类的对象,不属于外部类本身

实例内部类特点:

  1. 创建实例内部类前,必须存在外部类对象,通过外部类对象创建内部类对象(当存在内部类对象时,一定存在外部类对象)
  2. 实例内部类的实例自动持有外部类的实例的引用,内部类可以直接访问外部类成员
  3. 外部类中不能直接访问内部类的成员,必须通过内部类的实例去访问
  4. 实例内部类中不能定义静态成员,只能定义实例成员
  5. 如果实例内部类和外部类存在同名的字段或方法abc,那么在内部类中:

                   this.abc:表示访问内部类成员

                   外部类.this.abc:表示访问外部类成员

对于每个内部类来说,Java编译器会生成独立.class文件

成员内部类:外部类名$内部类名

局部内部类:外部类名$数字内部类名

匿名内部类:外部类名$数字

//外部类
class Outter
{
	String name = "Outter.name";
	public void ooxx()
	{
		System.out.println(this.new Inner().age); //3.外部类中不能直接访问内部类成员,必须通过内部类的实例去访问
	}
	//实例内部类
	class Inner
	{
		int age = 17;  
		String name = "Inner.name";
		public void test() //4.实例内部类中不能定义静态成员(不能加static),只能定义实例成员
		{
			//5.如果实例内部类和外部类存在同名的字段或方法,那么在内部类中:this.abc:表示访问内部类成员      外部类.this.abc:表示访问外部类成员
			String name = "Local.name";
			System.out.println(name); //Local.name
			System.out.println(this.name); //Inner.name
			System.out.println(Otter.this.name); //Outter.name
		}
	}
}
//演示实例内部类
class InstanceInnerClassDemo 
{
	public static void main(String[] args) 
	{
		//1.创建实例内部类前,必须存在外部类对象,通过外部类对象创建内部类对象(当存在内部类对象时,一定存在外部类对象)
		//创建Inner的对象
		//Outter out = new Outter();
		//Outter.Inner in = out.new Inner();
		Outter.Inner in = new Outter().new Inner(); 
		System.out.println(in);
		//2.实例内部类的实例自动持有外部类的实例引用,内部类可以直接访问外部外部类成员
		in.test();  
	}
}

静态内部类:

使用static修饰:

  1. 静态内部类的实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时,不必创建外部类的实例
  2. 静态内部类可以直接访问外部类的静态成员,如果访问外部类的实例成员,必须通过外部类的实例去访问
  3. 在静态内部类中可以定义静态成员和实例成员
  4. 测试类可以通过完整类名直接访问静态内部类的静态成员
class Outter
{
	String name = "Outter.name";
	static String name2 = "name2";
	static class Inner
	{
		static int age = 17;  //定义静态成员和实例成员
		//String name = "Inner.name";
		public void test() 
		{ 
			System.out.println(name2); //可以直接访问外部类的静态成员
			System.out.println(new Outter().name); //访问外部类的实例成员,必须通过外部类的实例去访问
		}
	}
}

class InstanceInnerClassDemo 
{
	public static void main(String[] args) 
	{
		Outter.Inner in = new Outter.Inner();  //实例不会自动持有外部类的特定实例的引用,在创建内部类的实例时,不必创建外部类的实例
		in.test();
		System.out.println( Outter.Inner.age); //通过完整类名直接访问静态内部类的静态成员
	}
}

185、局部内部类分析

局部内部类(dasi不用):在方法中定义的内部类,其可见范围是当前方法和局部变量是同一个级别

  1. 不能使用public,private,protected,static修饰符
  2. 局部内部类只能在当前方法中使用
  3. 局部内部类和实例内部类一样,不能包含静态成员
  4. 局部内部类和实例内部类,可以访问外部类的所有成员
  5. 局部内部类访问局部变量必须使用final修饰(java8是自动隐式加上final,但依然是常量,不能改变值)。原因:如果当前方法不是main方法,那么当前方法调用完毕之后,当前方法的栈帧被销毁,方法内部的局部变量的空间全部被销毁,然后局部内部类是定义在方法中的,而且方法中会创建局部内部类对象,而局部内部类会去访问局部变量,当当前方法被销毁的时候,对象还在堆内存,依然持有对局部变量的引用,但是方法被销毁的时候局部变量已经被销毁了。

             此时出现:在堆内存中,一个对象引用着一个不存在的数据。为了避免该问题,我们使用final修饰局部变量,从而变成常量,永驻内存空间,即使方法销毁后,该局部变量也在内存中,对象可以继续持有。

 

186、匿名内部类分析

匿名内部类(Anonymous),是一个没有名称的局部内部类,适合只使用一次的类。在开发中经常有这样的类,只需要定义一次,使用一次就可以丢弃了,此时,不应该白白定义在一个文件中。

在JavaSE/Android的事件处理中:不同的按钮点击之后,应该有不同的响应操作。首选匿名内部类。

  1. s匿名内部类本身没有构造器,但是会调用父类构造器
  2. 匿名内部类尽管没有构造器,但是还是可以在匿名类中提供一段实例初始化代码块,JVM在调用父类构造器后,会执行该段代码。
  3. 内部类处理可以继承类之外,还可以实现接口

格式:

      new 父类构造器 ([实参列表]) 或接口 ()

      {

         //匿名内部类的类体部分

      }

     注意:匿名内部类必须继承一个父类或者实现一个接口,但最多只能一个父类或实现一个接口。

        //安装USB键盘
		//创建一个IUSB的匿名实现类对象
		MotherBoard.pluginIn(new IUSB()
		{
			//匿名内部类体
			public void swapData()
			{
				System.out.println("键盘在哪里");
			}
		}	
		);

(三)枚举

187、引入枚举和枚举的模拟

需求:定义一个Employee(员工),使用一个变量restday来表示他哪一天休息(一周的哪一天)

class Employee
{
	private int restday; //一周的哪一天休息
	public int getRestday()
	{
		return restday;
	}
	public void setRestday(int restday)
	{
		this.restday = restday;
	}
}
//枚举的引入
class  EnumDemo
{
	public static void main(String[] args) 
	{
		//创建一个员工对象,并设置他哪一天休息
		Employee e = new Employee();
		e.setRestday(3); //接受int类型的值
		int restday = e.getRestday();
		if (restday == 6 || restday == 7)
		{
			System.out.println("周末休息");
		}
		else
		{
			System.out.println("周一至周五休息");
		}
	}
}

上面的设计,感觉是没有问题,但是经不起推敲:使用int类型来表示星期几存在的问题:

  1. 类型不安全,完全可以设置非[1,7]之间的数
  2. 业务含义不够明确,设置的1表示周几?周一/周日?

解决方案:专门使用一个类weekday来表示

//定义一个星期几的常量类
class Weekday
{
	public static final int MONDAY = 1;
	public static final int TUESDAY = 2;
	public static final int WEDNESDAY = 3;
	public static final int THURSDAY = 4;
	public static final int FRIDAY = 5;
	public static final int SARTUDAY = 6;
	public static final int SUNDAY = 7;
}

此时,调用代码:

//创建一个员工对象,并设置他哪一天休息
		Employee e = new Employee();
		e.setRestday(Weekday.WEDNESDAY); //周三

此时,业务含义很明确,因为Weekday.WEDNESDAY就是表示周三的意思,但是,,因为在Employee中的restday的类型是int类型,我们依然可以随意设置int类型的数据。如:e.setRestday(-13); 。所以还是没有解决数据类型不安全的问题。

解决方案:把休息日使用一个对象类型来表示,并固定该休息日的值只能是周一到周日

//定义一个星期几的常量类
class Weekday
{
	private Weekday(){} //创建一个私有化构造器,防止外界new Weekday()
	public static final Weekday MONDAY = new Weekday();
	public static final Weekday TUESDAY = new Weekday();
	public static final Weekday WEDNESDAY = new Weekday();
	public static final Weekday THURSDAY = new Weekday();
	public static final Weekday FRIDAY = new Weekday();
	public static final Weekday SARTUDAY = new Weekday();
	public static final Weekday SUNDAY = new Weekday();
}
class Employee
{
	private Weekday restday; //一周的哪一天休息
	public Weekday getRestday()
	{
		return restday;
	}
	public void setRestday(Weekday restday)
	{
		this.restday = restday;
	}
}
//枚举的引入
class  EnumDemo
{
	public static void main(String[] args) 
	{
		//创建一个员工对象,并设置他哪一天休息
		Employee e = new Employee();
		e.setRestday(Weekday.WEDNESDAY); //周三
		//-------------------------------------------
		Weekday restday = e.getRestday();
		if (restday == Weekday.SARTUDAY || restday == Weekday.SUNDAY)
		{
			System.out.println("周末休息");
		}
		else
		{
			System.out.println("周一至周五休息");
		}
	}
}

188、枚举的定义和特点以及底层分析

枚举是从java5开始,提供的一种新的数据类型,是一个特殊的类,就是多个常量对象的集合。

格式:

[修饰符] enum 类名

{

      常量A,常量B,常量C;s

}

//定义一个星期几的常量类
enum Weekday
{
	MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SARTUDAY,SUNDAY; //枚举中的MONDAY就等价于public static final Weekday MONDAY = new Weekday();
}
class Employee
{
	private Weekday restday; //一周的哪一天休息
	public Weekday getRestday()
	{
		return restday;
	}
	public void setRestday(Weekday restday)
	{
		this.restday = restday;
	}
}
//枚举的引入
class  EnumDemo1
{
	public static void main(String[] args) 
	{
		//创建一个员工对象,并设置他哪一天休息
		Employee e = new Employee();
		e.setRestday(Weekday.WEDNESDAY); //周三
		//-------------------------------------------
		Weekday restday = e.getRestday();
		if (restday == Weekday.SARTUDAY || restday == Weekday.SUNDAY)
		{
			System.out.println("周末休息");
		}
		else
		{
			System.out.println("周一至周五休息");
		}
	}
}

自定义的枚举类型,在编译(在底层)都是直接继承与java.lang.Enum类的,Enum是所有枚举的父类

枚举类的特点:

  1. 枚举的直接父类是java.lang.Enum,但是不能显示继承Enum
  2. 枚举就相当于一个类,可以定义构造方法、成员变量、普通方法和抽象方法
  3. 默认私有构造方法,即使不写访问权限也是private(假的构造器,底层没有无参数构造器)
  4. 每个实例分别用一个全局常量表示,枚举类的对象是固定的,实例个数有限,不能使用new关键字
  5. 枚举实例必须位于枚举体中的最开始部分,枚举实例列表的后面要有分号与其他成员相分隔
  6. 枚举实例后有花括号时,该实例是枚举类的匿名内部类对象(查看编译后的class文件)

189、枚举的操作细节

枚举的使用:

  1. 枚举中都是全局、公共的静态常量,可以直接使用枚举类名调用。如:Weekday day = Weekday.SARTUDAY;
  2. 因为java.lang.Enum类是所有枚举的父类,所以所有的枚举对象可以调用Enum类中的方法。 

                 String name = 枚举对象.name(); //返回枚举对象的常量名称

                 int ordinal = 枚举对象.ordinal(); //返回枚举对象的序号,从0开始

                 String str = 枚举对象.toString(); //返回枚举对象的常量名称

    3.编译器生成的枚举类的静态方法(从反编译代码中看):

                 枚举类型[] values(); // 返回当前枚举类型所有的常量,使用一个数组封装起来

                 枚举类型 valueOf(String name); //把一个指定名称的字符串,转换为当前枚举中同名的常量

     4.从java5开始出现枚举,switch也支持操作枚举类型。switch只支持int类型,支持枚举是因为底层使用的枚举对象ordinal,而ordinal的类型依然是int类型。

枚举主要用来表示事物固定的类型

//定义一个星期几的常量类
enum Weekday
{
	MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SARTUDAY,SUNDAY; //枚举中的MONDAY就等价于public static final Weekday MONDAY = new Weekday();
}
class Employee
{
	private Weekday restday; //一周的哪一天休息
	public Weekday getRestday()
	{
		return restday;
	}
	public void setRestday(Weekday restday)
	{
		this.restday = restday;
	}
}
//枚举的引入
class  EnumDemo1
{
	public static void main(String[] args) 
	{
		//创建一个员工对象,并设置他哪一天休息
		Employee e = new Employee();
		e.setRestday(Weekday.WEDNESDAY); //周三
		//-------------------------------------------
		Weekday restday = e.getRestday();
		if (restday == Weekday.SARTUDAY || restday == Weekday.SUNDAY)
		{
			System.out.println("周末休息");
		}
		else
		{
			System.out.println("周一至周五休息");
		}
		//new Weekday(); // 无法实例化枚举类型
		System.out.println(Weekday.SARTUDAY); //打印枚举
		System.out.println(Weekday.SARTUDAY.name()); //SARTUDAY  返回枚举对象的常量名称
		System.out.println(Weekday.SARTUDAY.ordinal()); //5    返回枚举对象的序号,从0开始
		System.out.println(Weekday.SARTUDAY.toString()); //SARTUDAY  返回枚举对象的常量名称
		System.out.println(Weekday.valueOf("MONDAY"));
		Weekday[] ws = Weekday.values(); // 返回当前枚举类型所有的常量,使用一个数组封装起来
		for (Weekday day :ws )
		{
			System.out.println(day);
		}
		switch (Weekday.SUNDAY)
		{
		case MONDAY : break;
		case TUESDAY : break;
		case WEDNESDAY : break;
		}
	}
}

枚举的单例模式:

在《effective java》书中提到,建议使用枚举做单例模式,很安全,即使使用反射也不能创建对象。

class ArrayUtil
{
	//1)必须在该类中,自己先创建出一个对象
	private static final ArrayUtil instance = new ArrayUtil();
	//2)私有化自身的构造器,防止外界通过构造器创建新的对象
	private ArrayUtil(){}
	//3)向外暴露一个公共的静态方法用于获取自身的对象
	public static ArrayUtil getInstance()
	{
		return instance;
	}
	//排序操作
	public void sort(int[] arr)
	{
		System.out.println("排序操作");
	}
}
//单例
class SingletionDemo 
{
	public static void main(String[] args) 
	{
        System.out.println(ArrayUtil.getInstance() == ArrayUtil.getInstance());		
        //需要做排序:不同类中 
		ArrayUtil.getInstance().sort(null);
		//需要做排序
		ArrayUtil.getInstance().sort(null);
		//需要做排序
		ArrayUtil.getInstance().sort(null);
		//需要做排序
		ArrayUtil.getInstance().sort(null);
	}
}

用枚举方式:

enum ArrayUtil
{
	INSTANCE;
	//排序操作
	public void sort(int[] arr)
	{
		System.out.println("排序操作");
	}
}
//单例
class SingletionDemo 
{
	public static void main(String[] args) 
	{
		System.out.println(ArrayUtil.INSTANCE == ArrayUtil.INSTANCE); //true
		//需要做排序:不同类中 
		ArrayUtil.INSTANCE.sort(null);
		//需要做排序
		ArrayUtil.INSTANCE.sort(null);
		//需要做排序
		ArrayUtil.INSTANCE.sort(null);
		//需要做排序
		ArrayUtil.INSTANCE.sort(null);
	}
}

190、小结

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值