【编程语言】Java基础语法回顾,大学期末考试速通版(选择填空、程序、实践)
【编程语言】Java基础语法回顾,大学期末考试速通版(选择填空、程序、实践)
文章目录
- 1、Java基础知识(选择填空题)
- 图形化 Swing
- 面向对象,继承&接口,对比C++
- 线程进程,并发 gc
- 异常处理,受检&非受检
- 注解和框架,spring,Ioc,AOP
- 2、1个项目回顾Java基础语法(程序题)
- Main.java
- 1、BasicSyntax.java
- 2、OOP.java、student_manager.cpp
- 3、ExceptionHandle.java
- 4、IOStream.java
- 5、SwingGUI.java
- 6、ThreadDemo.java
- 3、Java更多题目(实践题)
- 基础语法
- 常见算法
- 面向对象
- 图形界面
- IO文件
- 多线程
嗯,这个月又是咕咕咕的一个月~ 发一些远古文档~
带你从零基础,到12小时掌握这门Java课程~
1、Java基础知识(选择填空题)

图形化 Swing
Swing 的四个顶层组件?
- Swing 顶层组件是能独立存在、无需依赖其他容器的组件,共 4 个:
- JFrame:普通窗口(有标题栏、关闭 / 最小化按钮),是 Swing 应用最常用的顶层容器(如你之前项目中的窗口)。
- JDialog:对话框(依赖父窗口,父窗口关闭则对话框消失),用于弹出提示、输入等交互(如 JOptionPane 本质基于此)。
- JApplet:小应用程序容器(运行在浏览器或 Applet viewer 中,现已较少用)。
- JWindow:无边框窗口(无标题栏、无控制按钮,需手动添加组件和事件)。
画图(Swing/AWT)画直线
- 通过 Graphics 或 Graphics2D 类的 drawLine() 方法实现,核心是重写 JPanel 的 paintComponent() 方法(避免窗口刷新时图形消失),步骤如下:
面向对象,继承&接口,对比C++
static是什么?
- 假设你有一个Student类,需要统计所有学生的总数。如果不用static,每个学生对象都会有一个count变量,无法共享计数;而用static修饰count后,它就属于Student类本身,所有对象共享这一个变量,能正确统计总数。
- 当成员需要被所有对象共享(如计数、常量)时,用static避免资源浪费(无需每个对象都存一份)。
- 当方法 / 变量需要不创建对象就能使用时(如工具类方法、程序入口main),用static更方便。
- static的本质:属于类,不属于对象
非静态成员(无static):随对象创建而存在,随对象销毁而消失(每个对象一份)。
静态成员(有static):随类加载而存在,随类卸载而消失(整个程序运行期间只存在一份,所有对象共享)。
重载的关键判定公式
- 构成重载 = 方法名相同 + (参数个数不同 OR 参数类型不同 OR 参数顺序不同)
04737C++

这里我们主要来对比一下C++的面向对象
毕竟众所周知,C++主要就是OOP
- 继承
1、一个类可继承多个基类,语法:class 派生类 : 继承方式 基类1, 继承方式 基类2。
2、友元的 “资格” 必须由类内声明赋予,类内 / 外的区别只是函数声明和定义的位置不同,最终都能访问类的私有成员。
3、菱形继承问题,当一个派生类间接从同一个基类继承两次(形成 “菱形” 结构)时,会出现数据冗余和访问二义性。解决方式:在间接继承时使用 virtual 关键字(虚继承),让最终派生类只保留一份基类成员。 - 多态:
1、静态多态(编译期,如函数重载、运算符重载)和动态多态(运行期,基于虚函数)
2、虚函数必须在基类中声明 & 重写虚函数时参数个数必须相同
3、多态必须通过基类指针 / 引用实现
class B : virtual public A { }; // 虚继承 A
class C : virtual public A { }; // 虚继承 A
class D : public B, public C { }; int main() {D d;d.a = 10; // 合法,仅一份 A::areturn 0;
}
- 虚函数表是 C++ 实现多态的底层机制:当类包含虚函数时,编译器会为该类生成一张 “虚函数地址表”(Vtable),同时在类的对象中隐藏一个 “虚表指针”(vptr),指向这张表。
- C++允许灵活的多重继承,用虚基类解决菱形问题,,,
Java禁用多重继承保留单继承,不过实现了接口。。
Goland主要就是接口和组合了
| 特性 | C++ | Java | Golang |
|---|---|---|---|
| 类定义 | class/struct,支持全局函数 | 必须在 class 中,无全局函数 | 结构体 + 方法,无类关键字 |
| 继承 | 多重继承 + 虚基类(解决菱形问题) | 单继承 + 接口多实现 | 结构体嵌套(组合)模拟继承 |
| 多态 | 需显式 virtual 关键字,动态绑定基于虚函数表 | 非静态方法默认虚函数,自动动态绑定 | 接口隐式实现,基于方法集匹配 |
| 资源管理 | 析构函数自动调用(RAII) | 依赖 GC,无析构函数 | 手动释放,无析构函数 |
| 灵活性 vs 复杂性 | 极高灵活性(多重继承、模板等),但复杂 | 简化设计(单继承、GC),学习成本低 | 极简设计(组合优先),强调实用主义 |
类的继承&派生:像“家族遗传”,子承父业+新增技能
- “动物”是大家族(基类),有“呼吸、吃饭”的基本能力(基类公有成员函数
breathe()、eat()); - “狗”是动物的孩子(派生类),遗传了“呼吸、吃饭”的能力(继承基类成员),还新增了“汪汪叫”的专属技能(派生类新增成员函数
bark()); - “导盲犬”又是狗的孩子(派生类的派生类),除了“呼吸、吃饭、汪汪叫”,还会“引路”(新增
guide())。
| 继承方式 | 现实类比 | C++语法 | 权限变化(基类public成员) |
|---|---|---|---|
| public继承 | 完全遗传(孩子能对外用父亲的技能) | class Dog:public Animal{} | 基类public→派生类public |
| protected继承 | 半遗传(孩子能用但不能对外说) | class Dog:protected Animal{} | 基类public→派生类protected |
| private继承 | 隐藏遗传(孩子能用但孙子不能用) | class Dog:private Animal{} | 基类public→派生类private |
菱形问题类比:“爸妈都教你同一技能,听谁的?”
- 现实场景:
你(派生类D)的爸爸(基类B)和妈妈(基类C)都来自同一个爷爷(基类A),爷爷教爸爸和妈妈“下棋”(A的play()函数),现在你要下棋,不知道听爸爸的还是妈妈的(二义性)。 - 解决方案(虚基类):
爷爷提前说“你们(B和C)学的下棋都是我教的,统一听我的标准”(class B:virtual public A、class C:virtual public A),你就不会混乱了。
虚函数本质类比:通用遥控器(动态绑定)
- 现实场景:
你有一个“通用遥控器”(基类指针Animal *p),上面有“开机”键(虚函数virtual void start());
按“开机”键控制电视(派生类TV),电视会显示画面(TV::start());
按同样的“开机”键控制空调(派生类Air),空调会吹风(Air::start());
核心:遥控器(基类指针)不变,按同一个键(调用虚函数),不同设备(派生类对象)有不同反应。
友元本质类比:“你家的好朋友”(打破隐私但有限制)
- 现实场景:
你家(类MyHome)有“客厅”(公有成员,外人能进)和“卧室”(私有成员,只有家人能进);
你的好朋友(友元函数void friendFun(MyHome &h))可以进你的卧室(访问私有成员),但好朋友的朋友不能进(友元关系不传递);
好朋友只能进你家,不能进你邻居家(友元只针对特定类)。
线程进程,并发 gc
缓冲区有什么好处?
- 一、最核心:IO 流中用缓冲区,减少磁盘 / 网络 IO 次数
- 二、减少资源开销:避免频繁创建 / 销毁临时对象
java四个整数类型?
- 按取值范围从小到大依次是 byte、short、int、long,核心区别在于占用内存空间(二进制位数)和取值范围不同
线程优先级?
- Java 线程优先级范围是 1~10,规则如下:
最高优先级:10(Thread.MAX_PRIORITY);
最低优先级:1(Thread.MIN_PRIORITY);
默认优先级:5(Thread.NORM_PRIORITY),子线程默认继承父线程的优先级(不是最低的 1)。 - 优先级高的线程 “优先获得 CPU 调度”,但不是绝对(受操作系统调度影响,不能依赖优先级保证执行顺序)。
GC机制
三者的内存管理差异本质是“开发效率”与“性能/控制度”的权衡——Java 和 Go 牺牲部分性能换取开发效率,C++ 牺牲开发效率换取极致性能和控制能力。
| 对比维度 | Java | Go | C++ |
|---|---|---|---|
| 是否有内置 GC | 有(自动垃圾回收) | 有(自动垃圾回收) | 无(需手动管理或依赖第三方库) |
| GC 核心机制 | 分代收集(新生代用复制算法,老年代用标记-清除/整理),采用“Stop-The-World”(STW)+ 并发收集结合的方式(如 G1、ZGC 等)。 | 三色标记法 + 写屏障,采用“非分代”设计,STW 时间极短(微秒级),适合高并发场景。 | 无内置 GC,需开发者通过 new/delete、malloc/free 手动分配和释放内存。 |
| 内存管理责任 | 开发者无需手动释放内存,只需关注对象创建,GC 自动回收不再被引用的对象。 | 开发者无需手动释放内存,GC 自动回收“不可达”的内存(通过逃逸分析优化,栈上分配减少 GC 压力)。 | 开发者必须手动释放已分配的内存,否则会导致内存泄漏;释放后再次访问会导致“野指针”错误。 |
| 开发效率 | 高:无需关注内存释放,减少手动操作错误(如内存泄漏、野指针)。 | 高:自动 GC 减少手动管理成本,同时 GC 性能优化较好,兼顾开发效率和运行效率。 | 低:需手动处理内存生命周期,增加代码复杂度,容易因疏忽导致内存问题。 |
| 运行时性能 | 中等:GC 有一定性能开销(STW 可能导致短暂停顿,现代 GC 已大幅优化)。 | 高:GC 设计轻量,STW 时间短,适合高性能服务(如微服务、中间件)。 | 极高:无 GC 开销,内存操作直接可控,适合对性能极致要求的场景(如游戏引擎、实时系统)。 |
| 灵活性 | 低:内存管理完全由 JVM 控制,开发者无法直接干预(如强制释放对象)。 | 中:支持手动调用 runtime.GC() 触发 GC,但不推荐;通过逃逸分析等机制优化内存分配。 | 极高:开发者可完全控制内存分配方式(栈/堆、内存池、自定义分配器等)。 |
| 典型内存问题 | 内存泄漏(如长生命周期集合持有短生命周期对象引用)、OOM(内存溢出)。 | 内存泄漏(如 goroutine 泄漏、未关闭的资源)、GC 压力过大(频繁创建大对象)。 | 内存泄漏(忘记 delete)、野指针(访问已释放内存)、二次释放(重复 delete)。 |
| 适用场景 | 企业级应用、Web 服务、Android 开发等(优先开发效率和稳定性)。 | 云原生服务、微服务、高并发后端(平衡开发效率和性能)。 | 系统级开发、游戏引擎、实时通信(优先性能和底层控制)。 |
异常处理,受检&非受检
java的异常,如果没有被捕获到,会怎么样
- 未捕获的异常会导致线程终止,若发生在主线程则整个程序崩溃,同时 JVM 会输出异常详情用于调试。因此,实际开发中应尽量捕获可预见的异常,或通过 throws 显式声明,避免程序意外终止。
- Go 语言的错误处理设计与 Java 有本质区别,核心原因在于两者对 “错误” 和 “异常” 的定义、处理哲学完全不同。这种差异导致了 Go 中程序很少因错误终止,而更倾向于通过 error 向上传递,而 panic 仅作为 “真正异常情况” 的处理机制。
- Go 语言通过 error 显式传递预期错误,强制开发者处理;通过 panic 处理致命异常,并允许 recover 恢复,这种设计使得程序更稳定(很少因预期内错误终止),同时让错误处理逻辑更清晰。而 Java 的异常机制更倾向于 “隐式传播”,将各类问题统一为 “异常”,因此未捕获时容易导致程序终止。两者的差异本质上是设计哲学的不同:Go 强调 “显式、可控”,Java 强调 “统一、便捷”。
java的异常处理
- Java 异常绝非 “写死的”,其自定义机制完全能应对复杂业务场景。开发者可以通过继承 Exception 或 RuntimeException,定义包含错误码、消息甚至业务数据的异常类,实现对 “千奇百怪” 业务异常的精确区分和处理。
- 在 Java 业务项目中,异常处理需要兼顾 “精准处理” 和 “兜底保障”,同时平衡受检异常(Checked Exception)和非受检异常(Unchecked Exception,如 RuntimeException)的处理逻辑。
- 非受检异常(RuntimeException):业务异常通常基于它扩展,通过顶层全局处理器兜底捕获,确保不遗漏。
- 受检异常:编译期强制处理,可通过 throws 传递到顶层统一处理,无需逐个捕获,常见类型集中在 IO、数据库等外部交互场景。
- 项目中通过 “分层传递 + 顶层兜底” 的模式,既能精准处理特定异常,又能保障整体稳定性,这是 Java 业务项目的主流实践。
常见的受检异常(JDK 内置)
| 异常类 | 含义 | 典型场景 |
|---|---|---|
IOException | IO 操作异常(父类) | 文件读写、网络流操作 |
FileNotFoundException | 文件未找到(IOException 的子类) | 读取不存在的文件 |
SQLException | 数据库操作异常 | SQL 执行错误、连接失败 |
ClassNotFoundException | 类未找到 | 反射加载类时类路径错误 |
InterruptedException | 线程中断异常 | 调用 Thread.sleep() 时线程被中断 |
ParseException | 解析异常(如日期解析) | SimpleDateFormat.parse() 失败 |
IOException 的其他子类 | 如 EOFException(文件结束)、SocketException(网络套接字错误)等 | 细分 IO 场景的错误 |
// 自定义业务异常基类(继承 RuntimeException,非受检,方便传递)
public class BusinessException extends RuntimeException {private int code; // 错误码(如 1001:余额不足,1002:权限不足)public BusinessException(int code, String message) {super(message);this.code = code;}// getter/setter
}// 具体业务异常(可选,更细分)
public class InsufficientBalanceException extends BusinessException {public InsufficientBalanceException() {super(1001, "用户余额不足");}
}public class PermissionDeniedException extends BusinessException {public PermissionDeniedException(String message) {super(1002, message); // 支持自定义消息}
}public void deductBalance(User user, int amount) {if (user.getBalance() < amount) {throw new InsufficientBalanceException(); // 抛出具体业务异常}// 正常扣减逻辑
}try {deductBalance(user, 100);
} catch (InsufficientBalanceException e) {log.error("扣减失败:{}", e.getMessage());return "余额不足,请充值";
} catch (PermissionDeniedException e) {log.error("权限错误:{}", e.getMessage());return "无操作权限";
} catch (BusinessException e) { // 捕获所有业务异常(兜底)log.error("业务错误({}):{}", e.getCode(), e.getMessage());return "操作失败";
}
这种设计体现了 Java 异常处理的核心原则:受检异常强制显式处理,运行时异常允许隐式传播,既保证了可预期错误的处理,又保留了灵活性。
-
throws声明的作用:- 仅用于受检异常,强制调用者处理或继续传递。
- 运行时异常无需声明,会自动传播。
-
未声明的异常处理:
- 未声明的受检异常:编译报错(必须捕获或声明)。
- 未声明的运行时异常:编译通过,运行时传播,若未被捕获则导致程序终止。
| 类型 | 本质 | 处理原则 | 核心目的 |
|---|---|---|---|
| 受检异常 | 可预期的外部环境问题 | 必须显式处理(捕获或声明抛出) | 强制开发者面对可预期的错误 |
| 非受检异常 | 不可预期的编程错误或致命错误 | 优先通过代码逻辑避免,必要时顶层兜底处理 | 提示开发者修复代码中的 bug |
注解和框架,spring,Ioc,AOP
注解的本质:Java 语法层面的 “元数据”
- Java 中的 @ 符号表示注解(Annotation),它是 Java 语言层面的语法特性(JDK 1.5 引入),而非框架专属。但注解的强大之处在于能被框架利用来实现 “声明式编程”,简化代码逻辑。Spring 等框架大量使用注解,本质上是借助 Java 的语法特性实现 “配置与代码的分离”“行为的增强” 等功能。
- 注解(Annotation)本身不直接影响代码执行,而是作为元数据(描述数据的数据) 附加在类、方法、字段等元素上。
告诉编译器或框架 “这个元素具有某种特性”。
框架可以通过反射读取这些元数据,动态赋予元素额外的行为(如权限校验、事务管理等)。
Spring 中注解的核心作用:简化开发,实现 “声明式编程”
-
Spring 框架的核心是依赖注入(DI) 和面向切面编程(AOP),而注解是实现这两个功能的 “语法糖”,让开发者无需编写复杂配置,只需通过注解 “声明” 即可完成功能。
-
1、标识组件:让框架自动管理对象(依赖注入 DI)
传统 Java 开发中,对象的创建和依赖关系需要手动 new 或通过 XML 配置,而 Spring 通过注解让对象成为 “容器管理的组件”,自动完成创建和注入。
@Component:通用组件标识(如工具类、服务类)。
@Service:标识业务逻辑层(Service)组件(语义更清晰,本质和 @Component 一样)。
@Repository:标识数据访问层(DAO)组件(框架会自动处理数据库异常转换)。
@Controller / @RestController:标识 Web 层(Controller)组件(处理 HTTP 请求)。 -
2、声明行为:通过注解附加功能(面向切面 AOP)
AOP 的核心是 “在不修改原有代码的情况下,给方法附加额外行为”(如事务、日志、权限校验)。Spring 通过注解让开发者 “声明” 需要附加的功能。
@Transactional:声明方法需要事务管理(框架自动开启、提交 / 回滚事务)。
@RequestMapping / @GetMapping:声明 Controller 方法处理的 HTTP 请求路径和方式。
@PreAuthorize:声明方法的访问权限(如 “必须有 ADMIN 角色才能调用”)。 -
3、配置替代:用注解代替 XML 配置
早期 Spring 大量使用 XML 配置(如 applicationContext.xml),而注解可以直接在代码中声明配置,更直观。
@Configuration:标识配置类(替代 XML 配置文件)。
@Bean:在配置类中声明一个对象(替代 XML 中的 标签)。
@Value:注入配置文件中的属性(如 @Value(“${server.port}”) 读取端口配置)。
必须掌握的核心注解(按场景分类)
- Spring 核心(IoC 容器)
@Component:标识普通组件,让 Spring 自动扫描并纳入 IoC 容器管理。@Service:标识业务层(Service)组件(语义化注解,本质同@Component)。@Repository:标识数据访问层(DAO)组件(会自动处理数据库异常转换)。@Controller:标识 Web 层(MVC 中的控制器)组件,处理 HTTP 请求。@RestController:@Controller + @ResponseBody的组合,直接返回 JSON 数据(RESTful API 常用)。@Autowired:自动注入依赖(默认按类型匹配,配合@Qualifier按名称匹配)。@Resource:JDK 自带的依赖注入注解(按名称匹配,与@Autowired功能类似)。@Configuration:标识配置类(替代 XML 配置文件)。@Bean:在配置类中声明一个 Bean 对象(由 Spring 管理)。
- Spring Boot 核心(简化配置)
@SpringBootApplication:Spring Boot 应用入口注解,包含@Configuration、@EnableAutoConfiguration(自动配置)、@ComponentScan(组件扫描)。@EnableAutoConfiguration:开启自动配置(根据依赖 jar 包自动生成配置,如引入spring-boot-starter-web则自动配置 Tomcat、Spring MVC)。@ComponentScan:指定 Spring 扫描组件的路径(默认扫描当前类所在包及子包)。@Value:注入配置文件(如application.yml)中的属性(如@Value("${server.port}"))。@ConfigurationProperties:将配置文件中的属性批量绑定到 Java 类(如@ConfigurationProperties(prefix = "user")绑定user.name、user.age等)。
- Spring MVC 与 Web 开发
@RequestMapping:映射 HTTP 请求(支持指定 URL、请求方法、参数等),可用于类或方法上。@GetMapping/@PostMapping/@PutMapping/@DeleteMapping:简化的@RequestMapping,分别对应 GET/POST/PUT/DELETE 请求方法。@PathVariable:获取 URL 路径中的参数(如/user/{id}中的id)。@RequestParam:获取 HTTP 请求参数(如/user?name=xxx中的name)。@RequestBody:接收 HTTP 请求体中的 JSON 数据(常用于 POST/PUT 请求)。@ResponseBody:将方法返回值直接转为 JSON 响应(@RestController已包含此注解)。
- 事务与数据访问
@Transactional:声明方法需要事务管理(Spring 自动处理事务的开启、提交/回滚),可指定事务隔离级别、传播行为等。@Repository:前文已提,数据访问层专用,与 MyBatis、JPA 等配合使用。
- Spring Cloud 微服务核心
@EnableEurekaClient/@EnableDiscoveryClient:声明当前服务是服务注册中心(如 Eureka)的客户端,用于服务发现。@LoadBalanced:标识 RestTemplate 支持负载均衡(配合 Ribbon 或 Spring Cloud LoadBalancer)。@FeignClient:声明 Feign 客户端(用于微服务间的接口调用,简化 HTTP 通信)。@EnableFeignClients:开启 Feign 客户端功能。@EnableCircuitBreaker/@CircuitBreaker:开启熔断降级功能(配合 Resilience4j 或 Hystrix)。@EnableConfigServer:声明当前服务是配置中心服务器(Spring Cloud Config)。@RefreshScope:声明配置动态刷新(当配置中心的配置更新时,无需重启服务即可生效)。
Spring Cloud 框架下的项目结构(典型微服务架构)
parent-project/ # 父工程(Maven/Gradle 聚合工程)
├── pom.xml # 统一管理依赖版本(如 Spring Cloud、Spring Boot 版本)
├── api-gateway/ # 网关服务(如 Spring Cloud Gateway)
├── service-registry/ # 服务注册中心(如 Eureka Server)
├── config-server/ # 配置中心服务(如 Spring Cloud Config)
├── user-service/ # 用户服务(业务服务1)
├── order-service/ # 订单服务(业务服务2)
├── product-service/ # 商品服务(业务服务3)
└── common/ # 公共模块(工具类、通用注解、实体类等)
单个业务服务的内部结构(以 user-service 为例)
user-service/
├── src/main/java/com/example/user/
│ ├── UserApplication.java # 服务入口类(标注 @SpringBootApplication、@EnableEurekaClient 等)
│ ├── config/ # 配置类
│ │ ├── FeignConfig.java # Feign 客户端配置
│ │ └── WebConfig.java # Spring MVC 配置(如拦截器、跨域等)
│ ├── controller/ # 控制器层(接收请求,调用 Service)
│ │ └── UserController.java # 标注 @RestController、@GetMapping 等
│ ├── service/ # 业务逻辑层
│ │ ├── UserService.java # 接口
│ │ └── impl/UserServiceImpl.java # 实现类(标注 @Service、@Transactional 等)
│ ├── dao/ # 数据访问层(与数据库交互)
│ │ └── UserMapper.java # MyBatis 接口或 JPA Repository
│ ├── entity/ # 实体类(如 User、UserDTO 等)
│ ├── feign/ # Feign 客户端(调用其他服务)
│ │ └── OrderFeignClient.java # 标注 @FeignClient("order-service")
│ └── exception/ # 异常处理
│ ├── GlobalExceptionHandler.java # 全局异常处理器(@RestControllerAdvice)
│ └── BusinessException.java # 自定义业务异常
├── src/main/resources/
│ ├── application.yml # 服务配置(端口、服务名、注册中心地址等)
│ └── bootstrap.yml # 启动配置(优先加载,用于配置中心连接等)
└── pom.xml # 服务依赖(引入 spring-cloud-starter-netflix-eureka-client 等)
注解本质上
- 就是通过 “标记” 让框架在方法前后(或其他时机)自动插入通用逻辑,而且你完全可以自己实现自定义注解。
- 标记 + 通用逻辑注入你说 “在函数前和函数后做一些通用固定的东西”,这正是注解最常见的应用场景(如日志、事务、权限校验等)。更准确地说,注解是 “元数据标记”,框架通过解析这些标记,在特定时机(如方法调用前 / 后、对象创建时)执行预设的通用逻辑。
控制对象创建(如 @Bean 告诉 Spring 这是一个需要管理的对象);
配置参数绑定(如 @Value 读取配置文件);
编译期检查(如 @Override 让编译器验证方法重写是否正确)。
| 概念 | 核心作用 | 与 k8s/Docker 的类比 | 解决的痛点 |
|---|---|---|---|
| 依赖注入(DI) | 框架管理对象创建和依赖绑定 | 类似 k8s 管理容器的创建、调度和依赖关系 | 硬编码依赖导致的耦合问题 |
| 面向切面编程(AOP) | 通用逻辑抽离并动态植入目标代码 | 类似容器的共享基础设施(如 Sidecar)自动附加功能 | 通用逻辑与业务逻辑混杂问题 |
2、1个项目回顾Java基础语法(程序题)
13215-Java语言程序设计
04747-Java
javac *.java
javac ThreadDemo.java
java ThreadDemoTestJavaExam/
├─ src/
│ ├─ Main.java // 主程序入口,整合所有模块调用
│ ├─ BasicSyntax.java // 模块1:基础语法(标识符、流程控制、数组)
│ ├─ OOP.java // 模块2:面向对象(类、继承、抽象类、接口)
│ ├─ ExceptionHandle.java // 模块3:异常处理(try-catch、受检/运行时异常)
│ ├─ IOStream.java // 模块4:IO流(字节流、字符流、对象流)
│ ├─ SwingGUI.java // 模块5:Swing图形界面(组件、布局、事件监听)
│ └─ ThreadDemo.java // 模块6:线程(创建、同步)
└─ README.md // 项目说明(考点对应关系)
Main.java
/*** Java核心考点整合项目 - 主程序* 考点1:Java程序入口必须是main()方法,格式固定:public static void main(String[] args)* 考点2:main()方法是静态方法(static修饰),无需实例化对象即可调用* 将所有.java 文件放在同一目录,用javac *.java编译,再用java Main运行,观察控制台输出和 Swing 窗口效果。*/
public class Main {public static void main(String[] args){}public static void main(String[] args) {// 调用各模块,逐个验证考点System.out.println("=== 1. 基础语法模块 ===");BasicSyntax.testBasic(); // 基础语法:标识符、循环、数组System.out.println("\n=== 2. 面向对象模块 ===");OOP.testOOP(); // 类、继承、抽象类、接口System.out.println("\n=== 3. 异常处理模块 ===");ExceptionHandle.testException(); // try-catch、受检异常System.out.println("\n=== 4. IO流模块 ===");IOStream.testIO(); // 字节流、字符流、文件操作System.out.println("\n=== 5. SwingGUI模块 ===");SwingGUI.testGUI(); // 组件、布局、事件监听System.out.println("\n=== 6. 线程模块 ===");ThreadDemo.testThread(); // 线程创建、同步}
}
1、BasicSyntax.java
import java.util.Scanner;/*** 模块1:基础语法(覆盖80%基础考点)* 考点1:标识符规则:字母/下划线/$开头,含字母/数字/下划线/$,不关键字(如int、class)* 考点2:转义字符:\n(换行)、\t(制表)、\r(回车)* 考点3:流程控制:for循环(嵌套)、while循环、switch(仅支持int/char)* 考点4:数组:静态初始化(new int[]{1,2,3})、动态初始化(new int[3]),数组长度用length属性*/
public class BasicSyntax {// 考点1:静态方法(static修饰),属于类,通过类名调用public static void testBasic() {// 1. 标识符示例(合法:userName、_age、$salary;非法:123num、int)String userName = "考生"; // 合法标识符int _age = 20; // 合法标识符System.out.println("标识符示例:userName=" + userName + ", _age=" + _age);// 2. 转义字符示例System.out.println("转义字符:\t制表符\t换行符\n后的内容");// 3. 流程控制:for循环嵌套(乘法口诀表,高频程序题)System.out.println("for循环嵌套(乘法口诀表):");for (int i = 1; i <= 9; i++) { // 外层循环:行数for (int j = 1; j <= i; j++) { // 内层循环:列数System.out.print(j + "*" + i + "=" + (i*j) + "\t");}System.out.println(); // 换行}// 4. 数组:动态初始化+遍历(填空题高频)int[] arr = new int[5]; // 动态初始化:指定长度,默认值0for (int i = 0; i < arr.length; i++) { // 数组长度:arr.lengtharr[i] = i * 2; // 赋值:0,2,4,6,8}System.out.println("数组遍历:");for (int num : arr) { // 增强for循环(foreach)System.out.print(num + " ");}// 5. switch语句(仅支持int/char,单选题考点)char grade = 'B';switch (grade) {case 'A':System.out.println("\nswitch:优秀");break; // 必须break,否则穿透case 'B':System.out.println("\nswitch:良好");break;default:System.out.println("\nswitch:及格");}}
}
2、OOP.java、student_manager.cpp
/*** 模块2:面向对象(核心,占分30%+)* 考点1:类与对象:类是模板,对象是实例;构造方法与类名相同,无返回值,默认无参构造* 考点2:this关键字:指代当前对象,用于区分成员变量与局部变量* 考点3:继承:单重继承(extends),Object是所有类的根类(单选题高频)* 考点4:super关键字:调用父类构造(必须在子类构造第一行)、调用父类方法* 考点5:方法重写:子类方法与父类同名+同参数列表,访问权限≥父类,返回值兼容* 考点6:抽象类:abstract修饰,含抽象方法(无方法体),不能实例化(单选题考点)* 考点7:接口:全是抽象方法(默认public abstract),类可实现多个接口(implements)*/
// 考点3:继承示例:Animal是父类,Dog是子类(单重继承)
class Animal {// 成员变量(考点1:类的属性)protected String name; // protected:子类可访问,同包其他类可访问// 考点1:构造方法(无参)public Animal() {System.out.println("Animal无参构造(父类)");}// 考点1:构造方法(有参)public Animal(String name) {this.name = name; // 考点2:this区分成员变量与局部变量System.out.println("Animal有参构造:name=" + name);}// 普通方法(考点5:可被重写)public void eat() {System.out.println(name + "吃食物");}
}// 考点3:子类继承父类(extends)
class Dog extends Animal {private int age; // private:仅本类可访问// 考点4:子类构造调用父类构造(super必须在第一行)public Dog(String name, int age) {super(name); // 调用父类有参构造this.age = age;System.out.println("Dog构造:age=" + age);}// 考点5:方法重写(与父类eat()同名+同参数列表)@Override // 注解:验证重写正确性public void eat() {super.eat(); // 考点4:调用父类方法System.out.println(name + "吃骨头(子类重写)");}// 子类特有方法public void bark() {System.out.println(name + "汪汪叫");}
}// 考点6:抽象类(abstract修饰,不能实例化)
abstract class Shape {// 考点6:抽象方法(无方法体,必须被子类实现)public abstract double getArea();
}// 抽象类子类:必须实现抽象方法
class Circle extends Shape {private double radius;public Circle(double radius) {this.radius = radius;}// 实现抽象方法@Overridepublic double getArea() {return 3.14 * radius * radius; // 圆面积公式}
}// 考点7:接口(全是抽象方法)
interface Runable {// 考点7:接口方法默认public abstract(可省略)void run();
}// 类实现接口(implements)
class Person implements Runable {private String name;public Person(String name) {this.name = name;}// 必须实现接口的抽象方法@Overridepublic void run() {System.out.println(name + "在跑步(接口实现)");}
}// 测试类
public class OOP {public static void testOOP() {// 1. 测试继承与方法重写Dog dog = new Dog("旺财", 3);dog.eat(); // 调用重写后的eat()dog.bark();// 2. 测试抽象类(不能实例化Shape,只能实例化子类Circle)Shape circle = new Circle(5); // 考点6:抽象类多态System.out.println("圆面积:" + circle.getArea());// 3. 测试接口Runable person = new Person("小明");person.run();// 考点3:Object是根类(所有类默认继承Object)System.out.println("Dog是否是Object子类:" + (dog instanceof Object)); // true}
}
student_manager.cpp
// 1. 包含考试高频头文件(<iostream>输入输出、<fstream>文件操作、<string>字符串、<algorithm>排序)
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
using namespace std;// 2. 定义基类:Person(考查类的定义、访问权限、构造函数)
// 知识点:类是对象的抽象,包含成员变量(属性)和成员函数(操作),默认访问权限为private
class Person {
protected: // 保护成员:派生类可访问,外部不可访问(继承考点)string name; // 姓名int id; // 编号(学生/教师共用)public:// 知识点:构造函数(与类名相同、无返回值、可重载)// 无参构造(默认构造):无自定义构造时系统自动生成,此处显式定义Person() : name("未知"), id(0) {}// 带参构造:初始化列表赋值(比函数体内赋值更高效)Person(string n, int i) : name(n), id(i) {}// 知识点:普通成员函数(非静态、非虚函数)void setName(string n) { name = n; }void setId(int i) { id = i; }string getName() const { return name; } // const成员函数:不修改成员变量(考点)int getId() const { return id; }
};// 3. 定义派生类:Student(继承Person)(考查继承、派生类构造、重定义)
// 知识点:公有继承(public):基类public成员→派生类public,protected→protected
class Student : public Person {
private:int score; // 学生特有属性:成绩static int totalStudents; // 静态成员:所有对象共享,统计学生总数(考点)public:// 知识点:派生类构造函数:必须调用基类构造(初始化列表中指定)Student() : Person(), score(0) { totalStudents++; }Student(string n, int i, int s) : Person(n, i), score(s) { totalStudents++; }// 知识点:析构函数(~类名、仅1个、释放资源)~Student() { totalStudents--; } // 静态成员计数减1// 知识点:成员函数重定义(派生类修改基类行为,非虚函数→静态绑定)void setScore(int s) { if (s >= 0 && s <= 100) score = s; // 数据合法性校验else cout << "成绩输入错误(0-100)!" << endl;}int getScore() const { return score; }// 知识点:静态成员函数(无this指针,只能访问静态成员)static int getTotalStudents() { return totalStudents; }// 知识点:友元函数(破坏封装性,可访问私有成员,用于输出学生信息)(考点)friend ostream& operator<<(ostream& os, const Student& stu);
};// 知识点:静态成员初始化(必须在类外,格式:类型 类名::成员名=初始值)
int Student::totalStudents = 0;// 4. 定义抽象类:SortStrategy(考查纯虚函数、抽象类)(考点)
// 知识点:抽象类:含纯虚函数(virtual 函数=0),不能实例化,仅作为基类
class SortStrategy {
public:// 纯虚函数:无实现,由派生类重写(多态考点)virtual bool compare(const Student& s1, const Student& s2) = 0;// 虚析构函数:基类指针指向派生类对象时,确保派生类析构被调用(考点)virtual ~SortStrategy() {}
};// 5. 定义排序策略派生类(考查多态、动态绑定)
// 策略1:按成绩降序排序
class SortByScoreDesc : public SortStrategy {
public:// 知识点:重写纯虚函数(函数签名完全一致)bool compare(const Student& s1, const Student& s2) override {return s1.getScore() > s2.getScore();}
};// 策略2:按学号升序排序
class SortByAsc : public SortStrategy {
public:bool compare(const Student& s1, const Student& s2) override {return s1.getId() < s2.getId();}
};// 6. 定义工具类:StudentManager(考查组合、文件操作、模板)
class StudentManager {
private:Student students[100]; // 学生数组(固定大小,实际可改用动态数组)int count; // 当前学生数量SortStrategy* sortStrategy; // 组合排序策略(依赖抽象类,符合开闭原则)public:StudentManager() : count(0), sortStrategy(nullptr) {}~StudentManager() {delete sortStrategy; // 释放排序策略对象(避免内存泄漏)}// 知识点:文件写入(ofstream、ios::out模式)(考点)void saveToFile(const string& filename) {ofstream outFile(filename, ios::out); // 以输出模式打开文件(覆盖原有内容)if (!outFile) { // 判断文件是否成功打开cout << "文件" << filename << "打开失败!" << endl;return;}// 写入学生总数outFile << count << endl;// 循环写入每个学生信息for (int i = 0; i < count; i++) {outFile << students[i].getId() << " " << students[i].getName() << " " << students[i].getScore() << endl;}outFile.close(); // 关闭文件(必须调用,确保缓冲区数据写入)cout << "成功保存" << count << "条学生数据到" << filename << endl;}// 知识点:文件读取(ifstream、ios::in模式)(考点)void loadFromFile(const string& filename) {ifstream inFile(filename, ios::in); // 以输入模式打开文件if (!inFile) {cout << "文件" << filename << "不存在!" << endl;return;}// 读取学生总数inFile >> count;// 循环读取每个学生信息for (int i = 0; i < count; i++) {int id, score;string name;inFile >> id >> name >> score;students[i].setId(id); students[i].setName(name);students[i].setScore(score);}inFile.close();cout << "成功从" << filename << "读取" << count << "条学生数据" << endl;}// 知识点:添加学生(对象数组操作)void addStudent(const Student& stu) {if (count >= 100) {cout << "学生数量已达上限(100人)!" << endl;return;}students[count++] = stu;cout << "成功添加学生:" << stu.getName() << endl;}// 知识点:排序(调用策略类的compare,动态多态)void sortStudents(SortStrategy* strategy) {if (count == 0) {cout << "无学生数据可排序!" << endl;return;}// 释放原有策略if (sortStrategy != nullptr) delete sortStrategy;sortStrategy = strategy;// 调用algorithm库的sort函数(第三个参数为比较规则)// sort(students, students + count, // [this](const Student& s1, const Student& s2) {// return sortStrategy->compare(s1, s2);// });cout << "排序完成!" << endl;}// 知识点:模板函数(泛型编程,支持不同类型查询)(考点)template <typename T>void searchStudent(T key, string type) {bool found = false;cout << "查询结果:" << endl;for (int i = 0; i < count; i++) {if ((type == "id" && students[i].getId() == key) || (type == "score" && students[i].getScore() == key)) {cout << "学号:" << students[i].getId() << " 姓名:" << students[i].getName() << " 成绩:" << students[i].getScore() << endl;found = true;}}if (!found) cout << "未找到符合条件的学生!" << endl;}// 显示所有学生void showAllStudents() {if (count == 0) {cout << "暂无学生数据!" << endl;return;}cout << "当前学生总数:" << Student::getTotalStudents() << endl;cout << "学号\t姓名\t成绩" << endl;for (int i = 0; i < count; i++) {cout << students[i].getId() << "\t" << students[i].getName() << "\t" << students[i].getScore() << endl;}}
};// 7. 实现友元函数(输出运算符重载)(考点)
// 知识点:运算符重载(非成员函数,参数为ostream&和对象引用)
ostream& operator<<(ostream& os, const Student& stu) {os << "学号:" << stu.getId() << " 姓名:" << stu.getName() << " 成绩:" << stu.getScore();return os;
}// 8. 主函数(程序入口,测试所有功能)
int main() {StudentManager manager;int choice;while (true) {// 菜单界面cout << "\n===== 学生成绩管理系统 =====" << endl;cout << "1. 添加学生" << endl;cout << "2. 显示所有学生" << endl;cout << "3. 按成绩降序排序" << endl;cout << "4. 按学号升序排序" << endl;cout << "5. 查找学生(按学号)" << endl;cout << "6. 查找学生(按成绩)" << endl;cout << "7. 保存数据到文件" << endl;cout << "8. 从文件加载数据" << endl;cout << "0. 退出系统" << endl;cout << "请输入选择:";cin >> choice;switch (choice) {case 1: {// 添加学生string name;int id, score;cout << "请输入学生姓名:";cin >> name;cout << "请输入学生学号:";cin >> id;cout << "请输入学生成绩:";cin >> score;Student stu(name, id, score);manager.addStudent(stu);break;}case 2:// 显示所有学生manager.showAllStudents();break;case 3:// 按成绩降序排序(多态:传入SortByScoreDesc对象)manager.sortStudents(new SortByScoreDesc());break;case 4:// 按学号升序排序(多态:传入SortByAsc对象)manager.sortStudents(new SortByAsc());break;case 5: {// 按学号查找(模板函数调用)int id;cout << "请输入要查找的学号:";cin >> id;manager.searchStudent(id, "id");break;}case 6: {// 按成绩查找(模板函数调用)int score;cout << "请输入要查找的成绩:";cin >> score;manager.searchStudent(score, "score");break;}case 7:// 保存数据到文件manager.saveToFile("student_scores.txt");break;case 8:// 从文件加载数据manager.loadFromFile("student_scores.txt");break;case 0:// 退出系统cout << "退出系统成功!" << endl;return 0;default:cout << "输入错误,请重新选择!" << endl;}}
}
3、ExceptionHandle.java
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;/*** 模块3:异常处理(必考点,占分15%)* 考点1:异常分类:* - 受检异常(Checked):必须处理(try-catch/throws),如IOException、FileNotFoundException* - 运行时异常(Unchecked):无需处理,如NullPointerException、ArrayIndexOutOfBoundsException* 考点2:异常处理机制:try(监控代码)→ catch(捕获异常)→ finally(可选,必执行,释放资源)* 考点3:throws关键字:声明方法可能抛出的异常,由调用者处理* 考点4:常见异常:* - FileNotFoundException:文件未找到(受检)* - ArrayIndexOutOfBoundsException:数组下标越界(运行时)*/
public class ExceptionHandle {// 考点3:throws声明方法抛出受检异常(FileNotFoundException、IOException)public static void readFile(String fileName) throws FileNotFoundException, IOException {// 考点2:try块:监控可能抛出异常的代码FileInputStream fis = new FileInputStream(fileName); // 可能抛FileNotFoundExceptionint data;while ((data = fis.read()) != -1) { // 可能抛IOException(读文件异常)System.out.print((char) data);}fis.close(); // 关闭流,释放资源}public static void testException() {// 1. 测试受检异常处理(try-catch)try {readFile("test.txt"); // 调用可能抛异常的方法} catch (FileNotFoundException e) { // 捕获“文件未找到”异常System.out.println("受检异常:文件未找到→" + e.getMessage());} catch (IOException e) { // 捕获“IO读异常”System.out.println("受检异常:读文件错误→" + e.getMessage());} finally {System.out.println("finally块:无论是否异常,必执行(释放资源)");}// 2. 测试运行时异常(无需try-catch,运行时抛出)int[] arr = new int[3];try {System.out.println(arr[5]); // 数组下标越界(ArrayIndexOutOfBoundsException)} catch (ArrayIndexOutOfBoundsException e) {System.out.println("运行时异常:数组下标越界→" + e.getMessage());}// 3. 测试NullPointerException(运行时异常)String str = null;try {System.out.println(str.length()); // str为null,调用方法抛异常} catch (NullPointerException e) {System.out.println("运行时异常:空指针→" + e.getMessage());}}
}
4、IOStream.java
import java.io.*;/*** 模块4:IO流(高频,占分20%)* 考点1:IO流分类:* - 字节流:InputStream(读)、OutputStream(写),处理字节(如图片、文件)* - 字符流:Reader(读)、Writer(写),处理字符(如文本)* - 缓冲流:BufferedReader(按行读)、BufferedWriter(按行写),提高效率* - 对象流:ObjectInputStream/ObjectOutputStream,实现对象序列化(单选题高频)* 考点2:FileInputStream/FileOutputStream:字节流操作文件* 考点3:BufferedReader的readLine():按行读取文本,返回null表示读结束* 考点4:对象序列化:类必须实现Serializable接口(标记接口,无方法)* 考点5:File类:操作文件属性(如length()获取文件长度,填空题考点)*/
// 考点4:可序列化的类(必须实现Serializable)
class Student implements Serializable {private String name;private int age;public Student(String name, int age) {this.name = name;this.age = age;}// 重写toString(),方便输出@Overridepublic String toString() {return "Student{name='" + name + "', age=" + age + "}";}
}public class IOStream {// 1. 测试字节流:复制文件(程序填空题高频)public static void copyFile(String srcPath, String destPath) {FileInputStream fis = null;FileOutputStream fos = null;try {// 考点2:创建字节流对象fis = new FileInputStream(srcPath);fos = new FileOutputStream(destPath);byte[] buf = new byte[10]; // 缓冲区,提高效率int len;// 考点2:read()读字节到缓冲区,返回-1表示读结束while ((len = fis.read(buf)) != -1) {fos.write(buf, 0, len); // 写缓冲区数据(0到len字节)}System.out.println("字节流:文件复制完成");} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {// 释放资源(必做,避免内存泄漏)try {if (fos != null) fos.close();if (fis != null) fis.close();} catch (IOException e) {e.printStackTrace();}}}// 2. 测试字符流:按行读文本(程序分析题高频)public static void readTextByLine(String filePath) {BufferedReader br = null;try {// 考点3:BufferedReader(字符缓冲流),包装FileReaderbr = new BufferedReader(new FileReader(filePath));String line;// 考点3:readLine()按行读,null表示结束while ((line = br.readLine()) != null) {System.out.println("字符流读行:" + line);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} finally {try {if (br != null) br.close();} catch (IOException e) {e.printStackTrace();}}}// 3. 测试对象流:序列化与反序列化(单选题高频)public static void serializeObject() {// 序列化:对象→字节流写入文件try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("student.ser"))) {Student stu = new Student("张三", 20);oos.writeObject(stu); // 写对象System.out.println("对象流:序列化完成");} catch (IOException e) {e.printStackTrace();}// 反序列化:字节流→对象try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("student.ser"))) {Student stu = (Student) ois.readObject(); // 读对象(需强转)System.out.println("对象流:反序列化结果→" + stu);} catch (IOException | ClassNotFoundException e) {e.printStackTrace();}}// 4. 测试File类(考点5:文件属性操作)public static void testFile() {File file = new File("test.txt");if (file.exists()) { // 判断文件是否存在System.out.println("File类:文件名=" + file.getName());System.out.println("File类:文件路径=" + file.getPath());System.out.println("File类:文件长度=" + file.length() + "字节"); // 考点5:length()} else {System.out.println("File类:文件不存在");}}// 统一测试public static void testIO() {// 注意:实际运行需确保test.txt存在(可手动创建,写入几行文本)String testTxt = "test.txt";String copyTxt = "test_copy.txt";testFile(); // 测试File类readTextByLine(testTxt); // 测试字符流copyFile(testTxt, copyTxt); // 测试字节流serializeObject(); // 测试对象流}// 添加main方法,作为程序入口,调用testIO()// public static void main(String[] args) {// testIO(); // 直接调用测试方法// }
}
5、SwingGUI.java
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;/*** 模块5:Swing图形界面(必考,占分15%)* 考点1:Swing组件:* - 顶层容器:JFrame(窗口,必须有)、JDialog(对话框)* - 中间容器:JPanel(面板,默认FlowLayout布局)* - 元素组件:JButton(按钮)、JTextField(文本框)、JTextArea(文本区)* 考点2:布局管理器(单选题高频):* - FlowLayout:流式布局(组件按顺序排列)* - BorderLayout:边界布局(分North/South/East/West/Center,默认Center)* - GridLayout:网格布局(多行多列)* 考点3:事件处理(程序设计题高频):* - 事件源:组件(如JButton)* - 监听器:接口(如ActionListener,处理按钮点击)* - 注册监听:addActionListener()*/
public class SwingGUI implements ActionListener {// 组件定义(成员变量,方便事件处理方法访问)private JFrame frame;private JTextField inputField;private JTextArea resultArea;private JButton confirmBtn;// 初始化GUIpublic void initGUI() {// 考点1:顶层容器JFrameframe = new JFrame("Swing考点演示"); // 窗口标题frame.setSize(400, 300); // 窗口大小frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 关闭窗口退出程序// 考点2:布局管理器:BorderLayout(边界布局)frame.setLayout(new BorderLayout());// 1. 北部区域:文本框+按钮(放在JPanel,用FlowLayout)JPanel northPanel = new JPanel();northPanel.setLayout(new FlowLayout()); // 考点2:FlowLayoutJLabel label = new JLabel("输入内容:");inputField = new JTextField(20); // 文本框,20列confirmBtn = new JButton("确认"); // 按钮(事件源)// 考点3:注册监听:按钮添加ActionListener,this实现该接口confirmBtn.addActionListener(this);// 添加组件到北部面板northPanel.add(label);northPanel.add(inputField);northPanel.add(confirmBtn);frame.add(northPanel, BorderLayout.NORTH); // 北部区域// 2. 中部区域:文本区(带滚动条)resultArea = new JTextArea();resultArea.setEditable(false); // 文本区不可编辑JScrollPane scrollPane = new JScrollPane(resultArea); // 滚动面板frame.add(scrollPane, BorderLayout.CENTER); // 中部区域(默认)// 显示窗口frame.setVisible(true);}// 考点3:实现ActionListener接口的方法(处理按钮点击事件)// @Overridepublic void actionPerformed(ActionEvent e) {// 判断事件源是否是确认按钮if (e.getSource() == confirmBtn) {String input = inputField.getText(); // 获取文本框内容// 文本区追加内容resultArea.append("你输入的内容:" + input + "\n");inputField.setText(""); // 清空文本框}}// 测试方法public static void testGUI() {// Swing组件需在EDT(事件调度线程)中创建,避免线程安全问题SwingUtilities.invokeLater(() -> {SwingGUI gui = new SwingGUI();gui.initGUI();});}public static void main(String[] args) {testGUI(); // 直接调用测试方法}
}
6、ThreadDemo.java
/*** 模块6:线程(必考点,占分10%)* 考点1:线程创建方式(单选题高频):* - 方式1:继承Thread类,重写run()方法* - 方式2:实现Runnable接口,重写run()方法(推荐,避免单继承限制)* 考点2:线程状态(填空题高频):* - 新建(new)→ 就绪(start())→ 运行(CPU调度)→ 阻塞(sleep()/wait())→ 死亡(run()结束)* 考点3:线程方法:* - start():启动线程(进入就绪状态,不能重复调用)* - run():线程执行逻辑(直接调用是普通方法,不启动线程)* - sleep(long ms):线程休眠(阻塞状态,释放CPU,不释放锁)* - wait()/notify():线程同步(释放锁/唤醒线程,需在synchronized块中)* 考点4:线程同步(程序分析题高频):* - synchronized:修饰方法/代码块,保证同一时间只有一个线程执行* - 作用:解决多线程访问共享资源的线程安全问题*/
// 考点1:方式1:继承Thread类
class MyThread extends Thread {private String name;public MyThread(String name) {super(name); // 调用父类Thread的构造,设置线程名this.name = name;}// 考点2:重写run()方法(线程执行逻辑)@Overridepublic void run() {for (int i = 1; i <= 5; i++) {System.out.println("线程" + name + ":执行第" + i + "次");try {// 考点3:sleep(300):休眠300ms(阻塞状态)Thread.sleep(300);} catch (InterruptedException e) {e.printStackTrace();}}System.out.println("线程" + name + ":执行结束(死亡状态)");}
}// 考点1:方式2:实现Runnable接口(推荐)
class MyRunnable implements Runnable {private String name;private int count = 0;public MyRunnable(String name) {this.name = name;}// 考点4:synchronized修饰方法:同步方法,保证线程安全public synchronized void increment() {count++;System.out.println("线程" + name + ":count=" + count);}// 重写run()方法@Overridepublic void run() {for (int i = 1; i <= 3; i++) {increment(); // 调用同步方法try {Thread.sleep(200);} catch (InterruptedException e) {e.printStackTrace();}}}
}public class ThreadDemo {public static void testThread() {// 1. 测试继承Thread的线程System.out.println("=== 继承Thread的线程 ===");Thread t1 = new MyThread("T1");Thread t2 = new MyThread("T2");t1.start(); // 考点3:start()启动线程(进入就绪状态)t2.start();// 等待t1、t2执行结束(避免干扰后续输出,实际开发用join())try {Thread.sleep(2000);} catch (InterruptedException e) {e.printStackTrace();}// 2. 测试实现Runnable的线程(多线程共享资源)System.out.println("\n=== 实现Runnable的线程(同步) ===");MyRunnable runnable = new MyRunnable("R1");// 多个线程共享同一个Runnable对象(count是共享资源)Thread t3 = new Thread(runnable, "T3");Thread t4 = new Thread(runnable, "T4");t3.start();t4.start();}public static void main(String[] args) {testThread(); // 直接调用测试方法}
}
3、Java更多题目(实践题)
参考 13216 实践
JavaExamPassProject
├─ com.basic: 基础语法与输入输出(考纲1、3;A/B卷基础题)
│ ├─ ArraySort_A1.java // A卷1题:字符串数组排序+GUI文本区
│ ├─ PrimeCheck_B2.java // B卷2题:素数判断(命令行输入)
│ ├─ UpperCount_A3.java // A卷3题:统计大写字母个数
├─ com.algorithm: 常见算法(考纲2;A/B卷算法题)
│ ├─ FactorialSum_B3.java // B卷3题:1!+2!+...+10!求和
│ ├─ PrimeRange_B2.java // B卷2题:100-1000素数输出
│ ├─ BinaryConvert_B1.java // B卷1题:长整数转二进制
├─ com.oop: 面向对象(考纲4;A/B卷类设计题)
│ ├─ Circle_A1.java // A卷1题:Circle类(面积/周长)
│ ├─ Cylinder_B1.java // B卷1题:圆柱体(体积/表面积)
│ ├─ Student_A1.java // A卷1题:Student类+成绩统计
├─ com.gui: Swing/AWT界面(考纲3;A卷GUI题)
│ ├─ TextAreaBtn_A3.java // A卷3题:按钮+文本区(追加/改色)
│ ├─ DrawPanel_A4.java // A卷4题:绘图面板(鼠标拖动+保存)
│ ├─ MenuText_A4.java // A卷4题:菜单(New/Save/Exit)
├─ com.io: 文件IO(考纲3;A/B卷IO题)
│ ├─ FileCreate_A2.java // A卷2题:创建目录/文件+写字节
│ ├─ FileReadWrite_B2.java // B卷2题:读文件+添加行号写入
│ ├─ FileSave_A4.java // A卷4题:JFileChooser保存图片
└─ com.thread: 多线程(考纲5;扩展备考)├─ DrawThread_A4.java // A卷4题:绘图线程(避免卡顿)└─ BasicThread.java // 基础多线程(继承Thread/实现Runnable)
| 模块 | 高频真题 | 必掌握知识点 |
|---|---|---|
| com.basic | A1(数组排序)、B2(素数) | JOptionPane、Scanner、Arrays.sort |
| com.algorithm | B3(阶乘和)、B1(二进制) | 循环嵌套、位运算、long类型避免溢出 |
| com.oop | A1(Circle/Student)、B1(圆柱体) | 构造函数重载、Getter、封装、统计算法 |
| com.gui | A3(按钮文本区)、A4(绘图) | BorderLayout、事件监听、JColorChooser |
| com.io | A2(文件创建)、B2(读写) | File类、字节流/字符流、缓冲流 |
| com.thread | A4(绘图线程) | 实现Runnable、线程启动、避免卡顿 |
调试技巧
- GUI类:运行后检查窗口大小、组件位置是否符合真题要求(如A3题400×300);
- IO类:注意文件路径(如A2题
d:\xxx\yyy\zzz需确保磁盘存在,无权限问题); - 算法类:通过
System.out输出中间结果(如阶乘和的每一步阶乘值),验证逻辑正确性; - 异常处理:考试时可添加
try-catch(如IO异常),避免程序崩溃(真题答案中未写,但实际考试建议补充)。
基础语法
ArraySort_A1.java
package com.basic;import java.awt.BorderLayout;
import java.util.Arrays;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTextArea;/*** A卷1题:图形界面+字符串数组排序* 考点:JFrame、JTextArea、JOptionPane、Arrays.sort*/
public class ArraySort_A1 extends JFrame {private JTextArea textArea;public ArraySort_A1() {// 窗口设置(真题要求:400×160,标题“第一题”,BorderLayout)setTitle("第一题");setSize(400, 160);setDefaultCloseOperation(EXIT_ON_CLOSE);getContentPane().setLayout(new BorderLayout());// 文本区(10行20列)textArea = new JTextArea(10, 20);getContentPane().add(textArea, BorderLayout.CENTER);// 1. 输入5个字符串到数组String[] strArr = new String[5];StringBuilder beforeSort = new StringBuilder("排序前:\n");for (int i = 0; i < strArr.length; i++) {strArr[i] = JOptionPane.showInputDialog("请输入第" + (i + 1) + "个字符串");beforeSort.append(strArr[i]).append("\t");}textArea.setText(beforeSort.toString());// 2. 排序(Arrays.sort升序)Arrays.sort(strArr);StringBuilder afterSort = new StringBuilder("\n排序后:\n");for (String s : strArr) {afterSort.append(s).append("\t");}textArea.append(afterSort.toString());setVisible(true);}public static void main(String[] args) {new ArraySort_A1();}
}
PrimeCheck_B2.java
package com.basic;import java.util.Scanner;/*** B卷2题:命令行输入整数,判断是否为素数* 考点:Scanner输入、素数算法、布尔返回值*/
public class PrimeCheck_B2 {// 真题要求:自定义方法判断素数,返回true/falsepublic static boolean isPrime(int num) {if (num < 2) return false; // 小于2不是素数if (num == 2) return true; // 2是唯一偶素数if (num % 2 == 0) return false; // 偶数排除// 优化:只需判断到根号num,步长2(奇数)for (int i = 3; i <= Math.sqrt(num); i += 2) {if (num % i == 0) return false;}return true;}public static void main(String[] args) {Scanner scanner = new Scanner(System.in);System.out.print("请输入一个整数:");int input = scanner.nextInt();System.out.println(isPrime(input)); // 真题要求:输入19输出truescanner.close();}
}
常见算法
FactorialSum_B3.java
package com.algorithm;/*** B卷3题:计算1!+2!+...+10!的和* 考点:阶乘算法、循环嵌套、long类型避免溢出*/
public class FactorialSum_B3 {// 计算单个数字的阶乘public static long getFactorial(int n) {long fact = 1;for (int i = 1; i <= n; i++) {fact *= i;}return fact;}// 计算阶乘之和public static long getSum(int max) {long sum = 0;for (int i = 1; i <= max; i++) {sum += getFactorial(i);}return sum;}public static void main(String[] args) {int max = 10;System.out.println("1!+2!+...+" + max + "! = " + getSum(max));// 输出结果:3628800 + ... + 1 = 4037913}
}
BinaryConvert_B1.java
package com.algorithm;import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;/*** B卷1题:命令行输入长整数转二进制,输入quit退出* 考点:BufferedReader输入、位运算、循环控制*/
public class BinaryConvert_B1 {// 真题要求:自定义static void printBinary(long i)public static void printBinary(long i) {System.out.println(i + "的2进制数表示为:");// 长整数64位,从最高位(63位)到最低位(0位)遍历for (int j = 63; j >= 0; j--) {// 位运算:1左移j位,与i按位与,判断该位是否为1System.out.print(((1L << j) & i) != 0 ? "1" : "0");}System.out.println();}public static void main(String[] args) throws IOException {BufferedReader br = new BufferedReader(new InputStreamReader(System.in));System.out.println("1.输入一个长整数,回车后求二进制;2.输入quit退出");String input;while (true) {System.out.print("Input:");input = br.readLine();if ("quit".equals(input)) break; // 输入quit退出long num = Long.parseLong(input);printBinary(num);}br.close();}
}
面向对象
Circle_A1.java
package com.oop;/*** A卷1题:Circle类(保护变量radius、构造函数、面积/周长)* 考点:类定义、构造函数重载、protected修饰符、Math.PI*/
public class Circle_A1 {protected double radius; // 真题要求:protected变量// 无参构造函数:初始化radius为20(真题要求)public Circle_A1() {this.radius = 20;}// 有参构造函数:传入参数初始化radiuspublic Circle_A1(double radius) {this.radius = radius;}// 计算面积:S=πr²public double getArea() {return Math.PI * radius * radius;}// 计算周长:C=2πrpublic double getPerimeter() {return 2 * Math.PI * radius;}// 测试:验证功能public static void main(String[] args) {Circle_A1 circle1 = new Circle_A1(); // 无参System.out.println("无参构造-面积:" + String.format("%.2f", circle1.getArea()));Circle_A1 circle2 = new Circle_A1(15); // 有参System.out.println("有参构造-周长:" + String.format("%.2f", circle2.getPerimeter()));}
}
Student_A1.java
package com.oop;/*** A卷1题:Student类(成员变量、构造函数、Getter、成绩统计)* 考点:类封装、Getter方法、数组存储对象、统计算法*/
public class Student_A1 {// 真题要求:成员变量sNo、sName、sex、sAge、sJavaprivate String sNo;private String sName;private String sex;private int sAge;private int sJava;// 带参数构造函数(真题要求:初始化所有成员变量)public Student_A1(String sNo, String sName, String sex, int sAge, int sJava) {this.sNo = sNo;this.sName = sName;this.sex = sex;this.sAge = sAge;this.sJava = sJava;}// Getter方法(真题要求:获取各成员变量)public String getSNo() { return sNo; }public String getSName() { return sName; }public String getSex() { return sex; }public int getSAge() { return sAge; }public int getSJava() { return sJava; }// 重写toString:便于输出学生信息@Overridepublic String toString() {return "学号:" + sNo + ",姓名:" + sName + ",性别:" + sex + ",年龄:" + sAge + ",Java成绩:" + sJava;}public static void main(String[] args) {// 真题要求:创建5个Student对象Student_A1[] students = {new Student_A1("2024001", "张三", "男", 20, 85),new Student_A1("2024002", "李四", "女", 19, 92),new Student_A1("2024003", "王五", "男", 20, 78),new Student_A1("2024004", "赵六", "女", 19, 95),new Student_A1("2024005", "孙七", "男", 20, 69)};// 1. 输出每个学生信息System.out.println("5个学生信息:");for (Student_A1 stu : students) {System.out.println(stu);}// 2. 统计Java成绩:平均值、最高分、最低分int sum = 0;int max = students[0].getSJava();int min = students[0].getSJava();for (Student_A1 stu : students) {int score = stu.getSJava();sum += score;max = Math.max(max, score);min = Math.min(min, score);}double avg = (double) sum / students.length;// 输出统计结果System.out.println("\nJava成绩统计:");System.out.println("平均值:" + String.format("%.1f", avg));System.out.println("最高分:" + max);System.out.println("最低分:" + min);}
}
图形界面
TextAreaBtn_A3.java
package com.gui;import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JColorChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextArea;/*** A卷3题:GUI界面(3个按钮+文本区,追加文本/改文字色/改背景色)* 考点:BorderLayout、JButton事件、JColorChooser、字体设置*/
public class TextAreaBtn_A3 extends JFrame {private JTextArea textArea;private JButton[] buttons = new JButton[3]; // 3个按钮public TextAreaBtn_A3() {// 窗口设置(真题要求:400×300,标题“第3题”)setTitle("第3题");setSize(400, 300);setDefaultCloseOperation(EXIT_ON_CLOSE);getContentPane().setLayout(new BorderLayout());// 文本区(20行20列,楷体_gb2312、普通体、30号字)textArea = new JTextArea(20, 20);textArea.setFont(new Font("楷体_gb2312", Font.PLAIN, 30));getContentPane().add(textArea, BorderLayout.CENTER);// 按钮面板(北边,FlowLayout)JPanel btnPanel = new JPanel();for (int i = 0; i < buttons.length; i++) {buttons[i] = new JButton("按钮" + (i + 1));btnPanel.add(buttons[i]);}getContentPane().add(btnPanel, BorderLayout.NORTH);// 按钮1事件:追加“java程序设计”(真题要求)buttons[0].addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {textArea.append("java程序设计\n");}});// 按钮2事件:改文字颜色(JColorChooser)buttons[1].addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {Color color = JColorChooser.showDialog(null, "选择文字颜色", Color.BLACK);if (color != null) textArea.setForeground(color);}});// 按钮3事件:改背景颜色buttons[2].addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {Color color = JColorChooser.showDialog(null, "选择背景颜色", Color.WHITE);if (color != null) textArea.setBackground(color);}});setVisible(true);}public static void main(String[] args) {new TextAreaBtn_A3();}
}
DrawPanel_A4.java
package com.gui;import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JPanel;/*** A卷4题:绘图面板(鼠标拖动绘图、缓冲区、十字光标)* 考点:MouseMotionListener、BufferedImage、Graphics2D*/
public class DrawPanel_A4 extends JPanel implements MouseMotionListener {public static final int DRAW = 1, CLEAR = 2;public int state = 0;private int width = 400, height = 400;private ArrayList<Point> points = new ArrayList<>(); // 存储拖动路径public BufferedImage buffImage; // 图像缓冲区(供保存用)private Graphics2D buffG2d;public DrawPanel_A4() {setBackground(Color.WHITE);// 初始化缓冲区(400×400,RGB格式)buffImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);buffG2d = buffImage.createGraphics();buffG2d.setColor(Color.WHITE);buffG2d.fillRect(0, 0, width, height); // 缓冲区背景为白色addMouseMotionListener(this); // 添加鼠标移动监听}// 绘图核心:先画缓冲区,再画拖动路径@Overridepublic void paint(Graphics g) {super.paint(g);Graphics2D g2d = (Graphics2D) g;// 清除绘图(New菜单触发)if (state == CLEAR) {buffG2d.setColor(Color.WHITE);buffG2d.fillRect(0, 0, width, height);points.clear();state = 0;}// 绘制拖动路径(画笔宽度3.0f)if (state == DRAW && points.size() > 1) {buffG2d.setColor(Color.RED);buffG2d.setStroke(new BasicStroke(3.0f));for (int i = 0; i < points.size() - 1; i++) {Point p1 = points.get(i);Point p2 = points.get(i + 1);buffG2d.drawLine(p1.x, p1.y, p2.x, p2.y);}}// 显示缓冲区内容到面板g2d.drawImage(buffImage, 0, 0, width, height, this);}// 鼠标移动:清空路径,手形光标@Overridepublic void mouseMoved(java.awt.event.MouseEvent e) {setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));points.clear();}// 鼠标拖动:添加路径点,十字光标,触发绘图@Overridepublic void mouseDragged(java.awt.event.MouseEvent e) {state = DRAW;setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR));points.add(e.getPoint());repaint(); // 重绘面板}// 面板首选大小(避免拉伸)@Overridepublic java.awt.Dimension getPreferredSize() {return new java.awt.Dimension(width, height);}
}
IO文件
FileCreate_A2.java
package com.io;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;/*** A卷2题:创建目录树d:\xxx\yyy\zzz、文件1.txt,写字节+读文件* 考点:File类、mkdirs()、createNewFile()、FileOutputStream/InputStream*/
public class FileCreate_A2 {public static void main(String[] args) throws IOException {// 1. 创建目录树d:\xxx\yyy\zzz(mkdirs()创建多级目录)File dir = new File("d:\\xxx\\yyy\\zzz");if (dir.mkdirs()) {System.out.println("目录创建成功:" + dir.getAbsolutePath());} else {System.out.println("目录已存在或创建失败");}// 2. 创建文件1.txt(在上述目录下)File file = new File(dir, "1.txt");if (file.createNewFile()) {System.out.println("文件创建成功:" + file.getAbsolutePath());} else {System.out.println("文件已存在或创建失败");}// 3. 写数据到1.txt:先写“I like java.”,再写26个小写字母FileOutputStream fos = new FileOutputStream(file);// 字符串转字节数组(getBytes())String str = "I like java.";fos.write(str.getBytes());// 写26个小写字母(a-z)for (char c = 'a'; c <= 'z'; c++) {fos.write(c); // char转int(ASCII码)}fos.close();System.out.println("数据写入完成");// 4. 读1.txt内容并显示在命令行FileInputStream fis = new FileInputStream(file);int data;System.out.print("文件内容:");while ((data = fis.read()) != -1) {System.out.print((char) data); // 字节转字符}fis.close();}
}
FileReadWrite_B2.java
package com.io;import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;/*** B卷2题:读源文件,添加行号后写入1.txt(当前目录)* 考点:FileReader/FileWriter、BufferedReader/BufferedWriter、行号统计*/
public class FileReadWrite_B2 {public static void main(String[] args) throws IOException {// 1. 读取源文件(示例:读当前项目下的Test.java,可修改路径)FileReader fr = new FileReader("src/com/io/FileReadWrite_B2.java");BufferedReader br = new BufferedReader(fr); // 缓冲读,提高效率// 2. 写入目标文件(当前目录下的1.txt)FileWriter fw = new FileWriter("1.txt");BufferedWriter bw = new BufferedWriter(fw); // 缓冲写// 3. 逐行读取,添加行号后写入String line;int lineNum = 1; // 行号从1开始while ((line = br.readLine()) != null) {bw.write(lineNum + ": " + line); // 行号+内容bw.newLine(); // 换行(跨平台兼容)lineNum++;}// 4. 关闭流(先关缓冲流,再关节点流)bw.flush(); // 强制刷新缓冲区bw.close();fw.close();br.close();fr.close();System.out.println("文件处理完成!1.txt已生成(当前目录)");}
}
多线程
DrawThread_A4.java
package com.thread;import com.gui.DrawPanel_A4;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.FileOutputStream;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;/*** A卷4题:Test4类(菜单+绘图面板,多线程避免绘图卡顿)* 考点:JMenu/JMenuItem、JFileChooser、多线程绘图、JPEG保存*/
public class DrawThread_A4 extends JFrame {private DrawPanel_A4 drawPanel;public DrawThread_A4() {setTitle("第4题");setSize(400, 400);setDefaultCloseOperation(EXIT_ON_CLOSE);getContentPane().setLayout(new BorderLayout());// 绘图面板(多线程绘制,避免主线程卡顿)drawPanel = new DrawPanel_A4();getContentPane().add(drawPanel, BorderLayout.CENTER);// 添加菜单条(File菜单:New/Save/Exit)JMenuBar menuBar = new JMenuBar();JMenu fileMenu = new JMenu("File");fileMenu.setMnemonic(KeyEvent.VK_F); // 快捷键ALT+F// New菜单项(清空绘图)JMenuItem newItem = new JMenuItem("New");newItem.setMnemonic(KeyEvent.VK_N); // ALT+NnewItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {drawPanel.state = DrawPanel_A4.CLEAR;drawPanel.repaint();}});// Save菜单项(保存为JPG)JMenuItem saveItem = new JMenuItem("Save");saveItem.setMnemonic(KeyEvent.VK_S); // ALT+SsaveItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {// 启动线程保存图片,避免阻塞主线程new Thread(new Runnable() {@Overridepublic void run() {saveJPG(drawPanel.buffImage);}}).start();}});// Exit菜单项(退出程序)JMenuItem exitItem = new JMenuItem("Exit");exitItem.setMnemonic(KeyEvent.VK_X); // ALT+XexitItem.addActionListener(new ActionListener() {@Overridepublic void actionPerformed(ActionEvent e) {System.exit(0);}});// 添加菜单项到菜单fileMenu.add(newItem);fileMenu.add(saveItem);fileMenu.add(exitItem);menuBar.add(fileMenu);setJMenuBar(menuBar);setVisible(true);}// 保存缓冲区为JPG文件(A卷4题要求)private void saveJPG(BufferedImage image) {javax.swing.JFileChooser fileChooser = new javax.swing.JFileChooser();fileChooser.setDialogTitle("保存图片");int result = fileChooser.showSaveDialog(this);if (result == javax.swing.JFileChooser.APPROVE_OPTION) {File file = fileChooser.getSelectedFile();try {FileOutputStream fos = new FileOutputStream(file + ".jpg");JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(fos);encoder.encode(image);fos.close();javax.swing.JOptionPane.showMessageDialog(this, "保存成功!");} catch (Exception e) {e.printStackTrace();javax.swing.JOptionPane.showMessageDialog(this, "保存失败!");}}}public static void main(String[] args) {// 主线程创建窗口,绘图逻辑在DrawPanel的线程中new DrawThread_A4();}
}
