本期是Java开发教程系列的第一期,本期主要要向各位介绍Java的基础信息.若你已经了解Java语法基础,并对面向对象编程有一定的体会,可以跳过本期内容.后续多期内容将以Minecraft(我的世界)模组教学为背景展开.
每期叠甲:
时间仓促,水平有限,文中难免存在缺点和错误,恳请广大开发者和从业者指正.
首先,我们需要了解一下 Java 的基础语法.我将其分成四个部分:
变量、数据类型、运算符
控制流程(if/for/while)
方法(函数)的定义和调用
数组和集合(List/Map)
首先先向各位介绍Java语言的变量.一共有八种
// 整数类型
byte myByte = 127; // 8位,范围 -128 到 127
short myShort = 32000; // 16位,范围 -32768 到 32767
int myInt = 2147483647; // 32位,最常用的整数类型
long myLong = 9223372036854775807L; // 64位,注意末尾的 L
// 浮点类型
float myFloat = 3.14f; // 32位,注意末尾的 f
double myDouble = 3.14159265359; // 64位,默认的小数类型
// 字符类型
char myChar = 'A'; // 16位 Unicode 字符
// 布尔类型
boolean myBoolean = true; // 只有 true 或 false
除了基本类型,其他都是引用类型(对象)
// 字符串(最常用的引用类型)
String MyCodes = "mycodes";
String fileName = "filename";
// 数组
int\[\] numbers = {1, 2, 3, 4, 5};
String\[\] names = new String[10]; // 创建长度为 10 的数组
// 对象
File myFile = new File(new xxxxxx); // 这里的问题后面具体说
以上就是 Java 中变量的分类:八种基本类型 + 无数种引用类型.接下来我们逐部分展开.
一、变量、数据类型、运算符
1.1 变量的声明
变量声明遵循"类型 变量名"的格式:
int age = 18; // 声明一个 int 变量并赋初值 18
double height = 1.75; // 声明一个 double 变量
String name; // 只声明,不赋值(此时是 null)
name = "lihua"; // 之后再赋值
1.2 变量的命名规则
只能由 字母、数字、下划线_、美元符号 `$` 组成
不能以数字开头,不能是 Java 关键字(如 class、new、int)
推荐使用驼峰命名法:myName、fileName、playerCount
int 2count; // 不能以数字开头
int class; // class 是关键字
int playerCount; // 驼峰命名,推荐
1.3 运算符
Java 的运算符分为四类,在开发中非常常用:
第 1 列 |
第 2 列 |
第 3 列 |
第 4 列 |
|---|
类型 |
运算符 |
说明 |
|
算术 |
+ - * / % |
% 是取余,如 7 % 3 = 1 |
|
赋值 |
= += -= *= /= %= |
x += 5 等价于 x = x + 5 |
|
比较 |
== != > < >= <= |
结果是 boolean |
|
逻辑 |
&& || ! |
与、或、非 |
|
|
|
|
|
int a = 10;
int b = 3;
// 这里的System.out.println() 类似于Python的print
System.out.println(a + b); // 13
System.out.println(a % b); // 1
System.out.println(a > b); // true
System.out.println(a == b); // false
boolean isDay = true;
boolean isRain = false;
System.out.println(isDay && isRain); // false,两个都为 true 才为 true
System.out.println(isDay || isRain); // true,有一个为 true 就为 true
System.out.println(!isDay); // false,布尔值取反
二、控制流程(if/for/while)
2.1 if 判断
int hp = 50;
if (hp <= 0) {
System.out.println("玩家已死亡");
} else if (hp <= 20) {
System.out.println("血量未满");
} else {
System.out.println("血量已满");
}
2.2 for 循环
// 一共执行 10 次:当 i = 0,1,2,...,9 时各执行一次;i = 10 时条件不成立,循环结束
for (int i = 0; i < 10; i++) {
System.out.println("第 " + i + " 次循环");
}
for 的三段分别是:初始化、循环条件、步进.`i++` 表示每次加一.
2.3 while 循环
int count = 0;
while (count < 5) { // 先判断,后执行
System.out.println("count = " + count);
count++;
}
int a = 0;
do { // 先执行一次,再判断
System.out.println(a);
a++;
} while (a < 3);
区别:while 可能一次都不执行,而 do...while 至少执行一次.
2.4 增强 for 循环(foreach)
遍历数组或集合时非常简洁,后面会频繁用到:
int[] scores = {60, 80, 100};
for (int s : scores) {
System.out.println(s);
}
for/while 本身非常轻量,单层循环开销极小.真正要注意的是嵌套循环——循环套循环,每多一层,执行次数就成倍增长;嵌套多一层,压力就成倍增长.另外增强 for 只是语法糖,遍历数组时性能与下标循环几乎一样,不用担心它"更慢".(至于"到底有多快、差距有多大",有一种专门衡量的方法,后面会再讲)
三、方法(函数)的定义和调用
方法是把一段代码封装起来,方便重复调用.
3.1 基本结构
修饰符 返回值类型 方法名(参数列表) {
// 方法体
return 返回值;
}
// 无返回值的方法
public static void greet(String name) {
System.out.println("你好, " + name + "!");
}
// 有返回值的方法
public static int add(int x, int y) {
return x + y;
}
// 调用
greet("mc"); // 你好, mc!
int sum = add(3, 4); // sum = 7
void 表示没有返回值
return 会结束方法并返回结果
调用时传入的实参要与参数列表一一对应
3.2 方法重载(Overload)
同一个类中,方法名相同但参数列表不同,叫重载.调用时按传入的参数自动匹配:
public static int add(int a, int b) {
return a + b;
}
public static int add(int a, int b, int c) {
return a + b + c;
}
add(1, 2); // 调用第一个,结果 3
add(1, 2, 3); // 调用第二个,结果 6
四、数组和集合(List/Map)
4.1 数组
数组长度固定,创建后不可改变:
int[] nums = {1, 2, 3}; // 方式一:直接初始化
String[] names = new String[5]; // 方式二:指定长度,默认 null
System.out.println(nums[0]); // 1,下标从 0 开始
nums[1] = 100; // 修改元素
System.out.println(nums.length); // 3,数组长度
数组是连续内存,几乎零额外开销,是占用最小的容器;缺点是长度固定,不能自动扩容.
4.2 List(列表)
比数组灵活,长度可以动态变化.最常用的是 ArrayList:
import java.util.ArrayList;
import java.util.List;
List<String> items = new ArrayList<>(); // 新建一个空的字符串列表
// 我是我的世界mod开发者,这里很多地方就用mc的元素了
items.add("sword"); // 添加元素
items.add("pickaxe");
items.remove("sword"); // 删除元素
System.out.println(items.size()); // 1,当前元素个数
System.out.println(items.get(0)); // pickaxe,按下标取值
<> 里的类型叫泛型,表示这个列表里装的是什么类型.
ArrayList 底层是会自动扩容的数组,每个元素存的只是引用(64 位 JVM 下约 8 字节),元素对象本身占的内存另算;扩容时会把旧数组整体拷贝一份(约扩到 1.5 倍).按下标取元素很快;但 contains(x) / remove(x) 要逐个比较,数据量大时别在循环里反复调用.
4.3 Map(映射表)
以"键-值对"存储数据,就像一本字典.最常用的是 HashMap:
import java.util.HashMap;
import java.util.Map;
Map<String, Integer> inventory = new HashMap<>();
inventory.put("diamond", 5); // 存入键值对
inventory.put("iron", 12);
System.out.println(inventory.get("diamond")); // 5,按键取值
inventory.put("diamond", 6); // 重复 put,会覆盖旧值
System.out.println(inventory.containsKey("iron")); // true,是否包含某个键
HashMap 的 get/put 都很快,适合"按键取值".但它内存开销比 List 大不少:底层有一块桶数组,每个键值对还要额外包装成 Node 对象,存的条目越多,差距越明显.
朝花夕拾:回到之前 File 的问题
开头我们写了这样一行:
File myFile = new File(new xxxxxx);
这行代码是有问题的.new xxxxxx 是想再创建一个对象传给 File 的构造方法,但 File 的常用构造方法接收的是一个路径字符串,而不是另一个对象.正确写法如下:
// 方式一:直接传入文件路径(注意反斜杠要写两个)
File myFile = new File("D:\\mc\\mod\\config.txt");
// 方式二:父目录 + 文件名
File parent = new File("D:\\mc\\mod");
File myFile2 = new File(parent, "config.txt");
小知识:File 并不代表"文件内容",它只是对文件或目录路径的抽象.真正读写文件内容是后面会讲到的 FileInputStream、FileWriter 等.
总结
本期我们完成了 Java 入门第一课:
掌握了以上基础,就可以开始阅读和编写简单的 Java 程序了.
: )