下面我将从最简单到最复杂的情况,详细解释如何实现,并附上代码示例。

核心概念
-
访问修饰符:它决定了变量(或方法)的可见范围。
public: 任何地方都可以访问。private: 只能在声明它的类内部访问。protected: 在同一个包内,或者在不同包的子类中可以访问。- 默认 (无修饰符): 只能在同一个包内访问。
-
创建对象实例:要访问一个非
static的变量,你必须先创建该类的对象(实例),然后通过这个对象去访问,这是最常见的情况。 -
静态变量:如果变量被
static关键字修饰,它属于类本身,而不是类的某个实例,你可以直接通过类名来访问,无需创建对象。
调用另一个类的 public 变量(最常见)
这是最基本、最常用的方式,假设 ClassA 想要访问 ClassB 的一个 public 变量。

步骤:
- 在
ClassB中,将你要暴露的变量声明为public。 - 在
ClassA中,创建ClassB的一个对象实例。 - 使用
对象名.变量名来访问和修改该变量。
代码示例:
ClassB.java (被调用的类)
public class ClassB {
// 1. 声明一个 public 变量
public String publicMessage = "Hello from ClassB!";
// 一个 public 方法用于演示
public void displayMessage() {
System.out.println("Message inside ClassB: " + this.publicMessage);
}
}
ClassA.java (调用方类)
public class ClassA {
public static void main(String[] args) {
// 2. 创建 ClassB 的一个实例
ClassB bObject = new ClassB();
// 3. 通过对象访问 publicMessage 变量
System.out.println("Accessing publicMessage from ClassA: " + bObject.publicMessage);
// 你也可以修改这个变量的值
bObject.publicMessage = "Hello from ClassA!";
System.out.println("After modifying, publicMessage is: " + bObject.publicMessage);
// 调用 ClassB 的方法来验证修改
bObject.displayMessage();
}
}
输出:
Accessing publicMessage from ClassA: Hello from ClassB!
After modifying, publicMessage is: Hello from ClassA!
Message inside ClassB: Hello from ClassA!
调用另一个类的 static 变量
当变量被 static 修饰时,它属于整个类,而不是某个对象,所有对象共享这个变量的值,你可以直接通过类名访问,无需创建对象。
代码示例:
ClassC.java (被调用的类)
public class ClassC {
// 声明一个 static 变量
public static int staticCounter = 0;
public ClassC() {
// 每创建一个对象,静态计数器加1
staticCounter++;
}
}
ClassD.java (调用方类)
public class ClassD {
public static void main(String[] args) {
// 直接通过类名访问 static 变量,无需创建 ClassC 对象
System.out.println("Initial staticCounter: " + ClassC.staticCounter);
// 创建几个 ClassC 对象
ClassC c1 = new ClassC();
System.out.println("After creating c1, staticCounter: " + ClassC.staticCounter);
ClassC c2 = new ClassC();
System.out.println("After creating c2, staticCounter: " + ClassC.staticCounter);
// 你也可以通过对象名访问,但推荐使用类名,这样更清晰表明它是静态成员
System.out.println("Accessing via c2 object: " + c2.staticCounter);
}
}
输出:
Initial staticCounter: 0
After creating c1, staticCounter: 1
After creating c2, staticCounter: 2
Accessing via c2 object: 2
调用另一个类的 private 变量(封装原则)
直接访问 private 变量是不允许的,这违背了面向对象编程的封装原则。private 变量是类的内部实现细节,外部不应该直接触碰。
正确的做法是:在 private 变量所在的类中,提供 public 的访问器和修改器方法,通常称为 getter 和 setter。
代码示例:
Person.java (封装了 private 变量的类)
public class Person {
// 1. 将变量设为 private,保护数据
private String name;
private int age;
// 2. 提供一个 public 的构造方法来初始化对象
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// 3. 提供一个 public 的 getter 方法来获取 name
public String getName() {
return this.name;
}
// 4. 提供一个 public 的 setter 方法来修改 name
public void setName(String name) {
this.name = name;
}
// 提供一个 public 的 getter 方法来获取 age
public int getAge() {
return this.age;
}
// 提供一个 public 的 setter 方法来修改 age (可以加一些逻辑校验)
public void setAge(int age) {
if (age > 0) { // 简单的校验逻辑
this.age = age;
} else {
System.out.println("Invalid age!");
}
}
}
Student.java (调用方类)
public class Student {
public static void main(String[] args) {
Person person = new Person("Alice", 20);
// 错误!无法直接访问 private 变量
// person.name = "Bob"; // 这行代码会编译报错
// 正确!通过 getter 方法获取值
System.out.println("Initial Name: " + person.getName());
System.out.println("Initial Age: " + person.getAge());
// 正确!通过 setter 方法修改值
person.setName("Bob");
person.setAge(21);
System.out.println("Updated Name: " + person.getName());
System.out.println("Updated Age: " + person.getAge());
// 测试 setter 中的逻辑校验
person.setAge(-5); // 会打印 "Invalid age!"
System.out.println("Age after invalid set attempt: " + person.getAge()); // Age 仍然是 21
}
}
输出:
Initial Name: Alice
Initial Age: 20
Updated Name: Bob
Updated Age: 21
Invalid age!
Age after invalid set attempt: 21
调用同一个包内另一个类的默认变量
如果两个类在同一个包下,你可以直接访问另一个类的没有修饰符(即默认 package-private)的变量。
代码示例:
假设这两个文件都在 com.example.myapp 包下。
Tool.java
package com.example.myapp;
// 默认修饰符,只在 com.example.myapp 包内可见
class Tool {
String toolName = "Hammer";
}
Worker.java
package com.example.myapp;
public class Worker {
public static void main(String[] args) {
Tool myTool = new Tool();
// 因为 Worker 和 Tool 在同一个包下,所以可以直接访问 toolName
System.out.println("Worker is using a: " + myTool.toolName);
}
}
在继承关系中访问变量
在子类中,你可以访问父类的 public 和 protected 变量,默认修饰符的变量如果父类和子类在同一个包下,也可以访问。private 变量仍然无法直接访问。
代码示例:
Animal.java (父类)
public class Animal {
public String publicName = "Public Animal";
protected String protectedName = "Protected Animal";
String defaultName = "Default Animal"; // package-private
private String privateName = "Private Animal";
}
Dog.java (子类)
public class Dog extends Animal {
public void displayParentVariables() {
// 可以访问 public 变量
System.out.println("Public variable: " + this.publicName);
// 可以访问 protected 变量
System.out.println("Protected variable: " + this.protectedName);
// Dog 和 Animal 在同一个包下,可以访问 default 变量
// System.out.println("Default variable: " + this.defaultName);
// 无法访问 private 变量,编译会报错
// System.out.println("Private variable: " + this.privateName);
}
}
总结表格
| 目标变量修饰符 | 如何访问 | 示例 |
|---|---|---|
public |
通过创建对象或通过类名(如果是 static) |
bObject.publicVar 或 ClassName.staticPublicVar |
private |
不能直接访问,必须通过该类提供的 public getter 和 setter 方法。 |
object.getVar() 或 object.setVar(value) |
protected |
在同一个包内,通过对象访问。 在不同包的子类中,通过 this 或对象访问。 |
this.protectedVar 或 super.protectedVar |
| 默认 (无修饰符) | 只能在同一个包内,通过对象访问。 | object.defaultVar |
static (任意修饰符) |
通过类名直接访问,无需创建对象。 | ClassName.staticVar |
最佳实践
- 优先使用
private:将类的所有成员变量都设为private,这是封装的核心思想。 - 提供
public的getter和setter:除非有特殊原因(比如不希望变量被修改),否则为每个private变量提供对应的访问器方法。 - 谨慎使用
public:避免将变量直接设为public,因为这会破坏封装,让代码难以维护。 - 合理使用
static:只有当变量真正属于整个类,并且所有实例都共享它时,才使用static。
