所使用的JDK版本为Open JDK 11.0.20,不保证所有的内容在高版本的JDK和旧版的JDK同样适用。

快速入门

import java.util.Scanner;

public class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        System.out.println("Hello, Java!");
        System.out.print("请输入你的名字: ");

        String name = scanner.nextLine();
        System.out.println("你好, " + name + "! 欢迎学习 Java!");

        System.out.print("请输入两个整数 (用空格分隔): ");
        int a = scanner.nextInt();
        int b = scanner.nextInt();
        int sum = a + b;
        System.out.println("它们的和是: " + sum);

        scanner.close();
    }
}

将上述代码保存到Main.java中,打开控制台,输入javac Main.javajava Main,就能看到输出的结果。

注释

单行注释://

// 这是一行注释

多行注释:/* .. */

/* 
	这是多行注释
*/

注释不会被执行,在用编译为class字节码文件后就会被移除。

注意事项:

Java 解析 .java 文件时,会先处理Unicode 转义字符,然后再进行词法分析。如果在单行注释 // 里放 \u000A(换行符),会导致下一行代码“恢复可执行”。

public class Demo {
    public static void main(String[] args) {
        // System.out.println("这行被注释了"); \u000A System.out.println("但这行仍然执行!");
    }
}

最终导致 System.out.println("但这行仍然执行!"); 仍然会被执行。

其它的,比如多行注释的*/对应的unicode码,提前结束多行注释。

标识符和命名规范

标识符

标识符是用于命名变量、方法、类、接口等的名称。Java 标识符的规则如下:

  • 组成:字母(A-Z, a-z)、数字(0-9)、下划线(_)、美元符号($)。
  • 开头:必须以字母、下划线或美元符号开头,不能以数字开头。
  • 区分大小写myVarmyvar 是不同的标识符。
  • 长度:无限制,但应保持简洁。
  • 关键字:不能使用 Java 关键字(如 class, public 等)。

Java命名规范

Java 遵循驼峰命名法(CamelCase),具体规范如下:

  • 类名:大驼峰法,每个单词首字母大写。
    • 示例:MyClass, StudentRecord
  • 方法名:小驼峰法,首字母小写,后续单词首字母大写。
    • 示例:calculateSum(), getUserName()
  • 变量名:小驼峰法,与方法名相同。
    • 示例:totalAmount, userName
  • 常量名:全大写,单词间用下划线分隔。
    • 示例:MAX_VALUE, PI
  • 包名:全小写,单词间用点号分隔。
    • 示例:com.example.myproject
  • 接口名:与类名相同,使用大驼峰法。
    • 示例:Runnable, Serializable

变量

数据类型

基本数据类型:

  • 整形:byteshortintlong
  • 浮点型floatdouble
  • 布尔型bool
  • 字符型char

引用数据类型

  • 接口
  • 数组

基本数据类型保存的是值,引用数据类型保存的是地址。

基本数据类型在把一个变量赋值给另一个变量时,传递的是值;引用数据类型传递的是地址。

System.out.println(args)中,如果是System.out.println("" + args),出现了字符串,则+表示拼接;如果没有出现字符串,则是数值相加。

public class Main {
    public static void main(String[] args) {
        int age = 18;
        System.out.println("age:" + age); // -->输出age:18
        System.out.println(age + 2); // -->输出20
    }
}

变量的使用

所有的变量在使用时都包含两部分:声明和初始化。声明不会为变量分配内存,只有在初始化后才会。

声明的语法如下:

数据类型 变量名;
int age;
String name;
char[] s;

初始化的语法如下:

变量名 = xxXXX;
age = 12;
name = "小明";
s = new char[]{'a', 'b', 'c'};

也可以声明的同时直接初始化:

数据类型 变量名 = xxXXX;
int age = 12;
String name = "小明";
char[] s = new char[]{'a', 'b', 'c'};

基本数据类型

整形

整形所占大小和表示的范围:

类型 占用存储空间 范围
byte 1 字节 −27 到 27 - 1
short 2 字节 −216 到 216 - 1
int 4 字节 −232 到 232 - 1
long 8 字节 −264 到 264 - 1

Java和C语言不同,具有固定的占用存储空间。

整形的使用

public class Main {
    public static void main(String[] args) {
        byte a = 1;
        short b = 3;
        int age = 18;
        long d = 100L;
    }
}

java默认使用int类型,long类型必需在后面加I或L。

浮点型

浮点型所占大小和表示的范围:

类型 占用存储空间 范围
float 4 字节 ±2±126
double 8 字节 ±2±1022

表示的范围只是大概的范围,并非范围中的每个数都能被表示,这和浮点数的表示有关。

浮点数的使用

public class Main {
    public static void main(String[] args) {
        float pi = 3.1415f;
        double source = 89.5;
    }
}

java默认使用double类型,float类型必需在后面加f或F。

字符型

字符型所占大小和表示的范围:

类型 占用存储空间 范围
char 2字节 −216 到 216 - 1

字符型的使用

public class Main {
    public static void main(String[] args) {
        char ch = 'A';
        char ch1 = '韩';
        char ch2 = '你';
        System.out.println(ch); 
        System.out.println(ch1);
        System.out.println(ch2);
        // A
        // 韩
        // 你
    }
}

字符型被定义的时候必需使用'',不能是"";String类型必须是"",不能是''。

字符型的本质是一个数,是字符对应的unicode码,在定义的时候也可以通过数字定义,输出对应的字符,也可以进行运算,进行运算时,被当作int类型。

public class Main {
    public static void main(String[] args) {
        char ch = 'c';
        System.out.println((int) ch);
        // 输出99,即c对于的unicode码
        char ch1 = 99;
        System.out.println(ch1);
        // 输出c
        System.out.println(ch + 1);
        // 输出100
    }
}

布尔类型

布尔类型的使用

public class Main {
    public static void main(String[] args) {
        boolean bool = true;
        if (bool) {
            System.out.println("bool if true");
        }
        bool = false;
        if (!bool) {
            System.out.println("bool is false");
        }
    }
    // 输出bool is true
    // 输出bool is false
}

Java中的布尔类型不能转换成整形,也不能从1或0转换成布尔型

类型转换

当Java进行赋值或运算时,范围小的类型会自动转换成范围大的类型。当把范围大的类型赋值给范围小的类型的时候,就会报错。

byte-->short-->int-->long-->float-->double
    
char--> int

注意事项:

  • char不会自动转换成byte和short类型,byte和short类型也不会自动转换成char类型。
byte ch = 99;
char ch1 = ch;
// 会报错
  • byte、short和char类型可以进行运算,在运算时会先转换成int类型。

  • boolean类型不参与基本类型之间的转换。

  • 表达式的结果会自动提升为操作数中的最大类型。

  • char类型可以通过数字赋值。

对于范围大的类型赋值给范围小的类型,需要强制类型转换,在进行强制类型转换时可能会发生数据溢出,需要格外注意。

float f = 10f;
int b = (int) f;

基本数据类型和String类型的转换

基本类型转String类型:直接+""即可

int a = 1;
double b = 2.0;
boolean d = true;
String s_a = "" + a;
String s_b = "" + b;
String s_d = "" + d;

String类型转基本类型:调用对应的包装类型的parseXXX方法

String s_a = "1";
String s_b = "2.0";
String s_d = "true";
int a = Integer.parseInt(s_a);
double b = Double.parseDouble(s_b);
boolean d = Boolean.parseBoolean(s_d);

对于字符,使用str.charAt(index)方法获取字符串中指定位置的字符。

String str = "Hello";
char ch = str.charAt(0);  // 获取第一个字符 'H'
System.out.println(ch);  // 输出: H

运算符

算数运算符

  • +:加法
  • -:减法
  • *:乘法
  • /:除法
  • %:取模(求余数)
  • ++:自增(变量值加1)
  • --:自减(变量值减1)

对于++--,如果时右++,是先赋值在运算;如果是左--,是先运算在赋值。

int number = 1;
int count = number++;
System.out.println(number); // 2
System.out.println(count); // 1
int number = 1;
int count = ++number;
System.out.println(number); // 2
System.out.println(count); // 2

关系运算符

  • ==:等于
  • !=:不等于
  • >:大于
  • <:小于
  • >=:大于等于
  • <=:小于等于

逻辑运算符

  • &&:逻辑与(两个条件都为真时返回真)
  • ||:逻辑或(至少一个条件为真时返回真)
  • !:逻辑非(反转布尔值)

对于&&||,多个条件进行判断时,如果在中间的某个条件就已经能判断出结果,就会直接停止判断。

int number = 1;
if(number < 0 && ++number > 1) {
     System.out.println("Hello World"); // 不会输出
}
System.out.println(number); // 1

// 因为number < 0可以判断出最终结果为false,后面的++number > 1就没有在进行。
int number = 1;
if(++number > 1 || ++number > 2) {
     System.out.println("Hello World"); // 会执行,输出Hello World
}
System.out.println(number); // 2

// 因为++number > 1可以判断出最终结果为true,后面的++number > 1就没有在进行。

赋值运算符和复合赋值运算符

  • =:赋值
  • +=:加后赋值
  • -=:减后赋值
  • *=:乘后赋值
  • /=:除后赋值
  • %=:取模后赋值

复合赋值运算符如a+=b,相当于a=a+b,复合赋值运算符会发生类型转换,如byte a = 1;a += 2;等同于a = (byte)(a + 2)

位运算符

  • &按位与,对两个操作数的每一位进行与操作,只有当两个对应位都为1时,结果位才为1,否则为0。

    int a = 5;  // 二进制:0101
    int b = 3;  // 二进制:0011
    int result = a & b; // 结果:0001 (十进制 1)
    
  • |按位或,对两个操作数的每一位进行或操作,只要有一个对应位为1,结果位就为1。

    int a = 5;  // 二进制:0101
    int b = 3;  // 二进制:0011
    int result = a | b; // 结果:0111 (十进制 7)
    
  • ^按位异或,对两个操作数的每一位进行异或操作,当两个对应位不同时,结果位为1,否则为0。

    int a = 5;  // 二进制:0101
    int b = 3;  // 二进制:0011
    int result = a ^ b; // 结果:0110 (十进制 6)
    
  • ~按位取反,对操作数的每一位进行取反操作,即1变0,0变1。

    int a = 5;  // 二进制:0000 0101
    int result = ~a; // 结果:1111 1010 (十进制 -6)
    
  • >>右移,将操作数的二进制位向右移动指定的位数,左侧空出的位用符号位填充(正数补0,负数补1)。

    int a = 10; // 二进制:0000 1010
    int result = a >> 1; // 结果:0000 0101 (十进制 5)
    
  • <<左移,将操作数的二进制位向左移动指定的位数,右侧空出的位用0填充。

    int a = 5;  // 二进制:0000 0101
    int result = a << 1; // 结果:0000 1010 (十进制 10)
    
  • >>>无符号右移,将操作数的二进制位向右移动指定的位数,左侧空出的位用0填充(无论正负),没有<<<

    int a = -10; // 二进制:1111 1111 1111 1111 1111 1111 1111 0110
    int result = a >>> 1; // 结果:0111 1111 1111 1111 1111 1111 1111 1011 (正数)
    

三元运算符

格式条件 ? 表达式1 : 表达式2,如果条件为真,返回表达式1的值,否则返回表达式2的值。

int a = 10;
int b = 22;
int c = a > b ? a : b; // 22

// a > b不为真,返回b的值,可以用来求两个数的最大值。

控制结构

分支控制

if语句

基本语法如下:

if (条件1) {
    // 当条件1为 true 时执行的代码
} else if (条件2) {
    // 当条件1为 false 且条件2为 true 时执行的代码
} else if (条件3) {
    // 当条件1和条件2为 false 且条件3为 true 时执行的代码
} else {
    // 当所有条件都为 false 时执行的代码
}

其中至少需要有一个if(条件),可以在内部嵌套if

int score = 85;

if (score >= 90) {
    System.out.println("成绩等级:A");
} else if (score >= 80) {
    System.out.println("成绩等级:B");
} else if (score >= 70) {
    System.out.println("成绩等级:C");
} else if (score >= 60) {
    System.out.println("成绩等级:D");
} else {
    System.out.println("成绩等级:F");
}
// 成绩等级:B

switch语句

基本语法如下:

switch (表达式) {
    case 值1:
        // 当表达式等于值1时执行的代码
        break;
    case 值2:
        // 当表达式等于值2时执行的代码
        break;
    case 值3:
        // 当表达式等于值3时执行的代码
        break;
    // 可以有任意数量的 case
    default:
        // 当表达式不匹配任何 case 时执行的代码
      	break;
}

表达式的类型可以是 intcharbyteshortString或枚举类型。

每个 case 后面跟一个常量值,表示与表达式可能匹配的值。

break用于终止 switch 语句,如果没有 break,程序会继续执行后续的 case 代码块。

default是可选的,当表达式的值不匹配任何 case 时,执行 default 后的代码块。

int day = 3;
String dayName;

switch (day) {
    case 1:
        dayName = "星期一";
        break;
    case 2:
        dayName = "星期二";
        break;
    case 3:
        dayName = "星期三";
        break;
    case 4:
        dayName = "星期四";
        break;
    case 5:
        dayName = "星期五";
        break;
    case 6:
        dayName = "星期六";
        break;
    case 7:
        dayName = "星期日";
        break;
    default:
        dayName = "无效的星期数";
}

System.out.println(dayName); // 星期三

switch和if的选择

如果判断的数值不多,而且是 intcharbyteshortString或枚举类型,虽然都可以用,建议使用switch,否则,则使用if

在底层的实现上,switch的速度相较于if更快。

循环控制

for循环

基本语法如下:

for (初始化表达式; 条件表达式; 迭代表达式) {
    // 循环体
}

初始化表达式:在循环开始时执行一次(通常用于定义并初始化循环变量)。

条件表达式:每次循环迭代前都会检查,如果为 true,则执行循环体;否则循环结束。

迭代表达式:每次循环迭代后执行,通常用于更新循环变量。

每个表达式部分可以为空,但是必需要写上";"。

for (int i = 0; i < 5; i++) {
    System.out.println("当前 i 的值:" + i);
}
/* 输出:
当前 i 的值:0
当前 i 的值:1
当前 i 的值:2
当前 i 的值:3
当前 i 的值:4
*/

高级for循环:

用于遍历数组或集合,语法如下:

for (元素类型 变量名 : 数组或集合) {
    // 操作变量
}

示例:

int[] numbers = {1, 2, 3, 4, 5};
for (int num : numbers) {
    System.out.println(num);
}

while循环

基本语法如下:

while (条件表达式) {
    // 循环体
}

条件表达式:在每次循环迭代前检查,如果为 true,则执行循环体;否则循环结束。

int i = 0;
while (i < 5) {
    System.out.println("当前 i 的值:" + i);
    i++;  // 迭代
}
/*
当前 i 的值:0
当前 i 的值:1
当前 i 的值:2
当前 i 的值:3
当前 i 的值:4
*/

注意事项:

必须注意循环条件,防止无限循环即死循环。

do...while 循环

基本语法如下:

do {
    // 循环体
} while (条件表达式)

先执行循环体,再检查条件表达式,如果为 true,则继续执行循环;否则退出。

int i = 0;
do {
    System.out.println("当前 i 的值:" + i);
    i++;
} while (i < 5);
/*
当前 i 的值:0
当前 i 的值:1
当前 i 的值:2
当前 i 的值:3
当前 i 的值:4
*/

breakcontinue 关键字

break终止 当前循环,并跳出循环结构。

continue跳过 本次循环,直接进入下一次迭代。

for (int i = 0; i < 10; i++) {
    if (i == 5) {
        break;  // 当 i == 5 时,终止整个循环
    }
    System.out.println(i);
}

int j = 0;
while (j < 10) {
    j++;
    if (j == 5) {
        continue;  // 当 j == 5 时,跳过本次循环
    }
    System.out.println(j);
}

此外,return也会终止掉循环,实质是终止掉了方法的执行并返回结果。

数组

数组的声明

结构如下:

数据类型[] 数组名;  // 推荐写法
数据类型 数组名[];  // 也可以这样写,但不推荐

示例:

int[] numbers;  // 定义一个整型数组
double[] prices; // 定义一个浮点型数组
String[] names; // 定义一个字符串数组

数组的声明不会分配内存,必须显式初始化才能使用。

数组的初始化

静态初始化

在定义数组的同时,直接指定数组元素:

int[] numbers = {1, 2, 3, 4, 5}; 
String[] names = {"Alice", "Bob", "Charlie"};

动态初始化

在定义数组时,只指定长度,然后逐个赋值:

int[] arr = new int[5];  // 创建长度为 5 的 int 数组,默认值为 0
arr[0] = 10;  
arr[1] = 20;  

默认初始化int 为 0,double 为 0.0,boolean 为 false,char为\u0000,引用类型为null。

访问数组元素

数组中的元素通过 索引访问,索引从 0 开始,直到数组的长度减一,索引为i的元素实际对应第i+1个元素:

int[] arr = {10, 20, 30, 40};
System.out.println(arr[0]); // 输出 10
arr[2] = 100;  // 修改第 3 个元素

访问数组的索引越界,即超过了索引的最大值,会发生异常。

数组的遍历

使用for循环:

int[] numbers = {1, 2, 3, 4, 5};
for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

使用while循环:

int[] numbers = {1, 2, 3, 4, 5};
int i = 0;
while (i < numbers.length) {
     System.out.println(numbers[i]);
     i++;
}

多维数组

声明和初始化

静态初始化:

int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6}
};
// 定义一个2行3列的二维数组

动态初始化:

int[][] matrix = new int[2][3];  // 2 行 3 列的数组
matrix[0][1] = 10;  // 赋值

遍历多维数组

int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6}
};
for (int i = 0; i < matrix.length; i++) {
    for (int j = 0; j < matrix[i].length; j++) {
        System.out.print(matrix[i][j] + " ");
    }
    System.out.println();
}

数组的操作

获取数组长度

使用数组名.length获取数组的长度

数组拷贝

int[] arr1 = {1, 2, 3, 4, 5};
int[] arr2 = new int[arr1.length];
System.arraycopy(arr1, 0, arr2, 0, arr1.length);

System.arraycopy() 方法参数:

  • 源数组
  • 源起始索引
  • 目标数组
  • 目标起始索引
  • 复制长度

Arrays工具类

  • Arrays.toString(Object[] a):将数组转换成字符串。

    String[] chars = {"aa", "ac", "ab", "da", "ea"};
    System.out.println(Arrays.toString(chars)); // [aa, ac, ab, da, ea]
    
  • Arrays.sort(Oject[] a):为数组排序,按照从小到大的顺序。对于字符类型的数组,则是按照首字母的顺序。对于字符串类型的数组,则是依次比较字母的顺序(仅限英文单词)。

    String[] chars = {"aa", "ac", "ab", "da", "ea"};
    Arrays.sort(chars);
    System.out.println(Arrays.toString(chars)); // [aa, ab, ac, da, ea]
    
  • Arrays.binarySearch(int[] a, int key):二分查找元素的索引,必需传入一个排序好的数组,如果找到则返回元素索引,找不到则返回负数。

    int[] arr = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    Arrays.sort(arr);
    int index = Arrays.binarySearch(arr, 5);
    System.out.println(index); // 5