这是之前备考时留下的 Java 二级笔记,后来又按教育考试院公开的二级 Java 考试大纲与样题补了一轮。考试环境的编辑器功能比较有限,和平时使用的 IntelliJ IDEA 差别很大,因此复习时除了看语法,还要练习在简单编辑器中定位编译错误。
Java 二级涉及的知识面比较宽,除了基础语法、面向对象、异常和线程,还保留了 AWT、Swing、Applet 等偏传统的 GUI 内容。操作题多为补空或修改既有代码,但仅背方法名并不稳,最好能看懂组件、容器和监听器之间的关系。
推荐题库:java.code2ji.cn(Java二级在线)
它的实用点是浏览器里可以直接运行 Java 小程序,并查看部分 GUI 题目的实际界面;手机端也能查看题面和填写代码。
Java 基础语法笔记
1. Java 基本概念
- Java 是一种面向对象的编程语言,广泛应用于开发桌面应用、Web应用和Android应用。
- Java 程序是由类(Class)组成的,每个程序必须有一个入口点,
main方法。
2. Java 程序结构
一个基本的 Java 程序结构如下:
public class HelloWorld {
public static void main(String[] args) {
// 这是输出语句
System.out.println("Hello, World!");
}
}
说明:
public class HelloWorld:定义一个类,类名通常与文件名相同。public static void main(String[] args):main 方法是 Java 程序的入口点。System.out.println:用于输出到控制台。
3. 基本数据类型
Java 有 8 种基本数据类型:
| 类型 | 描述 | 默认值 |
|---|---|---|
byte | 8位整数 | 0 |
short | 16位整数 | 0 |
int | 32位整数 | 0 |
long | 64位整数 | 0L |
float | 单精度浮点数 | 0.0f |
double | 双精度浮点数 | 0.0d |
char | 单个字符 | ‘\u0000’ |
boolean | 布尔值 | false |
表中的默认值只适用于实例字段、静态字段和数组元素;局部变量在读取前必须显式赋值。Java 规范也没有规定 boolean 必须占几个字节。
4. 变量声明与赋值
声明和初始化变量:
int x = 10; // 整型变量
double y = 3.14; // 双精度浮点型变量
boolean isJava = true; // 布尔型变量
char grade = 'A'; // 字符型变量
常见操作:
x = 20; // 变量赋值
int sum = x + 10; // 变量计算
5. 控制结构
条件语句
Java 使用 if, else if, 和 else 来进行条件判断。
int age = 18;
if (age >= 18) {
System.out.println("You are an adult.");
} else {
System.out.println("You are a minor.");
}
循环语句
Java 提供了 for、while 和 do-while 三种循环结构。
for 循环:
for (int i = 0; i < 5; i++) {
System.out.println("i = " + i);
}
while 循环:
int j = 0;
while (j < 5) {
System.out.println("j = " + j);
j++;
}
do-while 循环:
int k = 0;
do {
System.out.println("k = " + k);
k++;
} while (k < 5);
6. 数组
一维数组
int[] numbers = {1, 2, 3, 4, 5};
System.out.println(numbers[0]); // 输出 1
二维数组
int[][] matrix = {{1, 2, 3}, {4, 5, 6}};
System.out.println(matrix[1][2]); // 输出 6
真题实战:5×5 上三角矩阵(题目来源:java.code2ji.cn)
来看这道经典的数组操作题:

题目要求:构造一个 5×5 的上三角矩阵并输出。
public class Main {
public static void main(String args[]) {
int a[][] = new int[5][5]; // 声明5×5二维数组
int i, j, k = 1;
for(i = 0; i < 5; i++)
for(j = 0; j < 5; j++)
if((i + j) < 5) { // 上三角条件
a[i][j] = k;
k++; // 递增
if (k > 9) k = 1; // 大于9重置为1
} else
a[i][j] = 0; // 下三角设为0
for(i = 0; i < 5; i++) {
for(j = 0; j < 5; j++)
System.out.print(a[i][j] + " ");
System.out.println(); // 换行
}
}
}
解题思路与考点解析:
这道题考查二维数组操作和上三角矩阵的构造,需要理解数组索引与矩阵位置的关系。
- 二维数组声明:
int a[][] = new int[5][5]创建 5×5 数组; - 条件判断:
(i + j) < 5判断是否在上三角区域; - 循环赋值:
k值循环使用 1-9,超过 9 重置为 1; - 记忆技巧:二维数组
a[行][列],先行后列;副对角线上三角条件为行索引 + 列索引 < 总阶数。
7. 方法(函数)
方法声明和调用:
public class Main {
public static void main(String[] args) {
greet("Alice");
}
public static void greet(String name) {
System.out.println("Hello, " + name);
}
}
8. 面向对象
类与对象
class Person {
String name;
int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void greet() {
System.out.println("Hello, my name is " + name + " and I am " + age + " years old.");
}
}
public class Main {
public static void main(String[] args) {
Person p = new Person("Alice", 30);
p.greet();
}
}
继承与多态
class Animal {
public void sound() {
System.out.println("Animal makes a sound.");
}
}
class Dog extends Animal {
@Override
public void sound() {
System.out.println("Dog barks.");
}
}
public class Main {
public static void main(String[] args) {
Animal a = new Dog();
a.sound(); // 输出: Dog barks. (多态调用)
}
}
重载、重写、抽象类与接口速查
- 重载(overload):发生在同一个类中,方法名相同,参数个数、类型或顺序不同;不能只靠返回类型区分。
- 重写(override):子类重新实现父类的实例方法,方法签名一致,访问权限不能缩小,可使用
@Override检查。 - 抽象类:用
abstract class声明,可以有字段、构造方法、普通方法和抽象方法,不能直接实例化。 - 接口:字段隐式为
public static final;没有方法体的普通接口方法隐式为public abstract。一个类只能直接继承一个父类,但可以实现多个接口。
访问范围从小到大可记为:private → 默认包访问 → protected → public。static 成员属于类,静态方法中不能直接使用 this 或访问实例字段。
9. 常见类库
// String
String greeting = "Hello, World!";
System.out.println(greeting.length());
System.out.println(greeting.toUpperCase());
// ArrayList
import java.util.ArrayList;
ArrayList<String> list = new ArrayList<>();
list.add("Apple");
System.out.println(list.get(0));
// Scanner 输入
import java.util.Scanner;
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
从下面开始进入更容易丢分的部分。Java 二级不只考基础语法,还会涉及异常、I/O、线程和 GUI,代码一长就更考验阅读顺序。
进阶考点:异常、IO、多线程与 GUI
1. 异常处理
public static void main(String[] args) {
test(1, 0); // 当 b 为 0 的时候,还能正常运行吗?
}
private static int test(int a, int b) {
return a / b; // 没有任何的判断而是直接做计算
}
结果会报错:

考试环境如果允许复制文本,调试时可以先从报错信息里复制异常类名再搜索代码位置;不过 ArithmeticException、NullPointerException、ArrayIndexOutOfBoundsException、IOException 这些高频类型仍然值得直接认出来。
异常的类型
Java 中可抛出的对象都继承自 Throwable。它下面主要分为 Error 和 Exception;常见运行时异常继承自 RuntimeException,受检异常则需要捕获或在方法签名中声明抛出。
如空指针异常:
public static void main(String[] args) {
Object object = null;
object.toString(); // 运行时抛出 NullPointerException
}

抛出异常
当传入错误参数导致无法运行,我们可以手动抛出异常:
public static int test(int a, int b) {
if (b == 0)
throw new IllegalArgumentException("除数不能为0");
return a / b;
}
当出现异常时:

程序会终止并打印栈追踪信息。实际上方法之间的调用是有层级关系的,位于最上面的就是发生异常的最核心代码行。
异常的捕获与处理
简单来说就是程序在遇到异常的时候会不知道怎么办,一般情况下会自动终止。然而你作为伟大的程序员早就料到了这一切,并且要求程序在遇到这个问题的时候不用停止,按照你说的继续做下去:
public static void main(String[] args) {
try {
Object object = null;
object.toString();
} catch (NullPointerException e) {
System.out.println("捕获到了空指针异常!");
}
System.out.println("程序继续正常运行!");
}

多重异常捕获注意顺序:子类在前,父类在后。
try {
// 可能出错的代码
} catch (NullPointerException e) {
// 处理空指针
} catch (IndexOutOfBoundsException e) {
// 处理数组越界
} catch (Exception e) {
// 处理其他异常
} finally {
System.out.println("无论是否出现异常,都会在最后执行!");
}
2. Java I/O 输入输出流
I/O 简而言之就是输入输出。
文件字节流
使用 FileInputStream 获取输入流:
// JDK 1.7 try-with-resources 语法,自动释放资源
try (FileInputStream inputStream = new FileInputStream("test.txt")) {
int tmp;
while ((tmp = inputStream.read()) != -1) { // 循环按字节读取,-1 表示文件结束
System.out.print((char)tmp);
}
} catch (IOException e) {
e.printStackTrace();
}
小文件演示中也能按当前可读字节数准备缓冲区:
try (FileInputStream inputStream = new FileInputStream("test.txt")) {
byte[] bytes = new byte[inputStream.available()];
inputStream.read(bytes);
System.out.println(new String(bytes));
} catch (IOException e) {
e.printStackTrace();
}
available() 不是“文件总长度”的通用接口,只表示当前无需阻塞即可读取的字节数。正式处理文件更稳妥的写法是循环调用 read(buffer),并以返回值 -1 判断结束。
文件输出流与文件拷贝:
try (FileOutputStream outputStream = new FileOutputStream("output.txt");
FileInputStream inputStream = new FileInputStream("test.txt")) {
byte[] bytes = new byte[10];
int tmp;
while ((tmp = inputStream.read(bytes)) != -1) {
outputStream.write(bytes, 0, tmp);
}
} catch (IOException e) {
e.printStackTrace();
}
对格式的疑惑请见:

真题实战:文件数据流读写(题目来源:java.code2ji.cn)
import java.io.*;
public class Main {
public static void main(String[] args) {
char[] charArray = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i'};
char c;
try {
// 创建数据输出流,写入文件
DataOutputStream out = new DataOutputStream(new FileOutputStream("test.txt"));
for(int i = 0; i < charArray.length; i++) {
out.writeChar(charArray[i]); // 写入字符
}
out.close();
// 创建数据输入流,从文件读取
DataInputStream in = new DataInputStream(new FileInputStream("test.txt"));
while(in.available() != 0) {
c = in.readChar(); // 读取字符
System.out.print(c + " ");
}
System.out.println();
in.close();
} catch(IOException e) {
e.printStackTrace();
}
}
}
这道题为了配合 DataInputStream 的演示使用了 available()。实际工程中不应把它理解为通用的“剩余文件长度”;处理未知长度的数据时,应根据读取方法的返回值或捕获 EOF 来判断结束。
3. 多线程编程
在了解多线程之前,回顾一下进程概念:进程是程序执行的实体(比如我们运行 QQ、浏览器、LOL、网易云音乐等),都有自己的内存空间。

但是如果我希望两个任务同时进行,进程之间通信太麻烦,上下文切换非常耗时。

后来线程横空出世,一个进程可以有多个线程,各个线程之间共享程序的内存空间。
线程的创建和启动
通过 Lambda 或匿名内部类实现 Runnable:



双线程并发交替执行实例:
public class Main {
public static void main(String[] args) {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 20; i++) System.out.println("一号线程: " + i);
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 20; i++) System.out.println("二号线程: " + i);
});
t1.start(); // 必须调用 start(),不能调用 run()!
t2.start();
}
}

线程锁与 synchronized 同步
多线程下变量存储在主内存中,每个线程有自己的工作内存:


如果同时写入共享变量就会导致数据错乱:

使用 synchronized 关键字创建同步锁:
private static int value = 0;
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
synchronized (Main.class) {
value++;
}
}
});
Thread t2 = new Thread(() -> {
for (int i = 0; i < 10000; i++) {
synchronized (Main.class) {
value++;
}
}
});
t1.start();
t2.start();
t1.join();
t2.join();
System.out.println("最终结果: " + value); // 两个线程结束后输出 20000
}
这里必须等待两个工作线程结束。Thread.sleep(1000) 只能让当前线程暂停一段时间,并不能保证另外两个线程恰好已经执行完成;join() 才是在等待目标线程终止。
死锁现象
当线程相互持有对方需要的锁又不释放时产生死锁:


ThreadLocal 线程本地变量
不同的线程访问到 ThreadLocal 对象时,都只能获取到当前线程所属的变量:

4. GUI 程序开发(AWT 与 Swing)
这部分不必死记所有组件,先抓住“创建组件 → 设置属性 → 加入容器 → 绑定事件”这条主线。
AWT 组件与窗口
AWT(Abstract Window Toolkit)是 Java 提供的抽象窗口工具包。

(woc,原)
创建基本窗口与事件监听器:
import java.awt.*;
import java.awt.event.*;
public class Main {
public static void main(String[] args) {
Frame frame = new Frame("AWT窗口");
frame.setSize(400, 250);
frame.setLayout(null); // 绝对定位
// 标签
Label label = new Label("用户名:");
label.setBounds(30, 50, 60, 25);
frame.add(label);
// 文本框
TextField field = new TextField();
field.setBounds(100, 50, 150, 25);
frame.add(field);
// 按钮与点击监听
Button button = new Button("点击登录");
button.setBounds(100, 90, 80, 30);
button.addActionListener(e -> System.out.println("输入的内容是: " + field.getText()));
frame.add(button);
// 窗口关闭监听
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
frame.dispose();
System.exit(0);
}
});
frame.setVisible(true);
}
}




5. Swing 实战大题:模拟 QQ 登录界面
这是一道非常综合的机考真题:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class Main extends JFrame {
private JTextField username;
private JPasswordField password;
private JLabel jl3;
private JLabel jl4;
private JButton bu1, bu2, bu3;
private JCheckBox jc1, jc2;
private JComboBox<String> jcb;
public Main() {
this.setTitle("QQ2025正式版");
init();
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setLayout(null);
this.setBounds(0, 0, 355, 265);
this.setResizable(false);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
public void init() {
Container con = this.getContentPane();
username = new JTextField();
username.setBounds(50, 50, 150, 20);
jl3 = new JLabel("注册账号");
jl3.setBounds(210, 50, 70, 20);
password = new JPasswordField();
password.setBounds(50, 80, 150, 20);
jl4 = new JLabel("找回密码");
jl4.setBounds(210, 80, 70, 20);
jc1 = new JCheckBox("记住密码");
jc1.setBounds(125, 135, 80, 15);
jc2 = new JCheckBox("自动登录");
jc2.setBounds(215, 135, 80, 15);
jcb = new JComboBox<>();
jcb.addItem("在线");
jcb.addItem("隐身");
jcb.addItem("离开");
jcb.setBounds(40, 135, 55, 20);
bu1 = new JButton("登录");
bu1.setBounds(250, 200, 65, 20);
bu1.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
JOptionPane.showConfirmDialog(null, "您输入的用户名是 " + username.getText());
}
});
bu2 = new JButton("多账号");
bu2.setBounds(25, 200, 75, 20);
bu3 = new JButton("设置");
bu3.setBounds(140, 200, 65, 20);
con.add(username); con.add(password);
con.add(jl3); con.add(jl4);
con.add(jc1); con.add(jc2);
con.add(jcb);
con.add(bu1); con.add(bu2); con.add(bu3);
}
public static void main(String[] args) {
new Main();
}
}
解题思路与考点总结:
- GUI 编程三步法:创建组件
→
\rightarrow
→ 设置属性/坐标(
setBounds) → \rightarrow → 添加到容器(con.add); - 事件监听:
button.addActionListener(e -> ...); - 密码框组件:使用
JPasswordField自动隐藏输入明文。
结语
差不多也就这些内容(其实真不少)。
题库平台最后还是拿出来夸一下:java.code2ji.cn
能在线跑代码、查看部分 GUI 题的界面,手机也能打开题面,用来零散复习很方便。

288

被折叠的 条评论
为什么被折叠?



