Properties 类在 Java 中是一个非常核心和常用的类,它继承自 Hashtable,主要用于读取和写入应用程序的配置参数,这些参数通常以“键=值”的形式存储在 .properties 文件中。

下面我将从以下几个方面进行详细说明:
Properties类简介- 核心特点
- 常用方法
- 实战操作(读取、写入、更新属性文件)
- 最佳实践与注意事项
Properties 类简介
java.util.Properties 类是 java.util.Hashtable 的子类,它提供了几个核心功能:
- 从
.properties文件加载属性: 可以轻松地从外部配置文件中读取键值对。 - 向
.properties文件存储属性: 可以将内存中的属性集合保存到文件中。 - 在内存中管理属性: 可以像操作 Map 一样,在程序中增删改查属性。
这种机制使得应用程序的配置与代码分离,提高了程序的灵活性和可维护性,当需要修改配置时,只需修改 .properties 文件,而无需重新编译 Java 代码。
核心特点
- 键和值都是字符串类型: 与
Hashtable不同,Properties要求键和值都必须是String类型,如果你尝试存入非String类型的键或值,它会自动调用toString()方法。 - 支持有序读取: 从 Java 8 开始,
Properties类的store()和load()方法可以保证属性的写入和读取顺序与它们在Properties对象中的迭代顺序一致(在 JDK 9 中得到改进和保证)。 - 支持默认属性: 可以在创建
Properties对象时指定另一个Properties对象作为“默认属性”,当查找一个键时,如果当前对象中不存在,会自动去默认属性中查找。 - 支持注释和特殊字符: 虽然不是官方标准,但大多数
.properties文件解析器都支持以 或 开头的行作为注释。Properties类本身也支持在store()方法中写入时间戳等注释信息。
常用方法
Properties 类的方法可以分为三大类:从文件加载、向文件存储、内存操作。

文件加载
load(InputStream inStream): 从字节输入流中加载属性列表。load(Reader reader): 从字符输入流中加载属性列表(推荐用于处理文本文件,可以指定字符编码)。loadFromXML(InputStream in): 从 XML 格式的输入流中加载属性列表。
文件存储
store(OutputStream out, String comments): 将属性列表以适合使用load(InputStream)方法加载到Properties表中的格式写入输出流。store(Writer writer, String comments): 将属性列表写入字符输出流(推荐)。storeToXML(OutputStream os, String comment): 将属性列表以 XML 格式写入输出流。
内存操作
这些方法与 Hashtable 类似。
String getProperty(String key): 用指定的键在此属性列表中搜索属性,如果找不到,则返回null。String getProperty(String key, String defaultValue): 用指定的键在此属性列表中搜索属性,如果找不到,则返回指定的默认值。Object setProperty(String key, String value): 调用Hashtable的put方法,它返回此属性列表中指定键对应的旧值,如果没有该键,则返回null。void list(PrintStream out): 将属性列表打印到指定的输出流。void list(PrintWriter out): 将属性列表打印到指定的输出流。Enumeration<?> propertyNames(): 返回此属性列表中所有键的枚举,包括在不同层次结构中默认属性列表中未覆盖的键。
实战操作
假设我们有一个配置文件 config.properties。
config.properties 文件内容
# Database Configuration db.url=jdbc:mysql://localhost:3306/mydb db.username=admin db.password=secret123 # Application Settings app.name=My Cool Application app.version=1.0.0
示例 1:读取属性文件
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class ReadPropertiesExample {
public static void main(String[] args) {
// 1. 创建一个 Properties 对象
Properties prop = new Properties();
// 使用 try-with-resources 自动关闭资源,这是最佳实践
try (InputStream input = new FileInputStream("config.properties")) {
// 2. 加载 properties 文件
prop.load(input);
// 3. 获取属性值
String dbUrl = prop.getProperty("db.url");
String username = prop.getProperty("db.username");
String password = prop.getProperty("db.password");
String appName = prop.getProperty("app.name", "Default App"); // 提供默认值
System.out.println("Database URL: " + dbUrl);
System.out.println("Username: " + username);
System.out.println("Password: " + password);
System.out.println("Application Name: " + appName);
// 如果键不存在,会返回 null
String nonExistentKey = prop.getProperty("non.existent.key");
System.out.println("Non-existent key: " + nonExistentKey);
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
示例 2:写入和更新属性文件
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Properties;
public class WritePropertiesExample {
public static void main(String[] args) {
// 1. 创建一个 Properties 对象
Properties prop = new Properties();
// 2. 设置一些属性
prop.setProperty("app.name", "My Updated Application");
prop.setProperty("app.version", "2.0.0");
prop.setProperty("debug.mode", "true");
// 3. 将属性写入文件
// 同样使用 try-with-resources
try (OutputStream output = new FileOutputStream("config.properties")) {
// 第二个参数是写入文件时的注释,可以为 null
prop.store(output, "Application Configuration File - Updated");
System.out.println("Properties file updated successfully!");
} catch (IOException io) {
io.printStackTrace();
}
}
}
运行此代码后,config.properties 文件内容将被更新为:
#Application Configuration File - Updated #Mon Nov 20 10:30:00 CST 2025 app.name=My Updated Application app.version=2.0.0 debug.mode=true # Database Configuration db.url=jdbc:mysql://localhost:3306/mydb db.username=admin db.password=secret123 # Application Settings app.name=My Cool Application app.version=1.0.0
注意: store() 方法会保留文件中原有的内容,并将新属性追加到文件末尾,如果需要完全覆盖,请确保文件是空的或先删除旧文件。

最佳实践与注意事项
-
资源管理(使用 try-with-resources):
FileInputStream和FileOutputStream都是需要手动关闭的资源。强烈推荐使用try-with-resources语句,它可以自动关闭资源,即使在发生异常时也能保证资源被正确释放,避免内存泄漏。 -
文件路径问题:
- 绝对路径:
new FileInputStream("C:/projects/myapp/config.properties"),这种方式硬编码了路径,降低了程序的可移植性。 - 相对路径:
new FileInputStream("config.properties"),路径是相对于当前工作目录的,在 IDE(如 IntelliJ IDEA, Eclipse)中运行时,当前工作目录通常是项目根目录,但在打包成 JAR 或部署到服务器后,当前工作目录可能会改变,导致找不到文件。 - 推荐做法:从类路径加载,将
.properties文件放在src/main/resources目录下(Maven/Gradle 项目),它会被打包到最终的 JAR 或 WAR 文件的根目录中,然后使用ClassLoader来加载:
// 推荐方式:从类路径加载 try (InputStream input = ReadPropertiesExample.class.getClassLoader().getResourceAsStream("config.properties")) { if (input == null) { System.out.println("Sorry, unable to find config.properties"); return; } prop.load(input); // ... 其余代码 } catch (IOException ex) { ex.printStackTrace(); } - 绝对路径:
-
字符编码:
load(InputStream)方法使用平台默认的字符编码(如 Windows 上的 GBK,Linux 上的 UTF-8)来读取文件,如果配置文件不是默认编码,可能会导致乱码。推荐使用load(Reader),并明确指定字符编码(如InputStreamReader)。// 处理编码问题的正确方式 try (InputStreamReader reader = new InputStreamReader( new FileInputStream("config.properties"), "UTF-8")) { prop.load(reader); } -
线程安全:
Properties对象本身不是线程安全的,如果多个线程同时读写同一个Properties实例,需要进行同步控制(例如使用synchronized块)。 -
不要将敏感信息存入明文:像数据库密码、API 密钥等敏感信息绝对不要直接写在
.properties文件中,应该考虑使用环境变量、加密的配置文件或专门的配置管理服务(如 HashiCorp Vault, Spring Cloud Config)。
Properties 类是 Java 开发中处理配置文件的基石,它的核心价值在于:
- 解耦:将配置与代码分离。
- 灵活:无需重新编译即可修改配置。
- 简单:API 设计直观,易于使用。
记住它的几个关键点:键值对都是字符串、推荐使用 try-with-resources、注意文件路径和字符编码问题,并遵循最佳实践,你就能在项目中得心应手地使用它。
