接口(interface)中的常量 和 类(class)中的常量 的区别。
1、定义方式
1.1. 接口中的常量(interface constant)
ini
public interface Config {
// 不需要显式写 public static final
String NAME = "A**";
int MAX_COUNT = 100;
}
接口中定义的变量,默认就是
public static final
,即使你不写,编译器也会自动加上。
public
:公开访问static
:属于接口本身,不依赖实例final
:不可修改
1.2. 类中的常量(class constant)
arduino
public class Config {
// 必须显式声明 static final
public static final String NAME = "A**";
public static final int MAX_COUNT = 100;
}
类中必须显式写出
static final
,否则就不是常量。
2、核心区别对比
特性 | 接口中的常量 | 类中的常量 |
---|---|---|
修饰符是否可选 | ✅ 隐式 public static final ,可不写 |
❌ 必须显式写 static final |
访问方式 | InterfaceName.CONSTANT |
ClassName.CONSTANT |
是否可以修改 | ❌ final ,不可变 |
❌ final ,不可变 |
存储位置 | 方法区(元数据) | 方法区(类静态变量) |
继承行为 | 实现类自动继承常量 | 子类可以继承 public /protected |
初始化时机 | 接口加载时初始化 | 类加载时初始化 |
性能 | 几乎无差别 | 几乎无差别 |
使用场景 | 定义公共配置、协议常量 | 定义类相关的常量、配置 |
3、代码示例
示例 1:接口常量的继承
typescript
public interface AppConfig {
String DOMAIN = "XX";
String TOKEN = "....";
}
public class LoginService implements AppConfig {
public void connect() {
System.out.println("域名: " + DOMAIN); // 直接使用接口常量
}
}
LoginService
虽然没有实现方法,但可以直接使用DOMAIN
和TOKEN
。
示例 2:类常量的继承
scala
public class AppConfig {
public static final String ENV = "prod";
}
public class DatabaseConfig extends AppConfig {
public void printEnv() {
System.out.println("环境: " + ENV); // 继承父类常量
}
}
类通过继承获得常量。
4、注意:
1. 接口常量是"隐式 public static final"
ini
interface BadExample {
final String NAME = "Alice"; // ❌ 冗余,final 可省略
static int COUNT = 10; // ❌ 冗余
// private String SECRET = "..."; // ❌ 编译错误!接口常量必须是 public
}
2. 接口不能有"实例常量"
- 不能有实例变量和实例常量(包括常量)
- 所有字段必须是
public static final
(即:类常量) - 接口不能被实例化,所以"实例"相关的概念都不存在
java
interface BadExample {
final String name = "Alice"; // ✅ 可以,但它是 static final(接口常量)
// String instanceValue; // ❌ 错误!接口不能有实例变量
}
3. 接口常量会类常量必须在声明时初始化(因为final修饰)
ini
interface Config {
// String NAME; // ❌ 编译错误!必须赋值
String NAME = "Alice"; // ✅
}
5、使用建议
场景 | 推荐方式 |
---|---|
定义一组公共配置(如 API 地址、状态码) | ✅ 使用 interface 常量(简洁) |
常量与某个类强相关(如 Math.PI ) |
✅ 使用 class 常量 |
常量需要封装逻辑(如通过方法计算) | ✅ 使用 class + 私有构造 |
6、什么是"实例常量"?
"实例常量"指的是:
- 使用
final
修饰的成员变量 - 属于对象实例(而不是类)
- 每个对象可以有不同的值
- 一旦创建后不可修改
示例:定义实例常量
arduino
public class Person {
// 实例常量:每个 Person 对象都有自己的 name 和 id
private final String name;
private final long id;
// 构造函数中初始化
public Person(String name, long id) {
this.name = name;
this.id = id;
}
// 只有 getter,没有 setter(因为是常量)
public String getName() {
return name;
}
public long getId() {
return id;
}
}
使用:
ini
Person p1 = new Person("Alice", 1L);
Person p2 = new Person("Bob", 2L);
// p1.name = "Charlie"; // ❌ 编译错误!不能修改 final 变量
name
和id
就是典型的"实例常量"------每个对象有自己的值,且创建后不可变。