Java 程序设计
速通的倒数第二门,唉这学期怎么都在速通,活得太没意思了。
祝我好运。
Java 基础
概述
Java 是一种“简单、面向对象、分布式、解释型、健壮、安全、体系结构中立、可移植、高性能、多线程和动态”的编程语言。
- 简单性
- 去掉了指针,取消多重继承和运算符重载。
- 自动内存分配与回收机制。
- 纯粹的面向对象
- 分布式,面向网络
- 健壮性
- 内存自动管理。
- 异常处理机制。
- 安全性
- 直接去掉指针。
- 所有程序和数据都在沙箱中。
- 体系结构中立,平台无关
- 只要安装了 Java 虚拟机 (JVM),代码就可以在随处运行。
- 可移植性
- 解释执行
- Java 程序被编译成 JVM 字节码,不依赖机器,可运行在任意安装了 Java 解释器的机器上。
- 高性能
- 多线程
- 动态性
- 在类库中可以自由地加入新的方法和实例变量而不会影响用户程序的执行。
Java 和 C++
- Java 语言中不允许在类之外定义全局变量,而只能通过在类中定义静态变量来实现。
- Java 语言中没有
goto
语句。 - Java 语言中没有指针型变量。
- 内存管理实现了自动化。
- Java 语言对于不同的数据类型定义统一的规格,保证了平台无关性。
- Java 语言中不允许像 C 和 C++ 中那样任意进行类型转换。
- Java 语言中无头文件。
- Java 语言中无结构体和联合。
- Java 语言中无预处理和宏定义。
Java 语言特色:
- 类不支持多重继承
Abstract
/Final
类- 接口
- 自动内存回收
- 多线程
标识符使用惯例
- 类和接口
SimpleApp
- 类名和接口名通常用名词,且每个单词的首字母大写。
- 方法
processResult
- 方法名用动词开头的单词序列,首单词全部小写,后面的每个单词首
字母大写。
- 方法名用动词开头的单词序列,首单词全部小写,后面的每个单词首
- 常量
PI
- 常量名全部用大写字母。
- 变量
outputResult
- 所有的对象实例名和全局变量名都使用首单词全部小写,后面的每个
单词首字母大写的格式。
- 所有的对象实例名和全局变量名都使用首单词全部小写,后面的每个
对象
访问控制
控制符 | 同一个类中 | 同一个包 中 | 不同包中的子类 | 不同包中的非子类 |
---|---|---|---|---|
public | ✅ | ✅ | ✅ | ✅ |
protected | ✅ | ✅ | ✅ | |
default (什么都不写) | ✅ | ✅ | ||
private | ✅ |
接口和类
Java 中所有的类都继承自 java.lang.Object
。
基本方法 | 作用 | 是否常重写 |
---|---|---|
toString() | 返回对象的字符串表示 | ✅ 常重写 |
equals(Object obj) | 判断两个对象是否“相等” | ✅ 常重写 |
hashCode() | 返回对象的哈希值 | ✅ 常和 equals 一起重写 |
getClass() | 返回运行时类对象 | ❌ 一般不重写 |
clone() | 对对象进行浅拷贝 | ❌ 少用,需实现 Cloneable 接口 |
finalize() | 垃圾回收前调用(不推荐使用) | ❌ 废弃 |
wait() | 线程等待(需在同步块中) | ❌ 通常不重写 |
notify() | 唤醒等待的线程 | ❌ 通常不重写 |
notifyAll() | 唤醒所有等待的线程 | ❌ 通常不重写 |
特性 | 接口(interface) | 类(class) |
---|---|---|
语义 | 定义行为规范,类似“能力” | 定义对象的属性和行为 |
方法 | 默认是 public abstract (除非是 default /static /private ) | 可包含具体实现的方法 |
字段 | 默认是 public static final (常量),且只能是 public | 可定义变量,有访问权限控制 |
继承 | 可以多继承多个接口 | 只能单继承一个类 |
实现方式 | 类用 implements 来实现接口 | 类用 extends 继承另一个类 |
实例化 | 无法直接实例化 | 可以实例化(如果不是 abstract ) |
数据结构
数组
数组是一种固定大小的同类型数据序列。
声明数组变量有两种形式:
类型[] 数组名;
(推荐)类型 数组名[];
例如:int[] a;
或 String[] names;
创建与初始化:
静态初始化:在声明时直接指定元素值。数组长度由元素个数决定 。
1
2int[] numbers = {1, 2, 3, 4, 5}; // 长度为 5
String[] colors = new String[]{"Red", "Green", "Blue"};动态初始化:指定数组长度,元素会自动赋为默认值(数值型为 0,布尔型为
false
,引用型为null
)。1
2int[] scores = new int[10]; // 长度为 10,所有元素初始化为 0
String[] names = new String[5]; // 长度为 5,所有元素初始化为 null对象数组:数组元素是对象引用,需要单独初始化每个对象 。
1
2
3
4// 声明并动态初始化一个 Person 对象数组
Person[] people = new Person[2];
people[0] = new Person("Alice", 30); // 单独初始化对象
people[1] = new Person("Bob", 25);
访问:使用 数组名[索引值]
访问元素,索引从 0 开始 。
长度属性:数组具有唯一的 length
属性,记录数组中元素的个数 ,用 numbers.length
获取数组长度 。
多维数组:是数组的数组,可以是不规则数组(各维长度不等) 。
1
2
3
4int[][] matrix = {{1, 2, 3}, {4, 5, 6}}; // 2x3 矩阵
int[][] irregularArray = new int[2][]; // 不规则数组
irregularArray[0] = new int[2]; // 第一行 2 列
irregularArray[1] = new int[3]; // 第二行 3 列数组引用:Java 数组是特殊的对象,数组变量存放一个数组对象的引用 。因此,数组作为方法参数时,传递的是引用,可以改变数组元素的值 。
1
2
3
4public static void changeArrayValue(int[] arr) {
arr[0] = 99; // 改变原数组的值
}
// 调用:int[] myArr = {1, 2, 3}; changeArrayValue(myArr); System.out.println(myArr[0]); // 输出 99
Arrays
工具类:java.util.Arrays
提供了一套静态方法,用于数组的排序 (sort()
)、查找 (binarySearch()
)、复制 (copyOf()
)、比较 (equals()
) 等 。
枚举
枚举是一种特殊的类,用于定义固定数量的命名常量。
使用 enum
关键字定义,枚举类型变量只能保存此类声明时给定的某个枚举值 。
1 |
|
本质:Java 的枚举是真正的类,它们可以有构造方法、成员变量、方法,甚至可以实现接口 。每个枚举常量都是该枚举类型的一个实例。
1 |
|
使用:
- 可以在
switch
语句中使用 。 name()
方法:返回枚举常量的名称字符串。ordinal()
方法:返回枚举常量的序数(在枚举声明中的位置,从 0 开始)。valueOf(String name)
:返回具有指定名称的枚举常量。values()
:返回包含所有枚举常量的数组。
容器
Java 集合框架(java.util
包)提供了一套用于存储和管理对象的接口和类,具有动态容量。这是 Java 处理对象集合的主要方式,与 C++ 的 STL 类似。
Java 中的容器:
核心接口:
Collection
:所有集合的根接口,定义了集合的基本操作(添加、删除、判断包含等) 。List
:有序的Collection
,元素有索引,允许重复元素 。- 实现类:
ArrayList
:基于动态数组实现,随机访问效率高,中间插入删除慢 。LinkedList
:基于双向链表实现,中间插入删除效率高,随机访问慢 。
- 实现类:
Set
:无序的Collection
,不允许重复元素 。- 实现类:
HashSet
:基于哈希表实现,查找、添加、删除效率高(平均 ),元素无序 。要求元素类正确重写hashCode()
和equals()
。LinkedHashSet
:基于哈希表和链表实现,保持元素的插入顺序 。TreeSet
:基于红黑树实现,元素按自然顺序或比较器顺序排序 。查找效率 。
- 实现类:
Map
:存储键值对 (KV Pair),键唯一,值可重复 。- 实现类:
HashMap
:基于哈希表实现,查找、添加、删除效率高(平均 ),键值对无序 。要求键类正确重写hashCode()
和equals()
。LinkedHashMap
:基于哈希表和链表实现,保持键值对的插入顺序 。TreeMap
:基于红黑树实现,键按自然顺序或比较器顺序排序 。查找效率 。
- 实现类:
迭代器:
Iterator
:用于遍历Collection
中的元素 。ListIterator
:专门用于List
,支持双向遍历和修改元素 。
泛型 (Generics):Java 1.5 引入,用于在编译时提供类型安全,避免运行时类型转换错误 。
1
2List<String> names = new ArrayList<>(); // 编译时检查,只能存 String
Map<Integer, String> students = new HashMap<>();工具类:
java.util.Collections
:提供对Collection
进行操作的静态方法(排序、查找、反转等) 。java.util.Arrays
:提供对数组进行操作的静态方法 。
图形化界面
Swing
- AWT (Abstract Window Toolkit):
- 提供一套与本地图形界面交互的接口。
- 依赖本地方法实现功能,因此 AWT 控件被称为重量级控件。
- Swing:
- 在 AWT 基础上构建的新图形界面系统。
- 提供 AWT 的所有功能,并进行大幅扩充。
- 没有使用本地方法实现图形功能,因此 Swing 控件被称为轻量级控件。
- 随着 Java2 的发布,Swing 逐渐替代了 AWT,本章主要介绍 Swing 组件。
- Swing 组件类以字母 “J” 开头,除了与 AWT 类似的组件外,还增加了丰富的高层组件。
- Java 语言采用向容器中添加组件的方式构建 GUI。通常使用顶级容器作为所有组件的承载物,可以向其中添加包括容器在内的各种组件,并合理安排布局。容器之间允许嵌套。
GUI 组件从使用上可分为三大类:
- 容器类 (Container):
- 用于包含其他组件的容器。
- 例如:
JFrame
(顶层容器),JApplet
,JDialog
,JPanel
(普通容器)。
- 控件类 (Control):
- 都是
JComponent
类(抽象类)的子类。 - 例如:
JButton
,JTextField
,JTextArea
,JComboBox
,JList
,JRadioButton
,JMenu
。
- 都是
- 辅助类 (Auxiliary Class):
- 描述和绘制容器类和组件类属性和放置的类。
- 例如:
Graphics
,Color
,Font
,FontMetrics
,Dimension
,LayoutManager
。
常用组件
JFrame
类
- 继承关系:
java.lang.Object
->java.awt.Component
->java.awt.Container
->java.awt.Window
->java.awt.Frame
->javax.swing.JFrame
。 - 构造方法:
public JFrame()
,public JFrame(String title)
。 - 成员方法:
setSize()
: 设置窗口大小。setVisible()
: 设置窗口可见性。setLocation()
: 设置窗口位置。setDefaultCloseOperation(int operation)
: 设置窗口关闭时的动作。- 参数
operation
有四种取值:DO_NOTHING_ON_CLOSE
,HIDE_ON_CLOSE
,DISPOSE_ON_CLOSE
,EXIT_ON_CLOSE
。
- 参数
getContentPane()
: 获取内容面板。setTitle()
: 设置窗口标题。
JLabel
类
- 继承关系:
java.lang.Object
->java.awt.Component
->java.awt.Container
->javax.swing.JComponent
->javax.swing.JLabel
。 - 构造方法: 支持多种构造方法,如只带文本、只带图标、或同时带文本和图标及对齐方式。
- 对齐属性:
SwingConstants.LEFT
,SwingConstants.CENTER
,SwingConstants.RIGHT
,SwingConstants.BOTTOM
。 - 成员方法:
setText()
,setIcon()
,getText()
,setHorizontalTextPosition()
,setVerticalTextPosition()
。
JPanel
类
- 面板容器:
JPanel
是分组放置组件的、位于框架更低一级的普通容器。 - 继承关系:
java.lang.Object
->java.awt.Component
->java.awt.Container
->javax.swing.JComponent
->javax.swing.JPanel
。 - 构造方法:
public JPanel()
。 - 成员方法:
paintComponents(Graphics g)
,add(Component comp)
。
JButton
类
- 继承关系:
java.lang.Object
->java.awt.Component
->java.awt.Container
->javax.swing.JComponent
->javax.swing.AbstractButton
->javax.swing.JButton
。 - 构造方法: 支持多种构造方法,如无文本、带文本、带图标、或同时带文本和图标。
- 成员方法:
setText()
,setIcon()
,setBounds()
,addActionListener(ActionListener l)
。
文本框 JTextField
- 构造方法:
public JTextField()
,public JTextField(String text)
,public JTextField(int columns)
,public JTextField(String text, int columns)
。 - 成员方法:
addActionListener(ActionListener l)
,setColumns(int columns)
,setText(String text)
。
其他常用组件
JTextArea
: 提供多行文本编辑功能。JCheckBox
: 复选框。JRadioButton
: 单选按钮,常与ButtonGroup
配合使用。JComboBox
: 组合框(下拉列表)。JDialog
: 对话框,可设置模式(应用程序只能响应对话框内事件)或非模式(可响应其他窗口事件)。JFileChooser
: 文件对话框,用于打开或存储文件。JMenuBar
,JMenu
,JMenuItem
: 用于创建菜单栏、菜单和菜单项。
布局管理
当向窗口中放置组件时,需要指定组件放置策略。
Java 中有两种定位组件的方法:
硬编码: 屏幕绝对位置,与机器相关。
软编码: 布局管理器,与机器无关。
Java 布局管理器类存在于
java.awt
包中。在
Container
中有一个setLayout()
方法,可以选择不同的布局方式。
FlowLayout
(顺序布局)
- 继承关系:
java.lang.Object
->java.awt.FlowLayout
。 - 构造方法:
public FlowLayout()
,public FlowLayout(int align)
,public FlowLayout(int align, int hGap, int vGap)
。 - 成员属性:
LEFT
,CENTER
,RIGHT
。 - 特点: 将组件从左到右放置,直到占满上方空间,再向下移动一行继续放置。所有组件将被压缩到它们的最小尺寸,按“合适”的大小呈现。
BorderLayout
(边界布局)
- 继承关系:
java.lang.Object
->java.awt.BorderLayout
。 - 构造方法:
public BorderLayout()
,public BorderLayout(int hGap, int vGap)
。 - 成员属性:
NORTH
,SOUTH
,EAST
,WEST
,CENTER
。 - 特点: 将组件分置五个区域:北、南、东、西、中。
BorderLayout
是JFrame
的默认布局。 - 使用
add()
方法时,第一个参数可以指定区域,如BorderLayout.NORTH
。 未指定区域的组件将放置在中央并拉伸。
GridLayout (网格布局)
- 继承关系:
java.lang.Object
->java.awt.GridLayout
。 - 构造方法:
public GridLayout()
,public GridLayout(int rows, int columns)
,public GridLayout(int rows, int columns, int hGap, int vGap)
。 - 特点: 在网格里从左到右、从上到下布局。确定行列数后,组件将以相同的长宽比排列。
事件处理
事件处理机制
要让图形界面接收用户的操作,必须为组件添加事件处理机制。
事件处理主要涉及三类对象:
Event (事件): 用户对界面操作在 Java 语言上的描述,以类的形式出现。例如键盘操作对应的事件类是
KeyEvent
。Event Source (事件源): 事件发生的场所,通常是各个组件,例如按钮
JButton
。Event Handler (事件处理者): 接收事件对象并对其进行处理的对象,也称为事件监听器 (
Listener
)。
事件响应过程:
- 组件(事件源)触发相应类型的事件。
- 生成事件对象。
- 把事件对象传入事件处理器。
- 事件由相应类型的
Listener
(事件监听器)接收并处理。- 实现事件监听器的方式:
- 内部类实现监听器方式:定义一个独立的内部类实现监听器接口,并在组件中注册该内部类的对象。
- 匿名内部类实现监听器方式:直接在
addActionListener()
方法中定义并实例化一个匿名内部类来实现监听器接口。 - 直接实现监听器方式:主类直接实现监听器接口,然后将
this
关键字作为监听器对象注册到组件中。
- 实现事件监听器的方式:
事件类与事件监听接口
- Java 使用
AWTEvent
类表示事件,其继承关系为java.lang.Object
->java.util.EventObject
->java.awt.AWTEvent
。 - 各种事件类别对应不同的监听器接口和方法:
ActionEvent
:ActionListener
(actionPerformed
)ItemEvent
:ItemListener
(itemStateChanged
)MouseEvent
:MouseListener
(mousePressed
,mouseReleased
,mouseEntered
,mouseExited
,mouseClicked
)MouseEvent
(移动):MouseMotionListener
(mouseDragged
,mouseMoved
)KeyEvent
:KeyListener
(keyPressed
,keyReleased
,keyTyped
)FocusEvent
:FocusListener
(focusGained
,focusLost
)AdjustmentEvent
:AdjustmentListener
(adjustmentValueChanged
)ComponentEvent
:ComponentListener
(componentMoved
,componentHidden
,componentResized
,componentShown
)WindowEvent
:WindowListener
(windowClosing
,windowOpened
,windowIconified
,windowDeiconified
,windowClosed
,windowActivated
,windowDeactivated
)ContainerEvent
:ContainerListener
(componentAdded
,componentRemoved
)TextEvent
:TextListener
(textValueChanged
)
适配器类 (Adapter
)
每个具有不止一个方法的 AWT 监听器接口都有一个实现了其所有方法但
不做任何工作的适配器类。
可以通过继承适配器类来只重写需要的方法,避免实现接口中所有的方法。
java.awt.event
包中定义的事件适配器类包括:
ComponentAdapter
ContainerAdapter
FocusAdapter
KeyAdapter
MouseAdapter
(示例显示其实现了mouseClicked
等空方法)MouseMotionAdapter
WindowAdapter
I/O 流
I/O (Input/Output) 指计算机与外部世界进行数据交换的过程,例如从键盘读取数据、向屏幕输出信息、读写文件、网络通信等。
**流 (Stream) **是 Java 语言输入/输出的方式, Java 程序通过流来完成输入/输出工作。是一个想象中的无限长的数据序列。 Java 提供了各种各样的流类来实现 I/O,封装了数据处理的细节.
流的分类:
- 按数据流向:
- 输入流 (InputStream/Reader): 从数据源读取数据到程序中。
- 输出流 (OutputStream/Writer): 从程序中写入数据到数据目的地。
- 按处理数据单位:
- 字节流 (Byte Stream): 以字节(8位)为单位处理数据,适用于所有类型的数据(如图片、视频、文本等)。
- 字符流 (Character Stream): 以字符(16位 Unicode 字符)为单位处理数据,专门用于处理文本数据,可以避免编码问题。
- 按功能:
- 节点流 (Node Stream): 直接与数据源(如文件、内存数组、管道)连接,提供基本的读写功能。
- 处理流 / 包装流 (Processing Stream / Wrapper Stream): 包装在其他流之上,修改或管理流中数据,提供额外的功能(如缓冲、数据转换、对象序列化、打印等)。
类型 | 字节流 | 字符流 |
---|---|---|
输入流(读) | InputStream 及其子类 | Reader 及其子类 |
输出流(写) | OutputStream 及其子类 | Writer 及其子类 |
常见的 I/O 流类:
类型 | 字节流类 | 字符流类 | 说明 |
---|---|---|---|
文件输入 | FileInputStream | FileReader | 从文件中读取 |
文件输出 | FileOutputStream | FileWriter | 写入文件 |
缓冲输入 | BufferedInputStream | BufferedReader | 提高读性能,支持按行读取 |
缓冲输出 | BufferedOutputStream | BufferedWriter | 提高写性能 |
转换流 | — | InputStreamReader / OutputStreamWriter | 将字节流转为字符流 |
数据流 | DataInputStream | — | 读写 Java 原始类型(如 int , double ) |
打印流 | PrintStream | PrintWriter | 方便格式化输出 |
对象流 | ObjectInputStream | — | 对象序列化与反序列化 |
标准流 | System.in | — | 控制台输入(字节流) |
文件 I/O
文件存储格式:
文件可以看作一系列字节的集合。
无论是字符 I/O 还是字节 I/O,最终文件中存储的都是这些字符的编码(字节序列)。
字符 I/O 程序:处理字符的统一码,进行编码/解码,文件中存储的是字符的编码(如 UTF-8, GBK 等)。
字节 I/O 程序:直接读写字节,文件中存储的是等价的字节数据。
File
类:
java.io.File
:文件和目录路径名的抽象表示形式,用于获取文件或目录的信息.- 构造器:
public File(String pathname)
: 以pathname
为路径创建File
对象,如果为相对路径则在默认的当前路径下存储.public File(String parent, String child)
: 以parent
为父路径,child
为子路径创建File
对象.
- 常用方法:
boolean canRead()
: 判断是否可读.boolean canWrite()
: 判断是否可写.boolean exists()
: 判断文件或目录是否存在.boolean isDirectory()
: 判断是否是目录.boolean isFile()
: 判断是否是文件.boolean isHidden()
: 判断是否是隐藏文件.long lastModified()
: 返回最后修改时间.long length()
: 返回文件长度(字节数).String getName()
: 返回文件或目录名.String getPath()
: 返回文件或目录的路径名字符串.String getAbsolutePath()
: 返回文件的绝对路径名字符串.boolean createNewFile()
: 创建新文件.boolean delete()
: 删除文件或目录.boolean mkdir()
: 创建单级目录.boolean mkdirs()
: 创建多级目录.File getParentFile()
: 返回父目录的File
对象.String[] list()
: 列出目录下的文件和目录名.File[] listFiles()
: 返回目录下的File
对象数组.
流与相关类
字节流类层次结构:
InputStream
(抽象基类): 所有字节输入流的父类.int read()
: 读取一个字节并以整数形式返回.int read(byte[] buffer)
: 读取一系列字节到数组buffer
中,返回读取的字节数.int read(byte[] buffer, int offset, int length)
: 从offset
位置开始存储到buffer
中.void close()
: 关闭流,释放内存资源.long skip(long n)
: 跳过n
个字节.主要子类 (节点流):
FileInputStream
: 从文件中读取信息.ByteArrayInputStream
: 将内存的缓冲区当作InputStream
使用.PipedInputStream
: 产生用于写入相关PipedOutputStream
的数据,实现“管道化”.SequenceInputStream
: 将两个或多个InputStream
对象转换成单一InputStream
.StringBufferInputStream
(已弃用): 将String
转换成InputStream
.
处理流 (
FilterInputStream
的子类):DataInputStream
: 与DataOutputStream
搭配使用,可以可移植方式从流读取基本数据类型 (int
,char
,long
等).BufferedInputStream
: 使用缓冲区,防止每次读取都进行实际的读操作,提高效率.LineNumberInputStream
: 跟踪输入流中的行号.PushbackInputStream
: 具有一个字节的回退缓冲区,可以将读到的最后一个字符回退.ObjectInputStream
: 用于读取对象,也可以处理基本数据类型.
OutputStream
(抽象基类): 所有字节输出流的父类.- 常用方法 (可能抛出
IOException
):void write(int b)
: 写入一个字节.void write(byte[] b)
: 写入字节数组.void write(byte[] b, int off, int len)
: 写入字节数组的一部分.void close()
: 关闭流.void flush()
: 刷新缓冲区,强制写入数据.
- 主要子类 (节点流):
FileOutputStream
: 用于向文件中写入信息.ByteArrayOutputStream
: 将数据写入内存缓冲区.PipedOutputStream
: 写入数据到相关PipedInputStream
.
- 处理流 (
FilterOutputStream
的子类):DataOutputStream
: 与DataInputStream
搭配使用,可移植地向流写入基本数据类型.BufferedOutputStream
: 使用缓冲区,提高写入效率.PrintStream
: 打印流,为其他输出流添加打印各种数据值表示形式的功能,不抛出IOException
,自动刷新.ObjectOutputStream
: 用于写入对象.
- 常用方法 (可能抛出
字符流类层次结构:
Reader
(抽象基类): 所有字符输入流的父类.常用方法 (可能抛出
IOException
):int read()
,int read(char[] cbuf)
,int read(char[] cbuf, int offset, int length)
,void close()
,long skip(long n)
.主要子类 (节点流):
FileReader
(文件),CharArrayReader
(内存字符数组),StringReader
(内存字符串),PipedReader
(管道).处理流 (
FilterReader
的子类 或 其他):BufferedReader
(缓冲),LineNumberReader
(行号),PushbackReader
(回退),InputStreamReader
(字节到字符的转换流).
Writer
(抽象基类): 所有字符输出流的父类.常用方法 (可能抛出
IOException
):void write(int c)
,void write(char[] cbuf)
,void write(char[] cbuf, int offset, int length)
,void write(String string)
,void write(String string, int offset, int length)
,void close()
,void flush()
.主要子类 (节点流):
FileWriter
(文件),CharArrayWriter
(内存字符数组),StringWriter
(内存字符串),PipedWriter
(管道).处理流 (
FilterWriter
的子类 或 其他):BufferedWriter
(缓冲),PrintWriter
(打印流),OutputStreamWriter
(字符到字节的转换流).
特殊流类型:
DataInputStream
/DataOutputStream
: 用于对已经存在的输入/输出流进行包装,以便在原始流中过滤数据。支持原始数据类型(boolean
,char
,byte
,short
,int
,long
,float
,double
)的输入输出,与机器无关.BufferedInputStream
/BufferedOutputStream
: 减少读写次数,提高 I/O 效率,通过在高速设备和低速设备之间使用缓冲区实现。缓冲区默认大小为 512 字节。当缓冲满或调用flush
方法时,数据写入.常用方法 (仅
BufferedReader
/BufferedWriter
):readLine()
(读取一行),newLine()
(写入行分隔符),mark()
,reset()
.
ObjectInputStream
/ObjectOutputStream
: 支持对象的输入输出,像数据流一样支持对象的输入输出。可序列化对象实现了java.io.Serializable
接口。Serializable
是一个标记性接口,没有方法,实现它可启动 Java 序列化机制.- 读取对象时,必须与写入时的类型顺序一致.
- 要使用读回的对象,必须使用 Java 安全类型转换.
- 数组也可以被序列化.
PrintStream
/PrintWriter
: 为其他输出流添加了方便地打印各种数据值表示形式的功能。分别针对字节和字符,提供重载的print
和println
方法。特点是不抛出IOException
,自动刷新.
标准 I/O 流
三个标准 I/O 流:
System.in
:InputStream
类的对象实例in
作为标准输入流对象,对应于键盘输入.System.out
:PrintStream
类的对象实例out
作为标准输出流对象,对应于显示器输出.System.err
:PrintStream
类的对象实例err
作为标准错误输出流对象,对应于显示器输出.标准 I/O 流可以被重定向到文件或其他流,实现文件复制等功能。
随机访问文件 (RandomAccessFile
)
RandomAccessFile
: 适用于由大小已知的记录组成的文件,可以使用 seek()
将记录从一处转移到另一处.
它不是继承自 InputStream
和 OutputStream
,而是像 DataInputStream
和 DataOutputStream
一样实现了 DataInput
和 DataOutput
接口.
类似于把
DataInputStream
和DataOutputStream
结合在一起使用.只有
RandomAccessFile
类在文件上支持搜寻(seek()
)方法.构造器:
RandomAccessFile(File file, String mode)
,RandomAccessFile(String name, String mode)
.常用方法:
void seek(long pos)
: 用于文件内移至新位置.long getFilePointer()
: 得到当前位置.long length()
: 判断文件大小.
压缩流
ZipOutputStream
/ GZIPOutputStream
: 压缩数据,生成 Zip 或 GZip 格式文件.
ZipInputStream
/ GZIPInputStream
: 解压缩已经生成的 Zip 或 GZip 文件.
它们继承于 InputStream
和 OutputStream
.
Scanner
类
java.util.Scanner
: Java 5 添加的类,用于从各种输入源(如 System.in
、文件、字符串)解析基本类型和字符串。
支持使用正则表达式来检索、替换那些符合某个模式(规则)的文本。
方法 | 含义 |
---|---|
next() | 读取下一个单词(以空格为界) |
nextLine() | 读取整行 |
nextInt() / nextDouble() | 读取指定类型 |
hasNext() / hasNextInt() | 判断是否还有下一个输入 |
useDelimiter() | 自定义分隔符(如读取 CSV) |
并发
实现并发有两种方法:
- 继承
Thread
类,重写run
方法
1 |
|
- 实现
Runnable
接口,重写run
方法,并创建Thread
对象
1 |
|
线程生命周期:
- Born state / New Thread (出生):线程对象被创建但尚未启动。
- Ready state / Runnable Thread (就绪):线程调用
start()
方法后进入此状态,等待 CPU 调度。 - Running state (运行):线程获得 CPU 时间片,正在执行
run()
方法中的代码。 - Sleeping state (休眠):线程调用
Thread.sleep()
方法后进入此状态,暂停执行指定时间,时间结束后进入就绪态。 - Waiting state (等待):线程调用
Object.wait()
或Thread.join()
等方法后进入此状态,等待其他线程的特定通知或完成。 - Blocked state (阻塞):线程试图获取一个被其他线程持有的
synchronized
锁时进入此状态。 - Dead state (死亡):线程的
run()
方法执行完毕或因未捕获的异常而终止。
Java 线程优先级由操作系统实现。
- 分为 1 到 10 级(
Thread.MIN_PRIORITY
到Thread.MAX_PRIORITY
),默认是 5 (Thread.NORM_PRIORITY
)。 setPriority(int newPriority)
: 设置线程优先级。- 线程组调度依赖于宿主系统的调度算法,优先级设置的复杂性。Java 线程优先级只是给操作系统的一个提示,具体调度由操作系统决定。
同步
Java 提供了 synchronized
关键字作为最基本的同步机制。每个 Java 对象都可以作为一个监视器锁 (monitor lock)。
当一个线程进入 synchronized
代码块或方法时,它会尝试获取该对象的锁。如果锁已经被其他线程持有,当前线程就会被阻塞,直到锁被释放。
synchronized
方法synchronized
块
协作
除了简单的同步访问共享资源,线程有时还需要相互协调,即一个线程等待某个条件满足,而另一个线程负责满足条件并通知等待的线程。Java 的 Object
类提供了 wait()
, notify()
, notifyAll()
方法来实现这种协作。
wait()
:- 作用: 使当前线程释放它所持有的对象锁 ,并进入该对象的等待池(或称等待队列),从而暂停执行。
- 调用时机: 必须在
synchronized
块或方法中调用,否则会抛出IllegalMonitorStateException
。 - 唤醒: 线程会一直等待,直到被
notify()
或notifyAll()
唤醒,或者达到超时时间 (wait(long timeout)
),或者被中断 (InterruptedException
)。 - 虚假唤醒 (Spurious Wakeup): 线程有可能在没有被
notify()
或notifyAll()
明确通知的情况下被唤醒。因此,等待的条件必须用while
循环进行检查,而不是if
语句 。
notify()
:- 作用: 唤醒在该对象上等待的一个任意线程(JVM 决定唤醒哪个)。被唤醒的线程会尝试重新获取对象锁,然后从
wait()
暂停的地方继续执行。 - 调用时机: 必须在
synchronized
块或方法中调用。
- 作用: 唤醒在该对象上等待的一个任意线程(JVM 决定唤醒哪个)。被唤醒的线程会尝试重新获取对象锁,然后从
notifyAll()
:- 作用: 唤醒在该对象上等待的所有线程。所有被唤醒的线程都会竞争对象锁。
- 调用时机: 必须在
synchronized
块或方法中调用。 - 建议: 鉴于虚假唤醒和条件竞争的复杂性,通常建议使用
notifyAll()
而非notify()
,以确保所有相关线程都有机会重新检查条件并继续执行 。
volatile
关键字
volatile
关键字典型的应用是作为状态标志或开关。
- 保证可见性 (Visibility)
- 在多核处理器系统中,每个 CPU 都可能有自己的高速缓存 (cache) 。当一个线程修改了一个共享变量时,它可能只修改了自己 CPU 缓存中的副本,而没有立即写入主内存 (main memory) 。其他线程在读取同一个变量时,可能仍然从自己的旧缓存中读取,从而看不到最新的修改。
volatile
关键字的作用是强制对变量的所有修改都立即从 CPU 缓存写入到主内存中,并且强制对该变量的所有读取都直接从主内存中进行,而不是从线程的本地缓存中读取 。这确保了当一个线程修改了volatile
变量的值,其他线程能够立即看到最新的值。
- 保证有序性 (Ordering) ,禁止指令重排序
- 为了提高性能,编译器和处理器可能会对指令进行重排序。例如,在一个线程中,如果代码是
operation1(); volatileVariable = true; operation2();
,在没有volatile
的情况下,operation1()
和operation2()
可能会被重排序到volatileVariable = true;
之前或之后执行,只要它们之间没有数据依赖。 volatile
关键字会禁止对其前后代码的指令重排序。具体来说,当一个变量被声明为volatile
后,读操作不能被重排序到写操作之后,写操作不能被重排序到读操作之前 。这确保了在写入volatile
变量之前的所有操作都已完成,并且在读取volatile
变量之后的所有操作都能看到最新的值。
- 为了提高性能,编译器和处理器可能会对指令进行重排序。例如,在一个线程中,如果代码是
volatile
不保证原子性,只能保证可见性和有序性。这意味着对于复合操作(如 i++
,它实际上是读-改-写三个步骤),即使变量是 volatile
的,仍然可能出现竞态条件和数据不一致问题。
网络编程
TCP
服务端:
1 |
|
客户端:
1 |
|
UDP
Sender:
1 |
|
Receiver:
1 |
|
SQL
增
1 |
|
查
1 |
|
删改
1 |
|
备考建议
- 选择题
- 大题主要有
- OOP 继承多态
- 比较简单的容器使用
- 多线程互斥同步
- SQL 或者通信应该会考一个