Java SE 基础部分笔记

Math常用方法

Math.abs(-2.0); //2.0  —— 绝对值
Math.ceil(3.3); //4.0  向上入——ceil天花板
Math.floor(3.6);//3.0  向下入——floor地板
Math.round(5.5);//6.0  四舍五入
Math.pow(2.0,2.0); // 4.0  第一个参数的第二个参数次幂

构造方法:子类对象调用父类构造方法

构造方法的作用是初始化成员变量的。所以子类的初始化过程中,必须先执行父类的初始化动作。子类的构造方法中默认有一个 super() ,表示调用父类的构造方法,父类成员变量初始化后,才可以给子类使用。

public Fu{System.out.println("Fu");}
public Zi{System.out.prinyln("Zi");}
多态的特点:

编译期检查父类:看父类是否有指定成员,如果没有则编译报错
运行时:
1.非静态的成员方法:如果子类有重写,则运行子类重写后的方法
2.其他(静态方法,静态成员变量,非静态成员变量):都使用父类

多态的缺点:
  • 父类对象不能调用子类特有成员,如需调用,需要向下转型
多态的优点:
  • 在方法的参数上,如果定义的类型是父类类型,则可以接收任意的子类对象

接口

public interface 接口名称{
    // 抽象方法    —— 可以省略abstranct,没有方法体,供子类实现使用(继承必须重写)
    // 默认方法    —— 不可省略default,供子类调用或者子类重写(继承后可以不重写) 
    // 子类可以默认使用接口定义的默认方法,假设有100个类使用了这个接口,如果有一天接口增加了新功能,那么所有的子类都要重写,这个时候,只需要在接口写默认方法,那么所有的子类就可以直接调用了。
    // 静态方法    —— 供接口直接调用
    // 私有方法    —— 供结构中的默认方法或者静态方法调用
}
public abstract 抽象方法{
    // 抽象类中可以有任意的成员,可以没有任意成员
}
若方法名与父类重名,则优先调用父类方法。

抽象类

一个类包含抽象方法,那么这个类就必须是抽象类
子类继承父类,要么它也是抽象类,要么它必须重写父类抽象方法


日历对象

Calendar类的月份表示是0——11月 ,星期表示是1-7天,1表示的是周日


Objects 工具类

Object的equals方法容易抛出空指针异常,所以使用Objects的equals可以避免空指针异常
底层实现是:

return (a == b) || (a != null && a.equals(b));

Set和Map

Set和Map存储数据都是无序的,如果想有序存储数据,则使用他们对应的LinkedHashSet和LinkedHashMap就可以了

  • boolean containsKey()
  • boolean containsValue()

Map的key和value只能存放引用类型,不能存放基本类型(装箱) –> 集合只能存放引用类型,不能存放基本类型(自动装箱)


LinkedList:双向链表

特有功能:能在链表的两端进行操作(增删查)
    * linkedList = [a,b,c,d,e,f,g]
    * 获取d元素,list.get(4),7/2=3,d的索引是4,所以从末尾开始获取元素
    * 在底层其实本质上链表没有索引,如果想获取链表中某个指定索引位置的元素
    * 先判断索引和长度/2的值谁更大,如果索引大,则从链表的末尾开始往前进行获取元素
    * 如果长度/2的值比较大,则从链表头开始获取元素
    * 尽量不要使用普通for遍历LinkedList,效率差,用增强for

List去重

String[] strs = {"12345","67891","12347809933","98765432102","67891","12347809933"};
//直接调用方法contains
if(!list.contains(str)) list.add(str);

并发/并行

并发:理论上的同时发生,实际上CPU在多个线程种进行高速的切换,单个时刻其实只有一个线程在执行
并行:实际上的同时发生,在某个时刻,多个线程同时在执行
进程:指一个内存中运行的应用程序,每个进程都有一个独立的内存空间,一个应用程序可以运行多个进程
线程:进程内部的一个独立执行单元,一个进程可以同时并发的运行多个线程`
Runnable比Thread优点在哪:Runnable可以被多个线程共享,并且可以继承有共性的父类
字符串是在常量池中存储的


sychronized

非静态方法的同步锁对象是this
静态方法的同步锁对象是该类的字节码对象,如MyTest.class(绝对唯一)
线程的6种状态:

  • New (新建) — start方法前
  • Runnable (可运行)
  • Blocked (锁阻塞)
  • Wait (无限等待) 该方法会释放锁
  • TimeWait (计时等待)
  • Terminatesd (被终止)
    wait()方法会释放锁,notify()方法不会释放锁

线程池 ThreadPool 的使用步骤 优点:1.效率高 2.复用性高 3.节约资源

    //1. 创建线程池对象
    ExcutorService service = Excutors.newFixedThreadPool(int count); count:包含几个线程对象
    //2. 创建要执行的Runnable对象
    MyRunnable runnable = new MyRunnable();
    //3. 从线程池中获取线程对象,然后调用Runnable里面的run方法
    service.submit(runnalbe);//将runnable塞给线程池运行
    //4. 关闭线程池
    service.shutdown();

File类常用方法

构造方法:

File(String pathName)
File(File parent,String child)
File(String parent,String child)
File对象在创建的时候,需要在构造方法中声明文件的目录

  • String getAbsolutePath() 获取绝对路径 getAbsoluteFile()
  • String getPath() 获取构造路径
  • String getName()获取文件/目录名称 getParent() getParentFile
  • long length() 获取文件 注意不能直接获取文件夹的大小(只能将该文件夹下的内容大小进行相加)

  • boolean exists()此File表示的文件/目录是否实际存在 isHidden() 判断文件的隐藏属性是否为true
  • boolean isDirectory() 此File表示的是否为目录
  • boolean isFile()此File表示的是否为我文件

  • boolean createNewFile() 仅当该文件名称不存在时/父路径存在时,创建【一个】新的文件
  • boolean delete()删除由此File表示的文件或目录 — 删除目录时,目录里面为空才能被删除
  • boolean mkdir() 创建单级目录
  • boolean mkdirs() 创建多级目录,包括任何必须但不存在的父目录

  • String[] list() 返回一个String数组,表示该File目录中的所有子文件或目录
  • File[] listFiles()返回一个File数组, 表示该File目录中的所有子文件或目录

调用listFiles方法的File对象,表示的必须是实际存在的目录,否则返回null,无法进行遍历


  • boolean accept() File的过滤器,使用方法:匿名内部类,

    listFiles((new FileFilter(){
        @Override
        public boolean accept(){
                return true;
        }
    }));
    //如果返回false,则被过滤掉,如果返回true,则被留下

FileOutputStream 字节输出流

构造方法:

FileOutputStream(File file)
FileOutputStream (String path)

关联文件过程:
    1.创建流对象 
    2.判断文件是否存在  
    3. 没有,就创建,有,就清空,并和文件关联
 前提条件是,父路径必须存在,否则会抛出异常

FileOutputStream(File file,boolean append)
声明是否继续续写文件 true表示追加数据,false表示清空原有数据

  • void write(int b)写出字节,每次只能写出一个字节数据 写的是ASCII码表中的整数
  • void write (byte[] b)写出字节数组
  • void write(byte[] b,int off,int len)off开始,写入len个字节

FileInputStream 字节输入流 (若文件不存在,则会报错)

  • int read() 每次可以读取一个字节数据,提升为int类型,取到末尾返回-1
  • read(byte[] b) 每次读取b个长度的字节到数组中,返回读取的有效字节个数,取到末尾返回-1
  • read(byte[] b,int off,int len)off开始,每次读取len个有效字节数

FileReader 字符输入流 (若文件不存在,则会报错)

构造方法:

FileReader(File file)
FileReader(String name)

  • int read()从输入流读取一个字符
  • int read(char[] ch) 从输入流中读取一些字符,并存储到ch字符数组中

FileWriter 字符输出流

构造方法:

FileWriter(File file)
FileWriter(String name)

  • void flush()刷新此输出流,并强制任何缓冲的输出字符被写出,缓冲区满了会自动刷新
  • void write(int c)
  • void write(char[] chs)
  • void write(String str)
FileWriter必须关闭流才会写入文件,否则数据只是保存在缓冲区,并未保存到文件

字符流,只能操作文本文件,不能操作图片,视频等非文本文件
当我们单纯读或者写文本的时候,使用字符流,其他情况使用字节流


Properties 属性集

  • Object setProperty(String key, String value) 保存一对属性
  • String getProperty(String key) 使用此属性列表中指定的键搜索属性值
  • Set<String> stringPropertyNames() 所有键的名称的集合
  • void load(InputStream inStream) 从字节输入流中读取键值对
  • void store(OutputStream out) 将配置信息写入文件

缓冲流

缓冲流的基本原理,是在创建流对象时,会创建一个内置的默认大小的缓冲区数组[8192],通过缓冲区读写,减少系统IO 次数,从而提高读写的效率。(想要读写更快,就使用byte[] 来接收和传递)

BufferedInputStream 字节缓冲输入流

构造方法:BufferedInputStream(InputStream in)

BufferedOutputStream 字节缓冲输出流

构造方法BufferedOutputStream(OutputStream out)

BufferedReader 字符缓冲输入流

构造方法:BufferedReader(Reader in)

  • 特有方法:String readLine() 读取一行文字
BufferedWriter 字符缓冲输出流

构造方法:BufferedWriter(Writer out)

  • 特有方法:void newLine 写一行 行分隔符,由系统属性定义符号,如 \r\n\r\n

转换流

【编码转换流】把字节流转换成字符流

InputStreamReader
构造方法:

InputStreamReader(InputStream in)
InputStreamReader (InputStream in, String charset)
字节数据读取出来,读到程序中,按照你指定的编码格式,进行转换,把固定数量的字节转换成对应的字符
字节数据转换成字符数据的一个桥梁

OutputStreamWriter
构造方法:

OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out, String charset)
转出转换流,本身是一个字符流,输出的数据是字符,但是先把字符按照指定的编码,把字符转成对应的字节
字符数据通向字节的桥梁


序列化流

【序列化/反序列化】Serializable就是一个标记接口,想要序列化,就必须实现这个接口
【瞬态关键字】【transient】修饰的属性不会被序列化
serialVersionUID 固定序列化ID,可以保证反序列化的成功

ObjectOutputStream

构造方法: ObjectOutputStream(OutputStream out)

  • void writeObject(Object obj) 将指定对象写出
ObjectInputStream

构造方法:ObjectInputStream(InputStream in)

  • Object readObject() 读取一个对象

打印流

PrintStream

构造方法:PrintStream(String path) 设置打印流的文件位置
System.setOut(ps) 设置系统打印System.out.println()的流向,–>流向PrintStream创建的文本位置


网络编程Socket

Tcp特点:三次握手,安全可靠,缺点:三次握手导致的速度慢
UDP特点:不需要握手,传输速度块 缺点:不安全,并且大小有限制,64kb
该类实现【客户端】套接字,套接字指的是两台设备之间通讯的端点

构造方法:

Socket(String host, int port)创建套接字对象并将其连接到指定主机指定端口号上,如果指定地址为null,相当于指定地址为回送地址(127.0.0.1)

  • InputStream getInputStream():【接收】获取服务器返回数据的输入流对象
    * 如果此Socket具有相关联的通道,则生成InputStream的所有操作也关联该通道
    * 关闭生成的InputStream也将关闭相关的Socket
  • OutputStream getOutputStream():【发送】获取输出到服务器的输出流对象
    * 同上
  • void close():关闭此套接字
    * 一旦一个socket被关闭,它不可再使用
    * 关闭此socket也将关闭相应的InputStream和OutputStream
  • void shutdownOutput(): 禁用此套接字的输出流
    * 任何先前写出的数据将被发送,随后终止输出流
    *【传输数据,客户端必须通过该方法,通知服务端数据传输完毕,否则服务端会陷入无限写入等待】
注意事项:

在服务器回写的时候,客户端要么是关闭了输出流,要么就是调用了shutdownOutput()通知服务器已写完毕,否则服务器会一直等待客户端关闭输出流。案例:

客户端写完之后,等待服务器回写数据,但是服务器读取完数据后,在等待客户端关闭输出流或者调用shutdownOutput()方法,此刻,便陷入了无限等待


ServerSocket

这个类实现了【服务器】套接字,该对象等待通过网络的请求。

构造方法:

ServerSocket(int port)使用该构造方法在创建ServerSocket对象时,就可以将其绑定到一个指定的端口号上,参数port就是端口号

  • Socket accept():侦听并接收连接,返回一个新的Socket对象,用于和客户端实现通信。该方法会一直阻塞直到建立连接

正则表达式

x 字符 x
[abc] a、b 或 c(简单类)
[^abc] 任何字符,除了 a、b 或 c(否定)
[a-zA-Z] a 到 z 或 A 到 Z,两头的字母包括在内(范围)
.   任何字符

X?  X,一次或一次也没有
X*  X,零次或多次
X+  X,一次或多次
X{n} X,恰好 n 次
X{n,} X,至少 n 次
X{n,m} X,至少 n 次,但是不超过 m 次
boolean matches(String regex) 告知字符串是否满足正则表达式
"12345".matches("[1-9][0-9]{4,10}")   --> 第一位不为0,第二位0-9,出现4-10次  (总共5-11个数字)

Lambda的延迟执行

    public static void showLog(int level, String message){
        if(level == 1){
            System.out.println(message);
        }
    }
    public static void main(String[] args){
        String msg1 = "Hello";
        String msg2 = "World";
        String msg3 = "Java";
        // 调用showLog方法
        showLog(2,msg1+msg2+msg3);
    } 

Lambda方法引用

1.通过对象名引用成员方法:obj :: printUpperCase
2.通过类名称引用静态方法:Math:: abs
3.通过super引用成员方法:super::sayHello
4.通过this引用成员方法 :this::buyHouse  本类的非静态成员方法
5.类的构造器的引用:Person::new
6.数组的构造器的引用: int[]::new

注意事项:
被传递的方法需要能替换接口中的抽象方法
1.参数 【被传递方法】的参数类型必须是【接口中抽象方法】的类型或者其父类型
2.返回值 【被传递方法】的返回值类型必须是【接口中抽象方法】的类型或者其子类型


Lambda常用函数式接口

Supplier接口(用于获取对象数据) Supplier:供应商
  • T get()指定接口的泛型是什么类型,那么接口中的get方法就会生产什么类型的数据 如:
        private static String getString(Supplier<String> sup)
Consumer接口(用于消费对象数据) Consumer:消费者
  • void accept(T t) 消费一个指定泛型的数据 —> 如:输出t
  • default Consumer<T> andThen(Consumer<? super T> after)消费一个数据的时候,首先做一个操作,然后再做一个操作,实现组合
    若after为null,会提前抛出异常,这样做的好处就是,不需要执行Lambda里面写的代码了,节约了性能
Predicate接口(用于判断/与或非) Predicate:断言,表明
  • boolean test(T t)用于条件判断的 场景 —> 如:str.length() > 5
  • default Predicate<T> and(Pridicate<? super T> other) 条件判断就会存在与或非,and()就是将两个条件语句“并且”在一起,相当于 &&
  • default Predicate<T> or(Pridicate<? super T> other)条件判断,或 ||
  • default Predicate<T> negate() 条件判断, 非 !
Function接口(用于类型转换)
  • R apply(T t) 根据类型T的参数获取类型为R的结构—> 如:String转Integer类型
  • default <V> Function<T,V> andThen(Function<? super R,? extends V> after)将T->R->V,该方法同样用于“先做什么,再做什么”的场景,和 Consumer 中的 andThen 差不多

延迟方法:只是在拼接Lambda函数模型的方法,并不立即执行得到结果。
终结方法:根据拼好的Lambda函数模型,立即执行得到结果值的方法。
通常情况下,这些常用的函数式接口中唯一的抽象方法为终结方法,而默认方法为延迟方法。但这并不是绝对的


Stream流

Stream流是一个来自数据源的元素队列并支持聚合操作
* 元素是特定类型的对象,形成一个队列。
* 数据源流的来源。可以是集合,数组,I/O channel,产生器generator等
* 聚合操作类似SQL语句一样的操作,比如filter,map,reduce,find,match,sorted等。
和以前的Collection操作不同,Stream操作还有两个基础的特征:
* Pipelinging:中间操作都会返回流对象本身。这样多个操作可以串联成一个管道,如同流式风格(fluent style)。这样做可以对操作进行优化,比如延迟执行(laziness)和短路终结(short-circuiting)
* 内部迭代:以前对集合遍历都是通过Iterator或者For-Each的方式,显式的集合外部进行迭代,这叫做外部迭代。Stream提供了内部迭代的方式,通过访问者模式(Visitor)实现。

获取Stream流:
所有的Collection集合都可以通过stream()方法获取流
数组可以用过Stream接口的静态方法,Stream.of(int[] arr) 来获取流对象
Stream的常用功能:

 1.过滤:filter
  • Stream<T> filter(Predicate<? super T> predicate) 可以通过filter方法将一个流转换成另一个子集流
 2.统计个数:【终结方法】
  • long count() 统计流中的元素个数
 3.取用前几个
  • Stream<T> limit(long maxSize) 该方法可以对流进行截取,只取用前几个
 4.跳过前几个
  • Stream<T> skip(long n) 跳过前n个,取后面的元素,若长度大于了总长,则返回长度为0的空流
 5.映射(类型转换)
  • <R> Stream<R> map(Function<? super T,extents R> mapper) 如果需要将流中的元素映射到另一个流中,可以使用map方法
 6.组合两个流
  • static <T> Stream<T> concat(Stream<? extents T> a, Stream<? extents T> b) 如果有两个流,希望合并成为一个流,那么可以使用Stream的静态方法concat
 7.遍历【终结方法】
  • void forEach(Consumer<? super T> action)逐一处理:和for循环不同,该方法不保证元素的逐一消费动作的流中是有序执行的
 8.收集元素到集合中
  • List collect(static <T> Collector<T, A, List<T>> toList()) 将Stream流转换为List集合
  • Set collect(static <T> Collector<T, ?, Set<T>> toSet()) 将Stream流转换为Set集合
 9.收集元素到数组中
  • Object[] toArray将Stream流转换为数组
  • <A> A[] toArray(IntFunction<A[]> generator) 从外面指定泛型参数
 10.并发流,多线程操作
  • Stream parallel() 转换为并发流 –> parallel:平行的,同时发生的
    Collection的方法也可以直接得到并发流,parallelStream();

只有在执行终止方法的时候,才会执行之前的过滤、映射、跳过等操作,–>得益于Lambda的延迟执行
每个流对象都只能处理一次,处理完毕之后产生新的流对象


Junit测试

Assert类 —— assert : 断言
Assert.assertEquals(期望的结果,真实的结果)

@Befor :初始化方法,用于资源申请,所有测试方法在执行之前都会先执行该方法
@After :释放资源方法,在所有测试方法执行完成后,都会自动执行该方法


反射

Java代码,在计算机中经历的三个阶段

    1. Source源代码阶段  ---> 此时类还在电脑的硬盘中
    2. Class类对象阶段   ---> 此时类已经被加载到了内存中
    3. Runtime运行时阶段 ---> 此时类已经被new出来了
* 框架:半成品软件。可以在框架的基础上进行软件开发,简化编码
* 反射:将类的各个组成部分封装为其他对象,这就是反射机制
    * 好处:
        1. 可以在程序过程中,操作这些对象。
        2. 可以解耦,提高程序的可扩展性。

获取Class字节码文件的三种方式
1. 第一阶段:Class.forName("全类名") 将字节码文件加载进内存,返回Class对象
* 多用于配置文件,将类名定义在配置文件中。读取文件,加载类
2. 第二阶段:类名.class 通过类名的属性class获取
* 多用于参数的传递
3. 第三阶段:对象.getClass() 返回一个Class对象
* 多用于对象的获取字节码的方式
* 结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个


Class字节码文件对象功能

1.获取功能

  1. 获取类加载器
    ClassLoader getClassLoader 返回加载该字节码文件的类加载器
    ClassLoader的方法
    URL getResource(String name) 获取指定资源的路径
    InputStream getResourceAsStream(String name) 获取指定资源对应的字节流

  2. 获取成员变量们
    Field[] getFields():获取所有的public修饰的成员变量
    Field getFile(String name) 获取指定名称的public修饰的成员变量
    Field[] getDeclaredFields() 获取所有的成员变量,不考虑修饰符
    Field getDeclartedField() 获取指定名称的成员变量,不考虑修饰符

  3. 获取构造方法们
    Constructor<T>[] getConstructors()获取所有的public修饰的构造方法
    Constructor<T> getConstructor(类<?>...parameterTypes) 如:int.class,String.class
    Constructor<T>[] getDeclaredConstructors()
    Constructor<T> getDeclaredConstructor()
  4. 获取成员方法们
    Method[] getMethods() –> 还会获得Object里定义的方法
    Method getMethod(String methodName, 类<?>... parameterTypes)
    Method[] getDeclaredMethods()
    Method getDeclaredMethod(String methodName, 类<?>... parameterTypes)
  5. 获取类名
    String getName()获取该字节码文件的类名称(非全类名)

2.Field:成员变量
1. 操作成员变量

获取值
  • get(Object obj)
设置值
  • set(Object obj, Object value)
忽略访问权限修饰符的安全检查(若操作private数据,会有报错)
  • setAccessible(true) 暴力反射

3.Constructor:构造方法

创建对象
  • T newInstance(Object... initargs) 通过构造器新建一个对象,括号内传入构造器的参数

4.Method:成员方法

执行方法 invoke:调用、激活
  • Object invoke(Object obj, Object... args) 第一个参数:执行对象。 第二个参数:方法参数
  • String getName() 获取方法名(非全名,如public void String get())
    类加载器:获取当前类的类加载器,类加载器可以获取src目录下的文件

JavaDoc注解

/**
 * @author 作者
 * @version 1.0
 * @since 1.5
 */
public class JavaDoc{
   /**
    * 加法运算
    * @param a 加数
    * @param b 被加数
    * @return 返回 a+b 的和
    */
   public int add(int a, int b){
        return a + b;
   }

   @Override :检测被该注解标注的方法是否是继承自父类(接口)的
   public String toString(){
        ...
   }

   @Deprecated : 该注解标注的内容,表示已过时
   @SuppressWarnings("all") :压制警告,一般传递参数all
   public void show1(){
        ...
   }
}

自定义注解

注解本身就是一个接口,继承Annotation接口,注解中的抽象方法叫做属性

1.格式:
    public @interface 注解名称{属性列表}
        1. 属性列表:属性返回值有下列取值
            * 基本数据类型
            * String
            * 枚举
            * 注解
            * 以上类型数组
        2. 定义了属性,在使用时需要给属性赋值
            * 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值
            * 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可
            * 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略

元注解:用于描述注解的注解

  • @Target:描述注解能够作用的位置 Target:目标、靶子
    * ElementType取值:
    * TYPE:可以作用于类上
    * METHOD:可以作用于方法上
    * FIELD:可以作用于成员变量上
  • @Retention:描述注解被保留的阶段 Retention:保留、维持
    * RetentionPolicy取值:
    * RUNTIME:当前被描述的注解,会保留到class字节码文件中,并被JVM读取到(最常用)
    * CLASS:当前被描述的注解,会保留到class字节码文件中,不会被JVM读取
    * SOURCE:当前被描述的注解,字节码文件都不会存在该注解
  • @Documented:描述注解是否被抽取到api文档中
  • @Inherited:描述注解是否被子类继承 Inherited:继承、遗产 extend:扩展

在程序使用(解析)注解:获取注解中定义的属性值

    1. 获取注解定义的位置的对象  (Class对象, Method对象, Field对象)
    2. 获取指定的注解
                // getAnnotation(Class cls)
                //其实就是在内存中生成了一个该注解接口的子类实现对象
                public class ProImpl implements Pro{
                    public String className(){
                        return "cn.itcast.annotation.Demo1";
                    }
                    public String methodName(){
                        return "show";
                    }
                }
    3. 调用注解中的抽象方法获取配置注解的属性值
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值