java语言基础

菜鸟工具,没事的时候可以玩玩

变量运算

赋值:

int a, b, c;         // 声明三个int型整数:a、 b、c
int d = 3, e = 4, f = 5; // 声明三个整数并赋予初值

算数运算符:

在这里插入图片描述
m=2a++ :先执行表达式赋值,在执行++ 也就是m=20,a=11
m=2
++a:先执行++,在计算表达式赋值,也就是m=22, a=11

关系运算符:

在这里插入图片描述

位运算符:

A = 0011 1100 //60
B = 0000 1101  //13

在这里插入图片描述

逻辑运算符:

在这里插入图片描述

赋值运算符:

在这里插入图片描述

条件运算符:

条件运算符也被称为三元运算符。该运算符有3个操作数,并且需要判断布尔表达式的值。该运算符的主要是决定哪个值应该赋值给变量

variable x = (expression) ? value if true : value if false

// 如果 a 等于 1 成立,则设置 b 为 20,否则为 30
b = (a == 1) ? 20 : 30;

instanceof 运算符:

该运算符用于操作对象实例,检查该对象是否是一个特定类型(类类型或接口类型)

( Object reference variable ) instanceof  (class/interface type)

String name = "James";
boolean result = name instanceof String; // 由于 name 是 String 类型,所以返回真

运算符优先级

在这里插入图片描述

语句

while循环

while( 布尔表达式 ) {
  //循环内容,只要布尔表达式为 true,循环就会一直执行下去
}

do…while 循环

do {
       //代码语句,do…while 循环和 while 循环相似,不同的是,do…while 循环至少会执行一次
}while(布尔表达式);

for循环

//最先执行初始化步骤。可以声明一种类型,但可初始化一个或多个循环控制变量,也可以是空语句
for(初始化; 布尔表达式; 更新) {
    //代码语句
}

//用于数组的循环
for(声明语句 : 表达式)
{
   //代码句子
   //声明语句:声明新的局部变量,该变量的类型必须和数组元素的类型匹配
}
for( String name : names ) {
         System.out.print( name );
         System.out.print(",");
      }

break关键字

break 主要用在循环语句或者 switch 语句中,用来跳出整个语句块,break 跳出最里层的循环,并且继续执行该循环下面的语句

continue关键字

continue 适用于任何循环控制结构中。作用是让程序立刻跳转到下一次循环的迭代。在 for 循环中,continue 语句使程序立即跳转到更新语句。在 while 或者 do…while 循环中,程序立即跳转到布尔表达式的判断语句。

条件语句

//if语句
if(布尔表达式)
{
   //如果布尔表达式为true将执行的语句
}

//if else语句
if(布尔表达式){
   //如果布尔表达式的值为true
}else{
   //如果布尔表达式的值为false
}

//if...else if...else 语句
if(布尔表达式 1){
   //如果布尔表达式 1的值为true执行代码
}else if(布尔表达式 2){
   //如果布尔表达式 2的值为true执行代码
}else if(布尔表达式 3){
   //如果布尔表达式 3的值为true执行代码
}else {
   //如果以上布尔表达式都不为true执行代码
}

switch case 语句

switch(expression){
    case value :
       //语句
       break; //可选
    case value :
       //语句
       break; //可选
    //你可以有任意数量的case语句
    default : //可选
       //语句
}

如果当前匹配成功的 case 语句块没有 break 语句,则从当前 case 开始,后续所有 case 的值都会输出,如果后续的 case 语句块有 break 语句则会跳出判断
在这里插入图片描述

java常用的类

numberle类

在实际开发过程中,我们经常会遇到需要使用对象,而不是内置数据类型的情形。为了解决这个问题,Java 语言为每一个内置数据类型提供了对应的包装类,所有的包装类(Integer、Long、Byte、Double、Float、Short)都是抽象类 Number 的子类
在这里插入图片描述

Integer x = 5; //当 x 被赋为整型值时,由于x是一个对象,所以编译器要对x进行装箱
 x =  x + 10;  //然后,为了使x能进行加运算,所以要对x进行拆箱

Math类

Java 的 Math 包含了用于执行基本数学运算的属性和方法,如初等指数、对数、平方根和三角函数,Math 的方法都被定义为 static 形式,通过 Math 类可以在主函数中直接调用

一些常用的方法

Math.sin(Math.PI/2) //正弦值  1.0
Math.asin(Math.PI/2) //反正弦值  
Math.cos(0)  //余弦值  1.0
Math.acos(0)  //反余弦值 
Math.tan(Math.PI/3)  //正切值  1.7320508075688767
Math.atan(1)   //反正切值  0.7853981633974483
Math.atan2(45.0, 30.0)  //atan2() 方法用于将矩形坐标 (x, y) 转换成极坐标 (r, theta),返回所得角 theta。
//该方法通过计算 y/x 的反正切值来计算相角 theta,范围为从 -pi 到 pi。 0.982793723247329
Math.toDegrees(Math.PI/2) //角度值 90.0
Math.toRadians(30.0)  //转变成弧度值0.5235987755982988

//--------------------------------------Number类才能用-----------------------------------
//numbei类= int, float, long, double, short, byte
//转换数据类型
Double score=4.0;
int m=score.intValue();//byteValue doubleValue floatValue longValue shortValue intValue

//该方法用于两个相同数据类型的比较,两个不同类型的数据不能用此方法来比较
Integer x = 5;
System.out.println(x.compareTo(3)); //相同返回0  x<3返回-1  x>3返回1
System.out.println(x.equals(y));  //y是任何对象,参数类型与数值都相等返回 True,否则返回 False

//返回给定参数的原生 Number 对象值  
//三种用法:valueOf(int i)   valueOf(String s)    valueOf(String s, int radix)
Integer x =Integer.valueOf(9); //9
Double c = Double.valueOf(5); //5.0
Float a = Float.valueOf("80");  //80.0            
Integer b = Integer.valueOf("444",16);   // 使用 16 进制 1092
String m=String.valueOf(12)

//返回整数值
//两种用法 parseInt(String s)  parseInt(String s, int radix)
int x =Integer.parseInt("9"); //9
double c = Double.parseDouble("5");  //5.0
int b = Integer.parseInt("444",16);  //1092

//转化为string类型输出
Integer x = 5;
System.out.println(x.toString());  
System.out.println(Integer.toString(12)); 

Math.abs(a);  //绝对值
Math.ceil(d);  //向上取整
Math.floor(f);  //向下取整
Math.rint(d);  //取最接近的整数,0.5算0
Math.round(d);  //四舍五入,即将原来的数字加上 0.5 后再向下取整
Math.min(a, b);  //取两个数中最小的
Math.max(a, b);  //取两个数中最大的
Math.exp(x);  //返回自然数底数e的x次方
Math.log(x);  //返回参数的自然数底数e的对数值
Math.pow(x, y);  //x的y次方
Math.sqrt(x);  //x的算术平方根
Math.random()  //返回一个随机数,随机数范围为[0.0,1.0)   0.0 =< Math.random < 1.0  

Character 类

Java语言为内置数据类型char提供了包装类Character类

char ch = 'a'; 
// Unicode 字符表示形式
char uniChar = '\u039A'; 
// 字符数组
char[] charArray ={ 'a', 'b', 'c', 'd', 'e' };

//使用Character的构造方法创建一个Character类对象
Character ch = new Character('a');

//-----------------------------Character 类用于对单个字符进行操作-------------------------
//常用的函数
Character.isLetter('c') //判断指定字符是否为字母,是则返回 true;否则返回 false;  true
Character.isDigit('c')  //判断指定字符是否为数字,是返回 true;否则返回 false; flase
Character.isWhitespace(' ') //用于判断指定字符是否为空白字符,空白符包含:空格、tab 键、换行符
Character.isUpperCase('C')  //判断指定字符是否为大写字母
Character.isLowerCase('c')   //判断指定字符是否为小写字母
Character.toUpperCase('a')  //将小写字符转换为大写
Character.toString('a')   //返回一个表示指定 char 值的 String 对象

String类

String 类是不可改变的,所以你一旦创建了 String 对象,那它的值就无法改变了
在这里插入图片描述

 //这些方法提供不同的参数来初始化字符串,比如提供一个字符数组参数
char[] helloArray = { 'r', 'u', 'n', 'o', 'o', 'b'};
String helloString = new String(helloArray); 

String site = "www.runoob.com";
int len = site.length(); //返回字符串对象包含的字符数 14 转义符不算
String s="我的名字是 ".concat("Runoob"); //连接字符串
String s="Hello," + " runoob" + "!"    //连接字符串
System.out.printf("浮点型变量的值为 " +
                  "%f, 整型变量的值为 " +
                  " %d, 字符串变量的值为 " +
                  "is %s", floatVar, intVar, stringVar); 

String fs;
fs = String.format("浮点型变量的值为 " +
                   "%f, 整型变量的值为 " +
                   " %d, 字符串变量的值为 " +
                   " %s", floatVar, intVar, stringVar);

//常用的方法
String s = "www.runoob.com";
char result = s.charAt(6);  //返回指定索引处的字符 n 
str1.compareTo( str2 )   //1字符串与对象进行比较(Object o)  2按字典顺序比较两个字符串
//参数字符串等于此字符串,则返回值 0 
//此字符串小于字符串参数,则返回一个小于 0 的值 
//此字符串大于字符串参数,则返回一个大于 0 的值
//对应位上字符不同,结束并且返回ASCII码差值,两个字符串不一样长,可对应字符又完全一样,返回长度差值

StringBuffer 和 StringBuilder 类

对字符串进行修改的时候,需要使用 StringBuffer 和 StringBuilder 类,和 String 类不同的是,StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象(对 StringBuffer 对象本身进行操作),StringBuilder 相较于 StringBuffer 有速度优势,所以多数情况下建议使用 StringBuilder 类
在这里插入图片描述

public class RunoobTest{
    public static void main(String args[]){
        StringBuilder sb = new StringBuilder(10); //申请一个10位的StringBuilder数组
        sb.append("Runoob..");   //添加字符串
        System.out.println(sb);  
        sb.append("!");
        System.out.println(sb); 
        sb.insert(8, "Java");  //在sb[8:12]插入4位
        System.out.println(sb); 
        sb.delete(5,8);   //删除sb[5:8]
        System.out.println(sb);  
    }
}

在这里插入图片描述

StringBuilder builder=new StringBuilder("hello,world");
String s="i,love,you";
builder.append("!");  //hello,world!
builder.append(s,0,6); //添加s[0:6]  hello,world!i,love
builder.capacity();  //返回当前的容量  27
builder.length();   //返回当前长度  18
builder.charAt(4);  //返回当前位置的字符 0
builder.delete(10, 14);  //删除builder[10:14]  hello,worllove
String sub=builder.substring(0, 10); //返回子序列 hello,worl		

更多函数参考下面:
StringBuilder类
StringBuffer类

数组

double[] myList;    // 首选的方法
double myList[];    // 效果相同,但不是首选方法
String[][] str = new String[3][4];  .//多维数据


double[] myList = new double[size];
dataType[] arrayRefVar = {value0, value1, ..., valuek};
double[] myList = {1.9, 2.9, 3.4, 3.5};

// For-Each 循环或者加强型循环,它能在不使用下标的情况下遍历数组
for (double element: myList) {
         System.out.println(element);
      }

日期时间

java.util 包提供了 Date 类来封装当前的日期和时间。 Date 类提供两个构造函数来实例化 Date 对象

Date date = new Date();  //使用当前日期和时间来初始化对象
Date date = new Date(long millisec)   //接收一个参数,该参数是从 1970 年 1 月 1 日起的毫秒数
date.toString() //显示日期和时间Tue May 24 21:31:58 CST 2022 2022/5/24的9.31分58秒,CST表示美国中部时间

//日期赋值
SimpleDateFormat dateformat = new SimpleDateFormat("yyyy-MM-dd");
Date date = dateformat.parse("2016-6-19");
System.out.println(dateformat.format(date));  //2016-06-19

//SimpleDateFormat 允许你选择任何用户自定义日期时间格式来运行
Date dNow = new Date( );
SimpleDateFormat ft = new SimpleDateFormat ("yyyy-MM-dd hh:mm:ss");
System.out.println("当前时间为: " + ft.format(dNow)); //当前时间为: 2018-09-06 10:16:34

//使用printf格式化日期
System.out.printf("年-月-日格式:%tF%n",date);  //年-月-日格式:2012-09-10  
Thread.sleep(1000*3); //线程休眠3秒,当前线程进入停滞状态,让出CPU的使用

在这里插入图片描述

//使用Calendar 类设置和获取日期数据的特定部分,比如说小时,日,或者分钟,在日期的这些部分加上或者减去值
Calendar c1 = Calendar.getInstance();//默认是当前日期,创建一个代表系统当前日期的Calendar对象
c1.set(2009, 6 , 12); //2009年6月12日

c1.set(Calendar.DATE,10);  //public void set(int field,int value) 只设定某个字段的值
int hour = c1.get(Calendar.HOUR_OF_DAY); //获得小时

在这里插入图片描述

正则表达式

正则表达式定义了字符串的模式,可以用来搜索、编辑或处理文本,并不仅限于某一种语言,但是在每种语言中有细微的差别
在这里插入图片描述
java.util.regex 包主要包括以下三个类:

Pattern 类:pattern 对象是一个正则表达式的编译表示。Pattern 类没有公共构造方法。要创建一个 Pattern 对象,你必须首先调用其公共静态编译方法,它返回一个 Pattern 对象。该方法接受一个正则表达式作为它的第一个参数。

Matcher 类: Matcher 对象是对输入字符串进行解释和匹配操作的引擎。与Pattern 类一样,Matcher 也没有公共构造方法。你需要调用 Pattern 对象的 matcher 方法来获得一个 Matcher 对象。

PatternSyntaxException: PatternSyntaxException 是一个非强制异常类,它表示一个正则表达式模式中的语法错误

String line = "This order was placed for QT3000! OK?";
String pattern = "(\\D*)(\\d+)(.*)";

boolean isMatch = Pattern.matches(pattern, content);
System.out.println("字符串中是否包含了 'runoob' 子字符串? " + isMatch); //true

// 创建 Pattern 对象
Pattern r = Pattern.compile(pattern);
// 现在创建 matcher 对象
 Matcher m = r.matcher(line);
 //调用Matcher的方法

语法

在其他语言中,\\ 表示:我想要在正则表达式中插入一个普通的(字面上的)反斜杠,请不要给它任何特殊的意义
在 Java 中,\\ 表示:我要插入一个正则表达式的反斜线,所以其后的字符具有特殊的意义

System.out.print("\\");    // 输出为 \
System.out.print("\\\\");  // 输出为 \\

在这里插入图片描述

start 和 end 方法


import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
 //对单词 "cat" 出现在输入字符串中出现次数进行计数
public class RegexMatches
{
    private static final String REGEX = "\\bcat\\b";
    private static final String INPUT =
                                    "cat cat cat cattie cat";
 
    public static void main( String[] args ){
       Pattern p = Pattern.compile(REGEX);
       Matcher m = p.matcher(INPUT); // 获取 matcher 对象
       int count = 0;
 
       while(m.find()) {  //查找与该模式匹配的输入序列的下一个子序列 boolean值
         count++;
         System.out.println("Match number "+count);
         System.out.println("start(): "+m.start()); //所捕获的子序列的初始索引
         System.out.println("end(): "+m.end());  所捕获的子序列的结束索引+1
      }
   }
}

matches 和 lookingAt 方法


import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
public class RegexMatches
{
    private static final String REGEX = "foo";
    private static final String INPUT = "fooooooooooooooooo";
    private static final String INPUT2 = "ooooofoooooooooooo";
    private static Pattern pattern;
    private static Matcher matcher;
    private static Matcher matcher2;
 
 //matches 要求整个序列都匹配,而lookingAt 不要求,但是需要从第一个字符开始匹配
    public static void main( String[] args ){
       pattern = Pattern.compile(REGEX);
       matcher = pattern.matcher(INPUT);
       matcher2 = pattern.matcher(INPUT2);
       System.out.println("lookingAt(): "+matcher.lookingAt()); //true
       System.out.println("matches(): "+matcher.matches());//false
       System.out.println("lookingAt(): "+matcher2.lookingAt());//false
   }
}

replaceFirst 和 replaceAll 方法


import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
 //替换匹配正则表达式的文本。不同的是,replaceFirst 替换首次匹配,replaceAll 替换所有匹配
public class RegexMatches
{
    private static String REGEX = "dog";
    private static String INPUT = "The dog says meow. " +
                                    "All dogs say meow.";
    private static String REPLACE = "cat";
 
    public static void main(String[] args) {
       Pattern p = Pattern.compile(REGEX);
       // get a matcher object
       Matcher m = p.matcher(INPUT); 
       INPUT = m.replaceAll(REPLACE);
       System.out.println(INPUT); //The cat says meow. All cats say meow.
   }
}

appendReplacement 和 appendTail 方法


import java.util.regex.Matcher;
import java.util.regex.Pattern;
 
 //Matcher 类也提供了appendReplacement 和 appendTail 方法用于文本替换,和上面两个方法功能一模一样
public class RegexMatches
{
   private static String REGEX = "a*b";
   private static String INPUT = "aabfooaabfooabfoobkkk";
   private static String REPLACE = "-";
   public static void main(String[] args) {
      Pattern p = Pattern.compile(REGEX);
      // 获取 matcher 对象
      Matcher m = p.matcher(INPUT);
      StringBuffer sb = new StringBuffer();
      while(m.find()){
         m.appendReplacement(sb,REPLACE);
      }
      m.appendTail(sb);
      System.out.println(sb.toString());  //-foo-foo-foo-kkk
   }
}

PatternSyntaxException 类的方法

在这里插入图片描述

java方法

方法的定义

修饰符 返回值类型 方法名(参数类型 参数名){
    ...
    方法体
    ...
    return 返回值;
}

在这里插入图片描述

方法的调用

值传递:不会改变传入的值的值
引用传递:传递的是该对象地址的,一般java中实例(包装)对象的传递是引用传递,引用类型没有使用改变自身方法的方法值不会改变,使用就会改变列入append
可变参数:在方法声明中,在指定参数类型后加一个省略号(…),public static void printMax( double... numbers),一个方法中只能指定一个可变参数,它必须是方法的最后一个参数。任何普通的参数必须在它之前声明

// 调用可变参数的方法
printMax(34, 3, 3, 2, 56.5);
printMax(new double[]{1, 2, 3});

命令行参数

public class CommandLine {
   public static void main(String[] args){ 
      for(int i=0; i<args.length; i++){
         System.out.println("args[" + i + "]: " + args[i]);
      }
   }
}

在这里插入图片描述

finalize() 方法

在对象被垃圾收集器析构(回收)之前调用,用来清除回收对象


public class FinalizationDemo {  
  public static void main(String[] args) {  
    Cake c1 = new Cake(1);  
    Cake c2 = new Cake(2);  
    Cake c3 = new Cake(3);  
      
    c2 = c3 = null;  
    System.gc(); //调用Java垃圾收集器
  }  
}  
 
class Cake extends Object {  
  private int id;  
  public Cake(int id) {  
    this.id = id;  
    System.out.println("Cake Object " + id + "is created");  
  }  
    
  protected void finalize() throws java.lang.Throwable {  
    super.finalize();  
    System.out.println("Cake Object " + id + "is disposed");  
  }  
}

在这里插入图片描述

Java 流(Stream)、文件(File)和IO

一个流可以理解为一个数据的序列。输入流表示从一个源读取数据输出流表示向一个目标写数据
Java Scanner 类 ,可以通过 Scanner 类来获取用户的输入,具体用法参考java se 包官网

//BufferedReader 对象创建后,我们便可以使用 read() 方法从控制台读取一个字符,或者用 readLine() 方法读取一个字符串
BufferedReader br = new BufferedReader(new  InputStreamReader(System.in));

//使用 BufferedReader 在控制台读取字符
 
import java.io.*;
 
public class BRRead {
    public static void main(String[] args) throws IOException {
        char c;
        // 使用 System.in 创建 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("输入字符, 按下 'q' 键退出。");
        // 读取字符
        do {
            c = (char) br.read();
            System.out.println(c);
        } while (c != 'q');
    }
}

//-----------------------------------------------------------------------------------------
//使用 BufferedReader 在控制台读取字符串
import java.io.*;
 
public class BRReadLines {
    public static void main(String[] args) throws IOException {
        // 使用 System.in 创建 BufferedReader
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String str;
        System.out.println("Enter lines of text.");
        System.out.println("Enter 'end' to quit.");
        do {
            str = br.readLine();
            System.out.println(str);
        } while (!str.equals("end"));
    }
}

//PrintStream 定义 write() 的最简单格式  void write(int byteval)
//write() 方法不经常使用,因为 print() 和 println() 方法用起来更为方便
int b;
b = 'A';
System.out.write(b);

读取文件

输入流和输出流的类层次图:
在这里插入图片描述
示列代码:

//OutputStream和InputStream一样
//创建方法一
OutputStream f = new FileOutputStream("C:/java/hello")
//创建方法二
File f = new File("C:/java/hello");
OutputStream fOut = new FileOutputStream(f);



import java.io.*;
 
public class fileStreamTest {
    public static void main(String[] args) {
        try {
            byte[] bWrite = { 11, 21, 3, 40, 5 };
            OutputStream os = new FileOutputStream("test.txt");
            //也可以os.write(bWrite) 写入数组
            for (int x = 0; x < bWrite.length; x++) {
                os.write(bWrite[x]); //写入单个字节
            }
            os.close();
 
            InputStream is = new FileInputStream("test.txt");
            int size = is.available();
 
            for (int i = 0; i < size; i++) {
                System.out.print((char) is.read() + "  ");
            }
            is.close(); //关闭此文件流并释放与此流有关的所有系统资源
        } catch (IOException e) {
            System.out.print("Exception");
        }
    }
}

//-----------------------------------------------------------
//文件名 :fileStreamTest2.java
import java.io.*;
 
public class fileStreamTest2 {
    public static void main(String[] args) throws IOException {
 
        File f = new File("a.txt");
        FileOutputStream fop = new FileOutputStream(f);
        // 构建FileOutputStream对象,文件不存在会自动新建
 
        OutputStreamWriter writer = new OutputStreamWriter(fop, "UTF-8");
        // 构建OutputStreamWriter对象,参数可以指定编码,默认为操作系统默认编码,windows上是gbk
 
        writer.append("中文输入");
        // 写入到缓冲区
 
        writer.append("\r\n");
        // 换行
 
        writer.append("English");
        // 刷新缓存冲,写入到文件,如果下面已经没有写入的内容了,直接close也会写入
 
        writer.close();
        // 关闭写入流,同时会把缓冲区内容写入文件,所以上面的注释掉
 
        fop.close();
        // 关闭输出流,释放系统资源
 
        FileInputStream fip = new FileInputStream(f);
        // 构建FileInputStream对象
 
        InputStreamReader reader = new InputStreamReader(fip, "UTF-8");
        // 构建InputStreamReader对象,编码与写入相同
 
        StringBuffer sb = new StringBuffer();
        while (reader.ready()) {
            sb.append((char) reader.read()); //每行的数据
            // 转成char加到StringBuffer对象中
        }
        System.out.println(sb.toString());
        reader.close();
        // 关闭读取流
 
        fip.close();
        // 关闭输入流,释放系统资源
 
    }
}

删除目录或文件

当删除某一目录时,必须保证该目录下没有其他文件才能正确删除,否则将删除失败


import java.io.File;
 
public class DeleteFileDemo {
    public static void main(String[] args) {
        // 这里修改为自己的测试目录
        File folder = new File("/tmp/java/");
        deleteFolder(folder);
    }
 
    // 删除文件及目录
    public static void deleteFolder(File folder) {
        File[] files = folder.listFiles();
        if (files != null) {
            for (File f : files) {
                if (f.isDirectory()) {
                    deleteFolder(f);
                } else {
                    f.delete();
                }
            }
        }
        folder.delete();
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值